blob: fa955efed12a815997c6644eb8323b5b113604a3 [file] [log] [blame]
bellard31e31b82003-02-18 22:55:36 +00001/*
bellard66fb9762003-03-23 01:06:05 +00002 * Emulation of Linux signals
ths5fafdf22007-09-16 21:08:06 +00003 *
bellard31e31b82003-02-18 22:55:36 +00004 * Copyright (c) 2003 Fabrice Bellard
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
Blue Swirl8167ee82009-07-16 20:47:01 +000017 * along with this program; if not, see <http://www.gnu.org/licenses/>.
bellard31e31b82003-02-18 22:55:36 +000018 */
19#include <stdlib.h>
20#include <stdio.h>
bellard66fb9762003-03-23 01:06:05 +000021#include <string.h>
bellard31e31b82003-02-18 22:55:36 +000022#include <stdarg.h>
bellard2677e102003-04-10 00:03:27 +000023#include <unistd.h>
bellard66fb9762003-03-23 01:06:05 +000024#include <errno.h>
aurel32603e4fd2009-04-15 16:18:38 +000025#include <assert.h>
bellard31e31b82003-02-18 22:55:36 +000026#include <sys/ucontext.h>
Mika Westerbergedf8e2a2009-04-07 09:57:11 +030027#include <sys/resource.h>
bellard31e31b82003-02-18 22:55:36 +000028
bellard3ef693a2003-03-23 20:17:16 +000029#include "qemu.h"
blueswir17d99a002009-01-14 19:00:36 +000030#include "qemu-common.h"
blueswir1992f48a2007-10-14 16:27:31 +000031#include "target_signal.h"
bellard66fb9762003-03-23 01:06:05 +000032
33//#define DEBUG_SIGNAL
34
blueswir1249c4c32008-10-05 11:09:37 +000035static struct target_sigaltstack target_sigaltstack_used = {
thsa04e1342007-09-27 13:57:58 +000036 .ss_sp = 0,
37 .ss_size = 0,
38 .ss_flags = TARGET_SS_DISABLE,
39};
40
pbrook624f7972008-05-31 16:11:38 +000041static struct target_sigaction sigact_table[TARGET_NSIG];
bellard31e31b82003-02-18 22:55:36 +000042
ths5fafdf22007-09-16 21:08:06 +000043static void host_signal_handler(int host_signum, siginfo_t *info,
bellard66fb9762003-03-23 01:06:05 +000044 void *puc);
45
Arnaud Patard3ca05582009-03-30 01:18:20 +020046static uint8_t host_to_target_signal_table[_NSIG] = {
bellard9e5f5282003-07-13 17:33:54 +000047 [SIGHUP] = TARGET_SIGHUP,
48 [SIGINT] = TARGET_SIGINT,
49 [SIGQUIT] = TARGET_SIGQUIT,
50 [SIGILL] = TARGET_SIGILL,
51 [SIGTRAP] = TARGET_SIGTRAP,
52 [SIGABRT] = TARGET_SIGABRT,
bellard01e3b762003-09-30 21:10:14 +000053/* [SIGIOT] = TARGET_SIGIOT,*/
bellard9e5f5282003-07-13 17:33:54 +000054 [SIGBUS] = TARGET_SIGBUS,
55 [SIGFPE] = TARGET_SIGFPE,
56 [SIGKILL] = TARGET_SIGKILL,
57 [SIGUSR1] = TARGET_SIGUSR1,
58 [SIGSEGV] = TARGET_SIGSEGV,
59 [SIGUSR2] = TARGET_SIGUSR2,
60 [SIGPIPE] = TARGET_SIGPIPE,
61 [SIGALRM] = TARGET_SIGALRM,
62 [SIGTERM] = TARGET_SIGTERM,
63#ifdef SIGSTKFLT
64 [SIGSTKFLT] = TARGET_SIGSTKFLT,
65#endif
66 [SIGCHLD] = TARGET_SIGCHLD,
67 [SIGCONT] = TARGET_SIGCONT,
68 [SIGSTOP] = TARGET_SIGSTOP,
69 [SIGTSTP] = TARGET_SIGTSTP,
70 [SIGTTIN] = TARGET_SIGTTIN,
71 [SIGTTOU] = TARGET_SIGTTOU,
72 [SIGURG] = TARGET_SIGURG,
73 [SIGXCPU] = TARGET_SIGXCPU,
74 [SIGXFSZ] = TARGET_SIGXFSZ,
75 [SIGVTALRM] = TARGET_SIGVTALRM,
76 [SIGPROF] = TARGET_SIGPROF,
77 [SIGWINCH] = TARGET_SIGWINCH,
78 [SIGIO] = TARGET_SIGIO,
79 [SIGPWR] = TARGET_SIGPWR,
80 [SIGSYS] = TARGET_SIGSYS,
81 /* next signals stay the same */
pbrook624f7972008-05-31 16:11:38 +000082 /* Nasty hack: Reverse SIGRTMIN and SIGRTMAX to avoid overlap with
Dong Xu Wangb4916d72011-11-22 18:06:17 +080083 host libpthread signals. This assumes no one actually uses SIGRTMAX :-/
pbrook624f7972008-05-31 16:11:38 +000084 To fix this properly we need to do manual signal delivery multiplexed
85 over a single host signal. */
86 [__SIGRTMIN] = __SIGRTMAX,
87 [__SIGRTMAX] = __SIGRTMIN,
bellard9e5f5282003-07-13 17:33:54 +000088};
Arnaud Patard3ca05582009-03-30 01:18:20 +020089static uint8_t target_to_host_signal_table[_NSIG];
bellard9e5f5282003-07-13 17:33:54 +000090
thsa04e1342007-09-27 13:57:58 +000091static inline int on_sig_stack(unsigned long sp)
92{
93 return (sp - target_sigaltstack_used.ss_sp
94 < target_sigaltstack_used.ss_size);
95}
96
97static inline int sas_ss_flags(unsigned long sp)
98{
99 return (target_sigaltstack_used.ss_size == 0 ? SS_DISABLE
100 : on_sig_stack(sp) ? SS_ONSTACK : 0);
101}
102
pbrook1d9d8b52009-04-16 15:17:02 +0000103int host_to_target_signal(int sig)
bellard31e31b82003-02-18 22:55:36 +0000104{
Andreas Schwab167c50d2013-07-02 14:04:12 +0100105 if (sig < 0 || sig >= _NSIG)
pbrook4cb05962008-05-30 18:05:19 +0000106 return sig;
bellard9e5f5282003-07-13 17:33:54 +0000107 return host_to_target_signal_table[sig];
bellard31e31b82003-02-18 22:55:36 +0000108}
109
pbrook4cb05962008-05-30 18:05:19 +0000110int target_to_host_signal(int sig)
bellard31e31b82003-02-18 22:55:36 +0000111{
Andreas Schwab167c50d2013-07-02 14:04:12 +0100112 if (sig < 0 || sig >= _NSIG)
pbrook4cb05962008-05-30 18:05:19 +0000113 return sig;
bellard9e5f5282003-07-13 17:33:54 +0000114 return target_to_host_signal_table[sig];
bellard31e31b82003-02-18 22:55:36 +0000115}
116
Anthony Liguoric227f092009-10-01 16:12:16 -0500117static inline void target_sigemptyset(target_sigset_t *set)
pbrookf5545b52008-05-30 22:37:07 +0000118{
119 memset(set, 0, sizeof(*set));
120}
121
Anthony Liguoric227f092009-10-01 16:12:16 -0500122static inline void target_sigaddset(target_sigset_t *set, int signum)
pbrookf5545b52008-05-30 22:37:07 +0000123{
124 signum--;
125 abi_ulong mask = (abi_ulong)1 << (signum % TARGET_NSIG_BPW);
126 set->sig[signum / TARGET_NSIG_BPW] |= mask;
127}
128
Anthony Liguoric227f092009-10-01 16:12:16 -0500129static inline int target_sigismember(const target_sigset_t *set, int signum)
pbrookf5545b52008-05-30 22:37:07 +0000130{
131 signum--;
132 abi_ulong mask = (abi_ulong)1 << (signum % TARGET_NSIG_BPW);
133 return ((set->sig[signum / TARGET_NSIG_BPW] & mask) != 0);
134}
135
Anthony Liguoric227f092009-10-01 16:12:16 -0500136static void host_to_target_sigset_internal(target_sigset_t *d,
bellard92319442004-06-19 16:58:13 +0000137 const sigset_t *s)
bellard66fb9762003-03-23 01:06:05 +0000138{
139 int i;
pbrookf5545b52008-05-30 22:37:07 +0000140 target_sigemptyset(d);
141 for (i = 1; i <= TARGET_NSIG; i++) {
142 if (sigismember(s, i)) {
143 target_sigaddset(d, host_to_target_signal(i));
144 }
bellard9e5f5282003-07-13 17:33:54 +0000145 }
bellard66fb9762003-03-23 01:06:05 +0000146}
147
Anthony Liguoric227f092009-10-01 16:12:16 -0500148void host_to_target_sigset(target_sigset_t *d, const sigset_t *s)
bellard92319442004-06-19 16:58:13 +0000149{
Anthony Liguoric227f092009-10-01 16:12:16 -0500150 target_sigset_t d1;
bellard92319442004-06-19 16:58:13 +0000151 int i;
152
153 host_to_target_sigset_internal(&d1, s);
154 for(i = 0;i < TARGET_NSIG_WORDS; i++)
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200155 d->sig[i] = tswapal(d1.sig[i]);
bellard92319442004-06-19 16:58:13 +0000156}
157
blueswir18fcd3692008-08-17 20:26:25 +0000158static void target_to_host_sigset_internal(sigset_t *d,
Anthony Liguoric227f092009-10-01 16:12:16 -0500159 const target_sigset_t *s)
bellard66fb9762003-03-23 01:06:05 +0000160{
161 int i;
pbrookf5545b52008-05-30 22:37:07 +0000162 sigemptyset(d);
163 for (i = 1; i <= TARGET_NSIG; i++) {
164 if (target_sigismember(s, i)) {
165 sigaddset(d, target_to_host_signal(i));
166 }
167 }
bellard66fb9762003-03-23 01:06:05 +0000168}
169
Anthony Liguoric227f092009-10-01 16:12:16 -0500170void target_to_host_sigset(sigset_t *d, const target_sigset_t *s)
bellard92319442004-06-19 16:58:13 +0000171{
Anthony Liguoric227f092009-10-01 16:12:16 -0500172 target_sigset_t s1;
bellard92319442004-06-19 16:58:13 +0000173 int i;
174
175 for(i = 0;i < TARGET_NSIG_WORDS; i++)
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200176 s1.sig[i] = tswapal(s->sig[i]);
bellard92319442004-06-19 16:58:13 +0000177 target_to_host_sigset_internal(d, &s1);
178}
ths3b46e622007-09-17 08:09:54 +0000179
blueswir1992f48a2007-10-14 16:27:31 +0000180void host_to_target_old_sigset(abi_ulong *old_sigset,
bellard66fb9762003-03-23 01:06:05 +0000181 const sigset_t *sigset)
182{
Anthony Liguoric227f092009-10-01 16:12:16 -0500183 target_sigset_t d;
bellard9e5f5282003-07-13 17:33:54 +0000184 host_to_target_sigset(&d, sigset);
185 *old_sigset = d.sig[0];
bellard66fb9762003-03-23 01:06:05 +0000186}
187
ths5fafdf22007-09-16 21:08:06 +0000188void target_to_host_old_sigset(sigset_t *sigset,
blueswir1992f48a2007-10-14 16:27:31 +0000189 const abi_ulong *old_sigset)
bellard66fb9762003-03-23 01:06:05 +0000190{
Anthony Liguoric227f092009-10-01 16:12:16 -0500191 target_sigset_t d;
bellard9e5f5282003-07-13 17:33:54 +0000192 int i;
193
194 d.sig[0] = *old_sigset;
195 for(i = 1;i < TARGET_NSIG_WORDS; i++)
196 d.sig[i] = 0;
197 target_to_host_sigset(sigset, &d);
bellard66fb9762003-03-23 01:06:05 +0000198}
199
Alex Barcelo1c275922014-03-14 14:36:55 +0000200/* Wrapper for sigprocmask function
201 * Emulates a sigprocmask in a safe way for the guest. Note that set and oldset
202 * are host signal set, not guest ones. This wraps the sigprocmask host calls
203 * that should be protected (calls originated from guest)
204 */
205int do_sigprocmask(int how, const sigset_t *set, sigset_t *oldset)
206{
Peter Maydella7ec0f92014-03-14 14:36:56 +0000207 int ret;
208 sigset_t val;
209 sigset_t *temp = NULL;
210 CPUState *cpu = thread_cpu;
211 TaskState *ts = (TaskState *)cpu->opaque;
212 bool segv_was_blocked = ts->sigsegv_blocked;
213
214 if (set) {
215 bool has_sigsegv = sigismember(set, SIGSEGV);
216 val = *set;
217 temp = &val;
218
219 sigdelset(temp, SIGSEGV);
220
221 switch (how) {
222 case SIG_BLOCK:
223 if (has_sigsegv) {
224 ts->sigsegv_blocked = true;
225 }
226 break;
227 case SIG_UNBLOCK:
228 if (has_sigsegv) {
229 ts->sigsegv_blocked = false;
230 }
231 break;
232 case SIG_SETMASK:
233 ts->sigsegv_blocked = has_sigsegv;
234 break;
235 default:
236 g_assert_not_reached();
237 }
238 }
239
240 ret = sigprocmask(how, temp, oldset);
241
242 if (oldset && segv_was_blocked) {
243 sigaddset(oldset, SIGSEGV);
244 }
245
246 return ret;
Alex Barcelo1c275922014-03-14 14:36:55 +0000247}
248
bellard9de5e442003-03-23 16:49:39 +0000249/* siginfo conversion */
250
Anthony Liguoric227f092009-10-01 16:12:16 -0500251static inline void host_to_target_siginfo_noswap(target_siginfo_t *tinfo,
bellard9de5e442003-03-23 16:49:39 +0000252 const siginfo_t *info)
bellard66fb9762003-03-23 01:06:05 +0000253{
Richard Hendersona05c6402012-09-15 11:34:20 -0700254 int sig = host_to_target_signal(info->si_signo);
bellard9de5e442003-03-23 16:49:39 +0000255 tinfo->si_signo = sig;
256 tinfo->si_errno = 0;
pbrookafd7cd92008-05-31 12:14:21 +0000257 tinfo->si_code = info->si_code;
Richard Hendersona05c6402012-09-15 11:34:20 -0700258
259 if (sig == TARGET_SIGILL || sig == TARGET_SIGFPE || sig == TARGET_SIGSEGV
260 || sig == TARGET_SIGBUS || sig == TARGET_SIGTRAP) {
261 /* Should never come here, but who knows. The information for
262 the target is irrelevant. */
bellard9de5e442003-03-23 16:49:39 +0000263 tinfo->_sifields._sigfault._addr = 0;
Richard Hendersona05c6402012-09-15 11:34:20 -0700264 } else if (sig == TARGET_SIGIO) {
265 tinfo->_sifields._sigpoll._band = info->si_band;
ths7f7f7c82007-07-12 11:02:46 +0000266 tinfo->_sifields._sigpoll._fd = info->si_fd;
Richard Hendersona05c6402012-09-15 11:34:20 -0700267 } else if (sig == TARGET_SIGCHLD) {
268 tinfo->_sifields._sigchld._pid = info->si_pid;
269 tinfo->_sifields._sigchld._uid = info->si_uid;
270 tinfo->_sifields._sigchld._status
271 = host_to_target_waitstatus(info->si_status);
272 tinfo->_sifields._sigchld._utime = info->si_utime;
273 tinfo->_sifields._sigchld._stime = info->si_stime;
bellard9de5e442003-03-23 16:49:39 +0000274 } else if (sig >= TARGET_SIGRTMIN) {
275 tinfo->_sifields._rt._pid = info->si_pid;
276 tinfo->_sifields._rt._uid = info->si_uid;
277 /* XXX: potential problem if 64 bit */
Richard Hendersona05c6402012-09-15 11:34:20 -0700278 tinfo->_sifields._rt._sigval.sival_ptr
279 = (abi_ulong)(unsigned long)info->si_value.sival_ptr;
bellard9de5e442003-03-23 16:49:39 +0000280 }
bellard66fb9762003-03-23 01:06:05 +0000281}
282
Anthony Liguoric227f092009-10-01 16:12:16 -0500283static void tswap_siginfo(target_siginfo_t *tinfo,
284 const target_siginfo_t *info)
bellard9de5e442003-03-23 16:49:39 +0000285{
Richard Hendersona05c6402012-09-15 11:34:20 -0700286 int sig = info->si_signo;
bellard9de5e442003-03-23 16:49:39 +0000287 tinfo->si_signo = tswap32(sig);
288 tinfo->si_errno = tswap32(info->si_errno);
289 tinfo->si_code = tswap32(info->si_code);
Richard Hendersona05c6402012-09-15 11:34:20 -0700290
291 if (sig == TARGET_SIGILL || sig == TARGET_SIGFPE || sig == TARGET_SIGSEGV
292 || sig == TARGET_SIGBUS || sig == TARGET_SIGTRAP) {
293 tinfo->_sifields._sigfault._addr
294 = tswapal(info->_sifields._sigfault._addr);
295 } else if (sig == TARGET_SIGIO) {
296 tinfo->_sifields._sigpoll._band
297 = tswap32(info->_sifields._sigpoll._band);
298 tinfo->_sifields._sigpoll._fd = tswap32(info->_sifields._sigpoll._fd);
299 } else if (sig == TARGET_SIGCHLD) {
300 tinfo->_sifields._sigchld._pid
301 = tswap32(info->_sifields._sigchld._pid);
302 tinfo->_sifields._sigchld._uid
303 = tswap32(info->_sifields._sigchld._uid);
304 tinfo->_sifields._sigchld._status
305 = tswap32(info->_sifields._sigchld._status);
306 tinfo->_sifields._sigchld._utime
307 = tswapal(info->_sifields._sigchld._utime);
308 tinfo->_sifields._sigchld._stime
309 = tswapal(info->_sifields._sigchld._stime);
bellard9de5e442003-03-23 16:49:39 +0000310 } else if (sig >= TARGET_SIGRTMIN) {
311 tinfo->_sifields._rt._pid = tswap32(info->_sifields._rt._pid);
312 tinfo->_sifields._rt._uid = tswap32(info->_sifields._rt._uid);
Richard Hendersona05c6402012-09-15 11:34:20 -0700313 tinfo->_sifields._rt._sigval.sival_ptr
314 = tswapal(info->_sifields._rt._sigval.sival_ptr);
bellard9de5e442003-03-23 16:49:39 +0000315 }
316}
317
318
Anthony Liguoric227f092009-10-01 16:12:16 -0500319void host_to_target_siginfo(target_siginfo_t *tinfo, const siginfo_t *info)
bellard9de5e442003-03-23 16:49:39 +0000320{
321 host_to_target_siginfo_noswap(tinfo, info);
322 tswap_siginfo(tinfo, tinfo);
323}
324
325/* XXX: we support only POSIX RT signals are used. */
thsaa1f17c2007-07-11 22:48:58 +0000326/* XXX: find a solution for 64 bit (additional malloced data is needed) */
Anthony Liguoric227f092009-10-01 16:12:16 -0500327void target_to_host_siginfo(siginfo_t *info, const target_siginfo_t *tinfo)
bellard66fb9762003-03-23 01:06:05 +0000328{
329 info->si_signo = tswap32(tinfo->si_signo);
330 info->si_errno = tswap32(tinfo->si_errno);
331 info->si_code = tswap32(tinfo->si_code);
bellard9de5e442003-03-23 16:49:39 +0000332 info->si_pid = tswap32(tinfo->_sifields._rt._pid);
333 info->si_uid = tswap32(tinfo->_sifields._rt._uid);
ths5fafdf22007-09-16 21:08:06 +0000334 info->si_value.sival_ptr =
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200335 (void *)(long)tswapal(tinfo->_sifields._rt._sigval.sival_ptr);
bellard66fb9762003-03-23 01:06:05 +0000336}
337
aurel32ca587a82008-12-18 22:44:13 +0000338static int fatal_signal (int sig)
339{
340 switch (sig) {
341 case TARGET_SIGCHLD:
342 case TARGET_SIGURG:
343 case TARGET_SIGWINCH:
344 /* Ignored by default. */
345 return 0;
346 case TARGET_SIGCONT:
347 case TARGET_SIGSTOP:
348 case TARGET_SIGTSTP:
349 case TARGET_SIGTTIN:
350 case TARGET_SIGTTOU:
351 /* Job control signals. */
352 return 0;
353 default:
354 return 1;
355 }
356}
357
Mika Westerbergedf8e2a2009-04-07 09:57:11 +0300358/* returns 1 if given signal should dump core if not handled */
359static int core_dump_signal(int sig)
360{
361 switch (sig) {
362 case TARGET_SIGABRT:
363 case TARGET_SIGFPE:
364 case TARGET_SIGILL:
365 case TARGET_SIGQUIT:
366 case TARGET_SIGSEGV:
367 case TARGET_SIGTRAP:
368 case TARGET_SIGBUS:
369 return (1);
370 default:
371 return (0);
372 }
373}
374
bellard31e31b82003-02-18 22:55:36 +0000375void signal_init(void)
376{
377 struct sigaction act;
pbrook624f7972008-05-31 16:11:38 +0000378 struct sigaction oact;
bellard9e5f5282003-07-13 17:33:54 +0000379 int i, j;
pbrook624f7972008-05-31 16:11:38 +0000380 int host_sig;
bellard31e31b82003-02-18 22:55:36 +0000381
bellard9e5f5282003-07-13 17:33:54 +0000382 /* generate signal conversion tables */
Arnaud Patard3ca05582009-03-30 01:18:20 +0200383 for(i = 1; i < _NSIG; i++) {
bellard9e5f5282003-07-13 17:33:54 +0000384 if (host_to_target_signal_table[i] == 0)
385 host_to_target_signal_table[i] = i;
386 }
Arnaud Patard3ca05582009-03-30 01:18:20 +0200387 for(i = 1; i < _NSIG; i++) {
bellard9e5f5282003-07-13 17:33:54 +0000388 j = host_to_target_signal_table[i];
389 target_to_host_signal_table[j] = i;
390 }
ths3b46e622007-09-17 08:09:54 +0000391
bellard9de5e442003-03-23 16:49:39 +0000392 /* set all host signal handlers. ALL signals are blocked during
393 the handlers to serialize them. */
pbrook624f7972008-05-31 16:11:38 +0000394 memset(sigact_table, 0, sizeof(sigact_table));
395
bellard9de5e442003-03-23 16:49:39 +0000396 sigfillset(&act.sa_mask);
bellard31e31b82003-02-18 22:55:36 +0000397 act.sa_flags = SA_SIGINFO;
398 act.sa_sigaction = host_signal_handler;
pbrook624f7972008-05-31 16:11:38 +0000399 for(i = 1; i <= TARGET_NSIG; i++) {
400 host_sig = target_to_host_signal(i);
401 sigaction(host_sig, NULL, &oact);
402 if (oact.sa_sigaction == (void *)SIG_IGN) {
403 sigact_table[i - 1]._sa_handler = TARGET_SIG_IGN;
404 } else if (oact.sa_sigaction == (void *)SIG_DFL) {
405 sigact_table[i - 1]._sa_handler = TARGET_SIG_DFL;
406 }
407 /* If there's already a handler installed then something has
408 gone horribly wrong, so don't even try to handle that case. */
aurel32ca587a82008-12-18 22:44:13 +0000409 /* Install some handlers for our own use. We need at least
410 SIGSEGV and SIGBUS, to detect exceptions. We can not just
411 trap all signals because it affects syscall interrupt
412 behavior. But do trap all default-fatal signals. */
413 if (fatal_signal (i))
pbrook624f7972008-05-31 16:11:38 +0000414 sigaction(host_sig, &act, NULL);
bellard31e31b82003-02-18 22:55:36 +0000415 }
bellard31e31b82003-02-18 22:55:36 +0000416}
417
bellard66fb9762003-03-23 01:06:05 +0000418/* signal queue handling */
419
Andreas Färber9349b4f2012-03-14 01:38:32 +0100420static inline struct sigqueue *alloc_sigqueue(CPUArchState *env)
bellard66fb9762003-03-23 01:06:05 +0000421{
Andreas Färber0429a972013-08-26 18:14:44 +0200422 CPUState *cpu = ENV_GET_CPU(env);
423 TaskState *ts = cpu->opaque;
pbrook624f7972008-05-31 16:11:38 +0000424 struct sigqueue *q = ts->first_free;
bellard66fb9762003-03-23 01:06:05 +0000425 if (!q)
426 return NULL;
pbrook624f7972008-05-31 16:11:38 +0000427 ts->first_free = q->next;
bellard66fb9762003-03-23 01:06:05 +0000428 return q;
429}
430
Andreas Färber9349b4f2012-03-14 01:38:32 +0100431static inline void free_sigqueue(CPUArchState *env, struct sigqueue *q)
bellard66fb9762003-03-23 01:06:05 +0000432{
Andreas Färber0429a972013-08-26 18:14:44 +0200433 CPUState *cpu = ENV_GET_CPU(env);
434 TaskState *ts = cpu->opaque;
435
pbrook624f7972008-05-31 16:11:38 +0000436 q->next = ts->first_free;
437 ts->first_free = q;
bellard66fb9762003-03-23 01:06:05 +0000438}
439
bellard9de5e442003-03-23 16:49:39 +0000440/* abort execution with signal */
Riku Voipio66393fb2009-12-04 15:16:32 +0200441static void QEMU_NORETURN force_sig(int target_sig)
bellard66fb9762003-03-23 01:06:05 +0000442{
Andreas Färber0429a972013-08-26 18:14:44 +0200443 CPUState *cpu = thread_cpu;
444 CPUArchState *env = cpu->env_ptr;
445 TaskState *ts = (TaskState *)cpu->opaque;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +0300446 int host_sig, core_dumped = 0;
aurel32603e4fd2009-04-15 16:18:38 +0000447 struct sigaction act;
Riku Voipio66393fb2009-12-04 15:16:32 +0200448 host_sig = target_to_host_signal(target_sig);
Andreas Färbera2247f82013-06-09 19:47:04 +0200449 gdb_signalled(env, target_sig);
aurel32603e4fd2009-04-15 16:18:38 +0000450
Mika Westerbergedf8e2a2009-04-07 09:57:11 +0300451 /* dump core if supported by target binary format */
Riku Voipio66393fb2009-12-04 15:16:32 +0200452 if (core_dump_signal(target_sig) && (ts->bprm->core_dump != NULL)) {
Mika Westerbergedf8e2a2009-04-07 09:57:11 +0300453 stop_all_tasks();
454 core_dumped =
Andreas Färbera2247f82013-06-09 19:47:04 +0200455 ((*ts->bprm->core_dump)(target_sig, env) == 0);
Mika Westerbergedf8e2a2009-04-07 09:57:11 +0300456 }
457 if (core_dumped) {
458 /* we already dumped the core of target process, we don't want
459 * a coredump of qemu itself */
460 struct rlimit nodump;
461 getrlimit(RLIMIT_CORE, &nodump);
462 nodump.rlim_cur=0;
463 setrlimit(RLIMIT_CORE, &nodump);
464 (void) fprintf(stderr, "qemu: uncaught target signal %d (%s) - %s\n",
Riku Voipio66393fb2009-12-04 15:16:32 +0200465 target_sig, strsignal(host_sig), "core dumped" );
Mika Westerbergedf8e2a2009-04-07 09:57:11 +0300466 }
467
Stefan Weil0c587512011-04-28 17:20:32 +0200468 /* The proper exit code for dying from an uncaught signal is
aurel32603e4fd2009-04-15 16:18:38 +0000469 * -<signal>. The kernel doesn't allow exit() or _exit() to pass
470 * a negative value. To get the proper exit code we need to
471 * actually die from an uncaught signal. Here the default signal
472 * handler is installed, we send ourself a signal and we wait for
473 * it to arrive. */
474 sigfillset(&act.sa_mask);
475 act.sa_handler = SIG_DFL;
Peter Maydell3a5d30b2014-02-17 18:55:32 +0000476 act.sa_flags = 0;
aurel32603e4fd2009-04-15 16:18:38 +0000477 sigaction(host_sig, &act, NULL);
478
479 /* For some reason raise(host_sig) doesn't send the signal when
480 * statically linked on x86-64. */
481 kill(getpid(), host_sig);
482
483 /* Make sure the signal isn't masked (just reuse the mask inside
484 of act) */
485 sigdelset(&act.sa_mask, host_sig);
486 sigsuspend(&act.sa_mask);
487
488 /* unreachable */
Blue Swirla6c6f762010-03-13 14:18:50 +0000489 abort();
bellard66fb9762003-03-23 01:06:05 +0000490}
491
bellard9de5e442003-03-23 16:49:39 +0000492/* queue a signal so that it will be send to the virtual CPU as soon
493 as possible */
Andreas Färber9349b4f2012-03-14 01:38:32 +0100494int queue_signal(CPUArchState *env, int sig, target_siginfo_t *info)
bellard31e31b82003-02-18 22:55:36 +0000495{
Andreas Färber0429a972013-08-26 18:14:44 +0200496 CPUState *cpu = ENV_GET_CPU(env);
497 TaskState *ts = cpu->opaque;
pbrook624f7972008-05-31 16:11:38 +0000498 struct emulated_sigtable *k;
bellard9de5e442003-03-23 16:49:39 +0000499 struct sigqueue *q, **pq;
blueswir1992f48a2007-10-14 16:27:31 +0000500 abi_ulong handler;
aurel32ca587a82008-12-18 22:44:13 +0000501 int queue;
bellard66fb9762003-03-23 01:06:05 +0000502
bellard9de5e442003-03-23 16:49:39 +0000503#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000504 fprintf(stderr, "queue_signal: sig=%d\n",
bellard9de5e442003-03-23 16:49:39 +0000505 sig);
bellard66fb9762003-03-23 01:06:05 +0000506#endif
pbrook624f7972008-05-31 16:11:38 +0000507 k = &ts->sigtab[sig - 1];
aurel32ca587a82008-12-18 22:44:13 +0000508 queue = gdb_queuesig ();
pbrook624f7972008-05-31 16:11:38 +0000509 handler = sigact_table[sig - 1]._sa_handler;
Peter Maydella7ec0f92014-03-14 14:36:56 +0000510
511 if (ts->sigsegv_blocked && sig == TARGET_SIGSEGV) {
512 /* Guest has blocked SIGSEGV but we got one anyway. Assume this
513 * is a forced SIGSEGV (ie one the kernel handles via force_sig_info
514 * because it got a real MMU fault). A blocked SIGSEGV in that
515 * situation is treated as if using the default handler. This is
516 * not correct if some other process has randomly sent us a SIGSEGV
517 * via kill(), but that is not easy to distinguish at this point,
518 * so we assume it doesn't happen.
519 */
520 handler = TARGET_SIG_DFL;
521 }
522
aurel32ca587a82008-12-18 22:44:13 +0000523 if (!queue && handler == TARGET_SIG_DFL) {
ths60b19692008-11-27 15:47:15 +0000524 if (sig == TARGET_SIGTSTP || sig == TARGET_SIGTTIN || sig == TARGET_SIGTTOU) {
525 kill(getpid(),SIGSTOP);
526 return 0;
527 } else
bellard66fb9762003-03-23 01:06:05 +0000528 /* default handler : ignore some signal. The other are fatal */
ths5fafdf22007-09-16 21:08:06 +0000529 if (sig != TARGET_SIGCHLD &&
530 sig != TARGET_SIGURG &&
ths60b19692008-11-27 15:47:15 +0000531 sig != TARGET_SIGWINCH &&
532 sig != TARGET_SIGCONT) {
bellard66fb9762003-03-23 01:06:05 +0000533 force_sig(sig);
bellard9de5e442003-03-23 16:49:39 +0000534 } else {
535 return 0; /* indicate ignored */
bellard66fb9762003-03-23 01:06:05 +0000536 }
aurel32ca587a82008-12-18 22:44:13 +0000537 } else if (!queue && handler == TARGET_SIG_IGN) {
bellard66fb9762003-03-23 01:06:05 +0000538 /* ignore signal */
bellard9de5e442003-03-23 16:49:39 +0000539 return 0;
aurel32ca587a82008-12-18 22:44:13 +0000540 } else if (!queue && handler == TARGET_SIG_ERR) {
bellard66fb9762003-03-23 01:06:05 +0000541 force_sig(sig);
542 } else {
bellard9de5e442003-03-23 16:49:39 +0000543 pq = &k->first;
544 if (sig < TARGET_SIGRTMIN) {
545 /* if non real time signal, we queue exactly one signal */
546 if (!k->pending)
547 q = &k->info;
548 else
549 return 0;
550 } else {
551 if (!k->pending) {
552 /* first signal */
553 q = &k->info;
554 } else {
pbrook624f7972008-05-31 16:11:38 +0000555 q = alloc_sigqueue(env);
bellard9de5e442003-03-23 16:49:39 +0000556 if (!q)
557 return -EAGAIN;
558 while (*pq != NULL)
559 pq = &(*pq)->next;
560 }
561 }
562 *pq = q;
563 q->info = *info;
564 q->next = NULL;
565 k->pending = 1;
566 /* signal that a new signal is pending */
pbrook624f7972008-05-31 16:11:38 +0000567 ts->signal_pending = 1;
bellard9de5e442003-03-23 16:49:39 +0000568 return 1; /* indicates that the signal was queued */
569 }
570}
571
ths5fafdf22007-09-16 21:08:06 +0000572static void host_signal_handler(int host_signum, siginfo_t *info,
bellard9de5e442003-03-23 16:49:39 +0000573 void *puc)
574{
Andreas Färbera2247f82013-06-09 19:47:04 +0200575 CPUArchState *env = thread_cpu->env_ptr;
bellard9de5e442003-03-23 16:49:39 +0000576 int sig;
Anthony Liguoric227f092009-10-01 16:12:16 -0500577 target_siginfo_t tinfo;
bellard9de5e442003-03-23 16:49:39 +0000578
579 /* the CPU emulator uses some host signals to detect exceptions,
aurel32eaa449b2009-01-03 13:14:52 +0000580 we forward to it some signals */
aurel32ca587a82008-12-18 22:44:13 +0000581 if ((host_signum == SIGSEGV || host_signum == SIGBUS)
aurel32eaa449b2009-01-03 13:14:52 +0000582 && info->si_code > 0) {
bellardb346ff42003-06-15 20:05:50 +0000583 if (cpu_signal_handler(host_signum, info, puc))
bellard9de5e442003-03-23 16:49:39 +0000584 return;
585 }
586
587 /* get target signal number */
588 sig = host_to_target_signal(host_signum);
589 if (sig < 1 || sig > TARGET_NSIG)
590 return;
591#if defined(DEBUG_SIGNAL)
bellardbc8a22c2003-03-30 21:02:40 +0000592 fprintf(stderr, "qemu: got signal %d\n", sig);
bellard9de5e442003-03-23 16:49:39 +0000593#endif
594 host_to_target_siginfo_noswap(&tinfo, info);
Andreas Färbera2247f82013-06-09 19:47:04 +0200595 if (queue_signal(env, sig, &tinfo) == 1) {
bellard9de5e442003-03-23 16:49:39 +0000596 /* interrupt the virtual CPU as soon as possible */
Andreas Färbera2247f82013-06-09 19:47:04 +0200597 cpu_exit(thread_cpu);
bellard66fb9762003-03-23 01:06:05 +0000598 }
bellard31e31b82003-02-18 22:55:36 +0000599}
600
ths0da46a62007-10-20 20:23:07 +0000601/* do_sigaltstack() returns target values and errnos. */
bellard579a97f2007-11-11 14:26:47 +0000602/* compare linux/kernel/signal.c:do_sigaltstack() */
603abi_long do_sigaltstack(abi_ulong uss_addr, abi_ulong uoss_addr, abi_ulong sp)
thsa04e1342007-09-27 13:57:58 +0000604{
605 int ret;
606 struct target_sigaltstack oss;
607
608 /* XXX: test errors */
bellard579a97f2007-11-11 14:26:47 +0000609 if(uoss_addr)
thsa04e1342007-09-27 13:57:58 +0000610 {
611 __put_user(target_sigaltstack_used.ss_sp, &oss.ss_sp);
612 __put_user(target_sigaltstack_used.ss_size, &oss.ss_size);
613 __put_user(sas_ss_flags(sp), &oss.ss_flags);
614 }
615
bellard579a97f2007-11-11 14:26:47 +0000616 if(uss_addr)
thsa04e1342007-09-27 13:57:58 +0000617 {
bellard579a97f2007-11-11 14:26:47 +0000618 struct target_sigaltstack *uss;
619 struct target_sigaltstack ss;
Tom Musta0903c8b2014-08-12 13:53:40 -0500620 size_t minstacksize = TARGET_MINSIGSTKSZ;
621
622#if defined(TARGET_PPC64)
623 /* ELF V2 for PPC64 has a 4K minimum stack size for signal handlers */
624 struct image_info *image = ((TaskState *)thread_cpu->opaque)->info;
625 if (get_ppc64_abi(image) > 1) {
626 minstacksize = 4096;
627 }
628#endif
thsa04e1342007-09-27 13:57:58 +0000629
ths0da46a62007-10-20 20:23:07 +0000630 ret = -TARGET_EFAULT;
Riku Voipio9eeb8302014-04-23 11:26:34 +0300631 if (!lock_user_struct(VERIFY_READ, uss, uss_addr, 1)) {
thsa04e1342007-09-27 13:57:58 +0000632 goto out;
Riku Voipio9eeb8302014-04-23 11:26:34 +0300633 }
634 __get_user(ss.ss_sp, &uss->ss_sp);
635 __get_user(ss.ss_size, &uss->ss_size);
636 __get_user(ss.ss_flags, &uss->ss_flags);
bellard579a97f2007-11-11 14:26:47 +0000637 unlock_user_struct(uss, uss_addr, 0);
thsa04e1342007-09-27 13:57:58 +0000638
ths0da46a62007-10-20 20:23:07 +0000639 ret = -TARGET_EPERM;
thsa04e1342007-09-27 13:57:58 +0000640 if (on_sig_stack(sp))
641 goto out;
642
ths0da46a62007-10-20 20:23:07 +0000643 ret = -TARGET_EINVAL;
thsa04e1342007-09-27 13:57:58 +0000644 if (ss.ss_flags != TARGET_SS_DISABLE
645 && ss.ss_flags != TARGET_SS_ONSTACK
646 && ss.ss_flags != 0)
647 goto out;
648
649 if (ss.ss_flags == TARGET_SS_DISABLE) {
650 ss.ss_size = 0;
651 ss.ss_sp = 0;
652 } else {
ths0da46a62007-10-20 20:23:07 +0000653 ret = -TARGET_ENOMEM;
Tom Musta0903c8b2014-08-12 13:53:40 -0500654 if (ss.ss_size < minstacksize) {
thsa04e1342007-09-27 13:57:58 +0000655 goto out;
Tom Musta0903c8b2014-08-12 13:53:40 -0500656 }
thsa04e1342007-09-27 13:57:58 +0000657 }
658
659 target_sigaltstack_used.ss_sp = ss.ss_sp;
660 target_sigaltstack_used.ss_size = ss.ss_size;
661 }
662
bellard579a97f2007-11-11 14:26:47 +0000663 if (uoss_addr) {
ths0da46a62007-10-20 20:23:07 +0000664 ret = -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +0000665 if (copy_to_user(uoss_addr, &oss, sizeof(oss)))
thsa04e1342007-09-27 13:57:58 +0000666 goto out;
thsa04e1342007-09-27 13:57:58 +0000667 }
668
669 ret = 0;
670out:
671 return ret;
672}
673
ths0da46a62007-10-20 20:23:07 +0000674/* do_sigaction() return host values and errnos */
bellard66fb9762003-03-23 01:06:05 +0000675int do_sigaction(int sig, const struct target_sigaction *act,
676 struct target_sigaction *oact)
bellard31e31b82003-02-18 22:55:36 +0000677{
pbrook624f7972008-05-31 16:11:38 +0000678 struct target_sigaction *k;
bellard773b93e2004-01-04 17:15:59 +0000679 struct sigaction act1;
680 int host_sig;
ths0da46a62007-10-20 20:23:07 +0000681 int ret = 0;
bellard31e31b82003-02-18 22:55:36 +0000682
ths2a913eb2008-11-27 15:46:25 +0000683 if (sig < 1 || sig > TARGET_NSIG || sig == TARGET_SIGKILL || sig == TARGET_SIGSTOP)
bellard66fb9762003-03-23 01:06:05 +0000684 return -EINVAL;
685 k = &sigact_table[sig - 1];
bellard773b93e2004-01-04 17:15:59 +0000686#if defined(DEBUG_SIGNAL)
Blue Swirl0bf9e312009-07-20 17:19:25 +0000687 fprintf(stderr, "sigaction sig=%d act=0x%p, oact=0x%p\n",
688 sig, act, oact);
bellard66fb9762003-03-23 01:06:05 +0000689#endif
690 if (oact) {
Richard Hendersond2565872013-01-04 16:39:32 -0800691 __put_user(k->_sa_handler, &oact->_sa_handler);
692 __put_user(k->sa_flags, &oact->sa_flags);
ths388bb212007-05-13 13:58:00 +0000693#if !defined(TARGET_MIPS)
Richard Hendersond2565872013-01-04 16:39:32 -0800694 __put_user(k->sa_restorer, &oact->sa_restorer);
ths388bb212007-05-13 13:58:00 +0000695#endif
Richard Hendersond2565872013-01-04 16:39:32 -0800696 /* Not swapped. */
pbrook624f7972008-05-31 16:11:38 +0000697 oact->sa_mask = k->sa_mask;
bellard66fb9762003-03-23 01:06:05 +0000698 }
699 if (act) {
pbrook624f7972008-05-31 16:11:38 +0000700 /* FIXME: This is not threadsafe. */
Richard Hendersond2565872013-01-04 16:39:32 -0800701 __get_user(k->_sa_handler, &act->_sa_handler);
702 __get_user(k->sa_flags, &act->sa_flags);
ths388bb212007-05-13 13:58:00 +0000703#if !defined(TARGET_MIPS)
Richard Hendersond2565872013-01-04 16:39:32 -0800704 __get_user(k->sa_restorer, &act->sa_restorer);
ths388bb212007-05-13 13:58:00 +0000705#endif
Richard Hendersond2565872013-01-04 16:39:32 -0800706 /* To be swapped in target_to_host_sigset. */
pbrook624f7972008-05-31 16:11:38 +0000707 k->sa_mask = act->sa_mask;
bellard773b93e2004-01-04 17:15:59 +0000708
709 /* we update the host linux signal state */
710 host_sig = target_to_host_signal(sig);
711 if (host_sig != SIGSEGV && host_sig != SIGBUS) {
712 sigfillset(&act1.sa_mask);
713 act1.sa_flags = SA_SIGINFO;
pbrook624f7972008-05-31 16:11:38 +0000714 if (k->sa_flags & TARGET_SA_RESTART)
bellard773b93e2004-01-04 17:15:59 +0000715 act1.sa_flags |= SA_RESTART;
716 /* NOTE: it is important to update the host kernel signal
717 ignore state to avoid getting unexpected interrupted
718 syscalls */
pbrook624f7972008-05-31 16:11:38 +0000719 if (k->_sa_handler == TARGET_SIG_IGN) {
bellard773b93e2004-01-04 17:15:59 +0000720 act1.sa_sigaction = (void *)SIG_IGN;
pbrook624f7972008-05-31 16:11:38 +0000721 } else if (k->_sa_handler == TARGET_SIG_DFL) {
aurel32ca587a82008-12-18 22:44:13 +0000722 if (fatal_signal (sig))
723 act1.sa_sigaction = host_signal_handler;
724 else
725 act1.sa_sigaction = (void *)SIG_DFL;
bellard773b93e2004-01-04 17:15:59 +0000726 } else {
727 act1.sa_sigaction = host_signal_handler;
728 }
ths0da46a62007-10-20 20:23:07 +0000729 ret = sigaction(host_sig, &act1, NULL);
bellard773b93e2004-01-04 17:15:59 +0000730 }
bellard66fb9762003-03-23 01:06:05 +0000731 }
ths0da46a62007-10-20 20:23:07 +0000732 return ret;
bellard66fb9762003-03-23 01:06:05 +0000733}
bellard31e31b82003-02-18 22:55:36 +0000734
Riku Voipiob0fd8d12014-04-23 10:46:13 +0300735static inline void copy_siginfo_to_user(target_siginfo_t *tinfo,
Anthony Liguoric227f092009-10-01 16:12:16 -0500736 const target_siginfo_t *info)
bellard43fff232003-07-09 19:31:39 +0000737{
738 tswap_siginfo(tinfo, info);
bellard43fff232003-07-09 19:31:39 +0000739}
740
bellard459a4012007-11-11 19:45:10 +0000741#if defined(TARGET_I386) && TARGET_ABI_BITS == 32
bellard66fb9762003-03-23 01:06:05 +0000742
743/* from the Linux kernel */
744
745struct target_fpreg {
746 uint16_t significand[4];
747 uint16_t exponent;
748};
749
750struct target_fpxreg {
751 uint16_t significand[4];
752 uint16_t exponent;
753 uint16_t padding[3];
754};
755
756struct target_xmmreg {
blueswir1992f48a2007-10-14 16:27:31 +0000757 abi_ulong element[4];
bellard66fb9762003-03-23 01:06:05 +0000758};
759
760struct target_fpstate {
761 /* Regular FPU environment */
blueswir1992f48a2007-10-14 16:27:31 +0000762 abi_ulong cw;
763 abi_ulong sw;
764 abi_ulong tag;
765 abi_ulong ipoff;
766 abi_ulong cssel;
767 abi_ulong dataoff;
768 abi_ulong datasel;
bellard66fb9762003-03-23 01:06:05 +0000769 struct target_fpreg _st[8];
770 uint16_t status;
771 uint16_t magic; /* 0xffff = regular FPU data only */
772
773 /* FXSR FPU environment */
blueswir1992f48a2007-10-14 16:27:31 +0000774 abi_ulong _fxsr_env[6]; /* FXSR FPU env is ignored */
775 abi_ulong mxcsr;
776 abi_ulong reserved;
bellard66fb9762003-03-23 01:06:05 +0000777 struct target_fpxreg _fxsr_st[8]; /* FXSR FPU reg data is ignored */
778 struct target_xmmreg _xmm[8];
blueswir1992f48a2007-10-14 16:27:31 +0000779 abi_ulong padding[56];
bellard66fb9762003-03-23 01:06:05 +0000780};
781
782#define X86_FXSR_MAGIC 0x0000
783
784struct target_sigcontext {
785 uint16_t gs, __gsh;
786 uint16_t fs, __fsh;
787 uint16_t es, __esh;
788 uint16_t ds, __dsh;
blueswir1992f48a2007-10-14 16:27:31 +0000789 abi_ulong edi;
790 abi_ulong esi;
791 abi_ulong ebp;
792 abi_ulong esp;
793 abi_ulong ebx;
794 abi_ulong edx;
795 abi_ulong ecx;
796 abi_ulong eax;
797 abi_ulong trapno;
798 abi_ulong err;
799 abi_ulong eip;
bellard66fb9762003-03-23 01:06:05 +0000800 uint16_t cs, __csh;
blueswir1992f48a2007-10-14 16:27:31 +0000801 abi_ulong eflags;
802 abi_ulong esp_at_signal;
bellard66fb9762003-03-23 01:06:05 +0000803 uint16_t ss, __ssh;
blueswir1992f48a2007-10-14 16:27:31 +0000804 abi_ulong fpstate; /* pointer */
805 abi_ulong oldmask;
806 abi_ulong cr2;
bellard66fb9762003-03-23 01:06:05 +0000807};
808
bellard66fb9762003-03-23 01:06:05 +0000809struct target_ucontext {
blueswir1992f48a2007-10-14 16:27:31 +0000810 abi_ulong tuc_flags;
811 abi_ulong tuc_link;
Anthony Liguoric227f092009-10-01 16:12:16 -0500812 target_stack_t tuc_stack;
bellardb8076a72005-04-07 22:20:31 +0000813 struct target_sigcontext tuc_mcontext;
Anthony Liguoric227f092009-10-01 16:12:16 -0500814 target_sigset_t tuc_sigmask; /* mask last for extensibility */
bellard66fb9762003-03-23 01:06:05 +0000815};
816
817struct sigframe
818{
blueswir1992f48a2007-10-14 16:27:31 +0000819 abi_ulong pretcode;
bellard66fb9762003-03-23 01:06:05 +0000820 int sig;
821 struct target_sigcontext sc;
822 struct target_fpstate fpstate;
blueswir1992f48a2007-10-14 16:27:31 +0000823 abi_ulong extramask[TARGET_NSIG_WORDS-1];
bellard66fb9762003-03-23 01:06:05 +0000824 char retcode[8];
825};
826
827struct rt_sigframe
828{
blueswir1992f48a2007-10-14 16:27:31 +0000829 abi_ulong pretcode;
bellard66fb9762003-03-23 01:06:05 +0000830 int sig;
blueswir1992f48a2007-10-14 16:27:31 +0000831 abi_ulong pinfo;
832 abi_ulong puc;
bellard66fb9762003-03-23 01:06:05 +0000833 struct target_siginfo info;
834 struct target_ucontext uc;
835 struct target_fpstate fpstate;
836 char retcode[8];
837};
838
839/*
840 * Set up a signal frame.
841 */
842
bellard66fb9762003-03-23 01:06:05 +0000843/* XXX: save x87 state */
Riku Voipio41ecc722014-04-23 11:01:00 +0300844static void setup_sigcontext(struct target_sigcontext *sc,
845 struct target_fpstate *fpstate, CPUX86State *env, abi_ulong mask,
846 abi_ulong fpstate_addr)
bellard66fb9762003-03-23 01:06:05 +0000847{
Andreas Färber27103422013-08-26 08:31:06 +0200848 CPUState *cs = CPU(x86_env_get_cpu(env));
Andreas Färber27103422013-08-26 08:31:06 +0200849 uint16_t magic;
bellard66fb9762003-03-23 01:06:05 +0000850
bellard579a97f2007-11-11 14:26:47 +0000851 /* already locked in setup_frame() */
Riku Voipio1d8b5122014-04-23 10:26:05 +0300852 __put_user(env->segs[R_GS].selector, (unsigned int *)&sc->gs);
853 __put_user(env->segs[R_FS].selector, (unsigned int *)&sc->fs);
854 __put_user(env->segs[R_ES].selector, (unsigned int *)&sc->es);
855 __put_user(env->segs[R_DS].selector, (unsigned int *)&sc->ds);
856 __put_user(env->regs[R_EDI], &sc->edi);
857 __put_user(env->regs[R_ESI], &sc->esi);
858 __put_user(env->regs[R_EBP], &sc->ebp);
859 __put_user(env->regs[R_ESP], &sc->esp);
860 __put_user(env->regs[R_EBX], &sc->ebx);
861 __put_user(env->regs[R_EDX], &sc->edx);
862 __put_user(env->regs[R_ECX], &sc->ecx);
863 __put_user(env->regs[R_EAX], &sc->eax);
864 __put_user(cs->exception_index, &sc->trapno);
865 __put_user(env->error_code, &sc->err);
866 __put_user(env->eip, &sc->eip);
867 __put_user(env->segs[R_CS].selector, (unsigned int *)&sc->cs);
868 __put_user(env->eflags, &sc->eflags);
869 __put_user(env->regs[R_ESP], &sc->esp_at_signal);
870 __put_user(env->segs[R_SS].selector, (unsigned int *)&sc->ss);
bellarded2dcdf2003-05-29 20:06:27 +0000871
bellard28be6232007-11-11 22:23:38 +0000872 cpu_x86_fsave(env, fpstate_addr, 1);
bellarded2dcdf2003-05-29 20:06:27 +0000873 fpstate->status = fpstate->sw;
bellard775b58d2007-11-11 16:22:17 +0000874 magic = 0xffff;
Riku Voipio1d8b5122014-04-23 10:26:05 +0300875 __put_user(magic, &fpstate->magic);
876 __put_user(fpstate_addr, &sc->fpstate);
bellarded2dcdf2003-05-29 20:06:27 +0000877
bellard66fb9762003-03-23 01:06:05 +0000878 /* non-iBCS2 extensions.. */
Riku Voipio1d8b5122014-04-23 10:26:05 +0300879 __put_user(mask, &sc->oldmask);
880 __put_user(env->cr[2], &sc->cr2);
bellard66fb9762003-03-23 01:06:05 +0000881}
882
883/*
884 * Determine which stack to use..
885 */
886
bellard579a97f2007-11-11 14:26:47 +0000887static inline abi_ulong
pbrook624f7972008-05-31 16:11:38 +0000888get_sigframe(struct target_sigaction *ka, CPUX86State *env, size_t frame_size)
bellard66fb9762003-03-23 01:06:05 +0000889{
890 unsigned long esp;
891
892 /* Default to using normal stack */
893 esp = env->regs[R_ESP];
bellard66fb9762003-03-23 01:06:05 +0000894 /* This is the X/Open sanctioned signal stack switching. */
pbrook624f7972008-05-31 16:11:38 +0000895 if (ka->sa_flags & TARGET_SA_ONSTACK) {
thsa04e1342007-09-27 13:57:58 +0000896 if (sas_ss_flags(esp) == 0)
897 esp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
898 }
bellard66fb9762003-03-23 01:06:05 +0000899
900 /* This is the legacy signal stack switching. */
ths5fafdf22007-09-16 21:08:06 +0000901 else
bellarda52c7572003-06-21 13:14:12 +0000902 if ((env->segs[R_SS].selector & 0xffff) != __USER_DS &&
pbrook624f7972008-05-31 16:11:38 +0000903 !(ka->sa_flags & TARGET_SA_RESTORER) &&
904 ka->sa_restorer) {
905 esp = (unsigned long) ka->sa_restorer;
bellarda52c7572003-06-21 13:14:12 +0000906 }
bellard579a97f2007-11-11 14:26:47 +0000907 return (esp - frame_size) & -8ul;
bellard66fb9762003-03-23 01:06:05 +0000908}
909
bellard579a97f2007-11-11 14:26:47 +0000910/* compare linux/arch/i386/kernel/signal.c:setup_frame() */
pbrook624f7972008-05-31 16:11:38 +0000911static void setup_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -0500912 target_sigset_t *set, CPUX86State *env)
bellard66fb9762003-03-23 01:06:05 +0000913{
bellard579a97f2007-11-11 14:26:47 +0000914 abi_ulong frame_addr;
bellard66fb9762003-03-23 01:06:05 +0000915 struct sigframe *frame;
Riku Voipio7df2fa32014-04-23 10:34:53 +0300916 int i;
bellard66fb9762003-03-23 01:06:05 +0000917
bellard579a97f2007-11-11 14:26:47 +0000918 frame_addr = get_sigframe(ka, env, sizeof(*frame));
bellard66fb9762003-03-23 01:06:05 +0000919
bellard579a97f2007-11-11 14:26:47 +0000920 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
bellard66fb9762003-03-23 01:06:05 +0000921 goto give_sigsegv;
bellard579a97f2007-11-11 14:26:47 +0000922
Peter Maydellb6e2c932015-01-08 12:19:43 +0000923 __put_user(sig, &frame->sig);
bellard66fb9762003-03-23 01:06:05 +0000924
bellard28be6232007-11-11 22:23:38 +0000925 setup_sigcontext(&frame->sc, &frame->fpstate, env, set->sig[0],
926 frame_addr + offsetof(struct sigframe, fpstate));
bellard66fb9762003-03-23 01:06:05 +0000927
Riku Voipio7df2fa32014-04-23 10:34:53 +0300928 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
929 __put_user(set->sig[i], &frame->extramask[i - 1]);
930 }
bellard66fb9762003-03-23 01:06:05 +0000931
932 /* Set up to return from userspace. If provided, use a stub
933 already in userspace. */
pbrook624f7972008-05-31 16:11:38 +0000934 if (ka->sa_flags & TARGET_SA_RESTORER) {
Riku Voipio1d8b5122014-04-23 10:26:05 +0300935 __put_user(ka->sa_restorer, &frame->pretcode);
bellard66fb9762003-03-23 01:06:05 +0000936 } else {
bellard775b58d2007-11-11 16:22:17 +0000937 uint16_t val16;
bellard28be6232007-11-11 22:23:38 +0000938 abi_ulong retcode_addr;
939 retcode_addr = frame_addr + offsetof(struct sigframe, retcode);
Riku Voipio1d8b5122014-04-23 10:26:05 +0300940 __put_user(retcode_addr, &frame->pretcode);
bellard66fb9762003-03-23 01:06:05 +0000941 /* This is popl %eax ; movl $,%eax ; int $0x80 */
bellard775b58d2007-11-11 16:22:17 +0000942 val16 = 0xb858;
Riku Voipio1d8b5122014-04-23 10:26:05 +0300943 __put_user(val16, (uint16_t *)(frame->retcode+0));
944 __put_user(TARGET_NR_sigreturn, (int *)(frame->retcode+2));
bellard775b58d2007-11-11 16:22:17 +0000945 val16 = 0x80cd;
Riku Voipio1d8b5122014-04-23 10:26:05 +0300946 __put_user(val16, (uint16_t *)(frame->retcode+6));
bellard66fb9762003-03-23 01:06:05 +0000947 }
948
bellard66fb9762003-03-23 01:06:05 +0000949
950 /* Set up registers for signal handler */
bellard28be6232007-11-11 22:23:38 +0000951 env->regs[R_ESP] = frame_addr;
pbrook624f7972008-05-31 16:11:38 +0000952 env->eip = ka->_sa_handler;
bellard66fb9762003-03-23 01:06:05 +0000953
954 cpu_x86_load_seg(env, R_DS, __USER_DS);
955 cpu_x86_load_seg(env, R_ES, __USER_DS);
956 cpu_x86_load_seg(env, R_SS, __USER_DS);
957 cpu_x86_load_seg(env, R_CS, __USER_CS);
958 env->eflags &= ~TF_MASK;
959
bellard579a97f2007-11-11 14:26:47 +0000960 unlock_user_struct(frame, frame_addr, 1);
961
bellard66fb9762003-03-23 01:06:05 +0000962 return;
963
964give_sigsegv:
965 if (sig == TARGET_SIGSEGV)
pbrook624f7972008-05-31 16:11:38 +0000966 ka->_sa_handler = TARGET_SIG_DFL;
bellard66fb9762003-03-23 01:06:05 +0000967 force_sig(TARGET_SIGSEGV /* , current */);
968}
969
bellard579a97f2007-11-11 14:26:47 +0000970/* compare linux/arch/i386/kernel/signal.c:setup_rt_frame() */
pbrook624f7972008-05-31 16:11:38 +0000971static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -0500972 target_siginfo_t *info,
973 target_sigset_t *set, CPUX86State *env)
bellard66fb9762003-03-23 01:06:05 +0000974{
bellard28be6232007-11-11 22:23:38 +0000975 abi_ulong frame_addr, addr;
bellard66fb9762003-03-23 01:06:05 +0000976 struct rt_sigframe *frame;
Riku Voipio0188fad2014-04-23 13:34:15 +0300977 int i;
bellard66fb9762003-03-23 01:06:05 +0000978
bellard579a97f2007-11-11 14:26:47 +0000979 frame_addr = get_sigframe(ka, env, sizeof(*frame));
bellard66fb9762003-03-23 01:06:05 +0000980
bellard579a97f2007-11-11 14:26:47 +0000981 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
bellard66fb9762003-03-23 01:06:05 +0000982 goto give_sigsegv;
bellard66fb9762003-03-23 01:06:05 +0000983
Peter Maydellb6e2c932015-01-08 12:19:43 +0000984 __put_user(sig, &frame->sig);
bellard28be6232007-11-11 22:23:38 +0000985 addr = frame_addr + offsetof(struct rt_sigframe, info);
Riku Voipio1d8b5122014-04-23 10:26:05 +0300986 __put_user(addr, &frame->pinfo);
bellard28be6232007-11-11 22:23:38 +0000987 addr = frame_addr + offsetof(struct rt_sigframe, uc);
Riku Voipio1d8b5122014-04-23 10:26:05 +0300988 __put_user(addr, &frame->puc);
Riku Voipiob0fd8d12014-04-23 10:46:13 +0300989 copy_siginfo_to_user(&frame->info, info);
bellard66fb9762003-03-23 01:06:05 +0000990
991 /* Create the ucontext. */
Riku Voipio1d8b5122014-04-23 10:26:05 +0300992 __put_user(0, &frame->uc.tuc_flags);
993 __put_user(0, &frame->uc.tuc_link);
994 __put_user(target_sigaltstack_used.ss_sp, &frame->uc.tuc_stack.ss_sp);
995 __put_user(sas_ss_flags(get_sp_from_cpustate(env)),
996 &frame->uc.tuc_stack.ss_flags);
997 __put_user(target_sigaltstack_used.ss_size,
998 &frame->uc.tuc_stack.ss_size);
Riku Voipio41ecc722014-04-23 11:01:00 +0300999 setup_sigcontext(&frame->uc.tuc_mcontext, &frame->fpstate, env,
1000 set->sig[0], frame_addr + offsetof(struct rt_sigframe, fpstate));
1001
Riku Voipio0188fad2014-04-23 13:34:15 +03001002 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
1003 __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
1004 }
bellard66fb9762003-03-23 01:06:05 +00001005
1006 /* Set up to return from userspace. If provided, use a stub
1007 already in userspace. */
pbrook624f7972008-05-31 16:11:38 +00001008 if (ka->sa_flags & TARGET_SA_RESTORER) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03001009 __put_user(ka->sa_restorer, &frame->pretcode);
bellard66fb9762003-03-23 01:06:05 +00001010 } else {
bellard775b58d2007-11-11 16:22:17 +00001011 uint16_t val16;
bellard28be6232007-11-11 22:23:38 +00001012 addr = frame_addr + offsetof(struct rt_sigframe, retcode);
Riku Voipio1d8b5122014-04-23 10:26:05 +03001013 __put_user(addr, &frame->pretcode);
bellard66fb9762003-03-23 01:06:05 +00001014 /* This is movl $,%eax ; int $0x80 */
Riku Voipio1d8b5122014-04-23 10:26:05 +03001015 __put_user(0xb8, (char *)(frame->retcode+0));
1016 __put_user(TARGET_NR_rt_sigreturn, (int *)(frame->retcode+1));
bellard775b58d2007-11-11 16:22:17 +00001017 val16 = 0x80cd;
Riku Voipio1d8b5122014-04-23 10:26:05 +03001018 __put_user(val16, (uint16_t *)(frame->retcode+5));
bellard66fb9762003-03-23 01:06:05 +00001019 }
1020
bellard66fb9762003-03-23 01:06:05 +00001021 /* Set up registers for signal handler */
bellard28be6232007-11-11 22:23:38 +00001022 env->regs[R_ESP] = frame_addr;
pbrook624f7972008-05-31 16:11:38 +00001023 env->eip = ka->_sa_handler;
bellard66fb9762003-03-23 01:06:05 +00001024
1025 cpu_x86_load_seg(env, R_DS, __USER_DS);
1026 cpu_x86_load_seg(env, R_ES, __USER_DS);
1027 cpu_x86_load_seg(env, R_SS, __USER_DS);
1028 cpu_x86_load_seg(env, R_CS, __USER_CS);
1029 env->eflags &= ~TF_MASK;
1030
bellard579a97f2007-11-11 14:26:47 +00001031 unlock_user_struct(frame, frame_addr, 1);
1032
bellard66fb9762003-03-23 01:06:05 +00001033 return;
1034
1035give_sigsegv:
1036 if (sig == TARGET_SIGSEGV)
pbrook624f7972008-05-31 16:11:38 +00001037 ka->_sa_handler = TARGET_SIG_DFL;
bellard66fb9762003-03-23 01:06:05 +00001038 force_sig(TARGET_SIGSEGV /* , current */);
1039}
1040
1041static int
1042restore_sigcontext(CPUX86State *env, struct target_sigcontext *sc, int *peax)
1043{
1044 unsigned int err = 0;
bellard28be6232007-11-11 22:23:38 +00001045 abi_ulong fpstate_addr;
1046 unsigned int tmpflags;
bellard66fb9762003-03-23 01:06:05 +00001047
bellard28be6232007-11-11 22:23:38 +00001048 cpu_x86_load_seg(env, R_GS, tswap16(sc->gs));
1049 cpu_x86_load_seg(env, R_FS, tswap16(sc->fs));
1050 cpu_x86_load_seg(env, R_ES, tswap16(sc->es));
1051 cpu_x86_load_seg(env, R_DS, tswap16(sc->ds));
bellard66fb9762003-03-23 01:06:05 +00001052
bellard28be6232007-11-11 22:23:38 +00001053 env->regs[R_EDI] = tswapl(sc->edi);
1054 env->regs[R_ESI] = tswapl(sc->esi);
1055 env->regs[R_EBP] = tswapl(sc->ebp);
1056 env->regs[R_ESP] = tswapl(sc->esp);
1057 env->regs[R_EBX] = tswapl(sc->ebx);
1058 env->regs[R_EDX] = tswapl(sc->edx);
1059 env->regs[R_ECX] = tswapl(sc->ecx);
1060 env->eip = tswapl(sc->eip);
bellard66fb9762003-03-23 01:06:05 +00001061
Mike McCormack9a826d72011-06-01 15:14:37 +09001062 cpu_x86_load_seg(env, R_CS, lduw_p(&sc->cs) | 3);
1063 cpu_x86_load_seg(env, R_SS, lduw_p(&sc->ss) | 3);
ths5fafdf22007-09-16 21:08:06 +00001064
bellard28be6232007-11-11 22:23:38 +00001065 tmpflags = tswapl(sc->eflags);
1066 env->eflags = (env->eflags & ~0x40DD5) | (tmpflags & 0x40DD5);
1067 // regs->orig_eax = -1; /* disable syscall checks */
1068
1069 fpstate_addr = tswapl(sc->fpstate);
1070 if (fpstate_addr != 0) {
1071 if (!access_ok(VERIFY_READ, fpstate_addr,
1072 sizeof(struct target_fpstate)))
1073 goto badframe;
1074 cpu_x86_frstor(env, fpstate_addr, 1);
bellard66fb9762003-03-23 01:06:05 +00001075 }
1076
bellard28be6232007-11-11 22:23:38 +00001077 *peax = tswapl(sc->eax);
bellard66fb9762003-03-23 01:06:05 +00001078 return err;
bellard66fb9762003-03-23 01:06:05 +00001079badframe:
1080 return 1;
bellard66fb9762003-03-23 01:06:05 +00001081}
1082
1083long do_sigreturn(CPUX86State *env)
1084{
bellard579a97f2007-11-11 14:26:47 +00001085 struct sigframe *frame;
1086 abi_ulong frame_addr = env->regs[R_ESP] - 8;
Anthony Liguoric227f092009-10-01 16:12:16 -05001087 target_sigset_t target_set;
bellard66fb9762003-03-23 01:06:05 +00001088 sigset_t set;
1089 int eax, i;
1090
bellard447db212003-05-10 15:10:36 +00001091#if defined(DEBUG_SIGNAL)
1092 fprintf(stderr, "do_sigreturn\n");
1093#endif
bellard579a97f2007-11-11 14:26:47 +00001094 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
1095 goto badframe;
bellard66fb9762003-03-23 01:06:05 +00001096 /* set blocked signals */
Riku Voipiof5f601a2014-04-23 13:00:17 +03001097 __get_user(target_set.sig[0], &frame->sc.oldmask);
bellard92319442004-06-19 16:58:13 +00001098 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
Riku Voipiof5f601a2014-04-23 13:00:17 +03001099 __get_user(target_set.sig[i], &frame->extramask[i - 1]);
bellard92319442004-06-19 16:58:13 +00001100 }
bellard66fb9762003-03-23 01:06:05 +00001101
bellard92319442004-06-19 16:58:13 +00001102 target_to_host_sigset_internal(&set, &target_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00001103 do_sigprocmask(SIG_SETMASK, &set, NULL);
ths3b46e622007-09-17 08:09:54 +00001104
bellard66fb9762003-03-23 01:06:05 +00001105 /* restore registers */
1106 if (restore_sigcontext(env, &frame->sc, &eax))
1107 goto badframe;
bellard579a97f2007-11-11 14:26:47 +00001108 unlock_user_struct(frame, frame_addr, 0);
bellard66fb9762003-03-23 01:06:05 +00001109 return eax;
1110
1111badframe:
bellard579a97f2007-11-11 14:26:47 +00001112 unlock_user_struct(frame, frame_addr, 0);
bellard66fb9762003-03-23 01:06:05 +00001113 force_sig(TARGET_SIGSEGV);
1114 return 0;
1115}
1116
1117long do_rt_sigreturn(CPUX86State *env)
1118{
bellard28be6232007-11-11 22:23:38 +00001119 abi_ulong frame_addr;
1120 struct rt_sigframe *frame;
bellard66fb9762003-03-23 01:06:05 +00001121 sigset_t set;
bellard66fb9762003-03-23 01:06:05 +00001122 int eax;
1123
bellard28be6232007-11-11 22:23:38 +00001124 frame_addr = env->regs[R_ESP] - 4;
1125 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
1126 goto badframe;
bellardb8076a72005-04-07 22:20:31 +00001127 target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
Alex Barcelo1c275922014-03-14 14:36:55 +00001128 do_sigprocmask(SIG_SETMASK, &set, NULL);
ths5fafdf22007-09-16 21:08:06 +00001129
bellardb8076a72005-04-07 22:20:31 +00001130 if (restore_sigcontext(env, &frame->uc.tuc_mcontext, &eax))
bellard66fb9762003-03-23 01:06:05 +00001131 goto badframe;
1132
bellard28be6232007-11-11 22:23:38 +00001133 if (do_sigaltstack(frame_addr + offsetof(struct rt_sigframe, uc.tuc_stack), 0,
1134 get_sp_from_cpustate(env)) == -EFAULT)
bellard66fb9762003-03-23 01:06:05 +00001135 goto badframe;
thsa04e1342007-09-27 13:57:58 +00001136
bellard28be6232007-11-11 22:23:38 +00001137 unlock_user_struct(frame, frame_addr, 0);
bellard66fb9762003-03-23 01:06:05 +00001138 return eax;
1139
1140badframe:
bellard28be6232007-11-11 22:23:38 +00001141 unlock_user_struct(frame, frame_addr, 0);
1142 force_sig(TARGET_SIGSEGV);
bellard66fb9762003-03-23 01:06:05 +00001143 return 0;
1144}
1145
Andreas Schwab1744aea2013-09-03 20:12:16 +01001146#elif defined(TARGET_AARCH64)
1147
1148struct target_sigcontext {
1149 uint64_t fault_address;
1150 /* AArch64 registers */
1151 uint64_t regs[31];
1152 uint64_t sp;
1153 uint64_t pc;
1154 uint64_t pstate;
1155 /* 4K reserved for FP/SIMD state and future expansion */
1156 char __reserved[4096] __attribute__((__aligned__(16)));
1157};
1158
1159struct target_ucontext {
1160 abi_ulong tuc_flags;
1161 abi_ulong tuc_link;
1162 target_stack_t tuc_stack;
1163 target_sigset_t tuc_sigmask;
1164 /* glibc uses a 1024-bit sigset_t */
1165 char __unused[1024 / 8 - sizeof(target_sigset_t)];
1166 /* last for future expansion */
1167 struct target_sigcontext tuc_mcontext;
1168};
1169
1170/*
1171 * Header to be used at the beginning of structures extending the user
1172 * context. Such structures must be placed after the rt_sigframe on the stack
1173 * and be 16-byte aligned. The last structure must be a dummy one with the
1174 * magic and size set to 0.
1175 */
1176struct target_aarch64_ctx {
1177 uint32_t magic;
1178 uint32_t size;
1179};
1180
1181#define TARGET_FPSIMD_MAGIC 0x46508001
1182
1183struct target_fpsimd_context {
1184 struct target_aarch64_ctx head;
1185 uint32_t fpsr;
1186 uint32_t fpcr;
1187 uint64_t vregs[32 * 2]; /* really uint128_t vregs[32] */
1188};
1189
1190/*
1191 * Auxiliary context saved in the sigcontext.__reserved array. Not exported to
1192 * user space as it will change with the addition of new context. User space
1193 * should check the magic/size information.
1194 */
1195struct target_aux_context {
1196 struct target_fpsimd_context fpsimd;
1197 /* additional context to be added before "end" */
1198 struct target_aarch64_ctx end;
1199};
1200
1201struct target_rt_sigframe {
1202 struct target_siginfo info;
1203 struct target_ucontext uc;
1204 uint64_t fp;
1205 uint64_t lr;
1206 uint32_t tramp[2];
1207};
1208
1209static int target_setup_sigframe(struct target_rt_sigframe *sf,
1210 CPUARMState *env, target_sigset_t *set)
1211{
1212 int i;
1213 struct target_aux_context *aux =
1214 (struct target_aux_context *)sf->uc.tuc_mcontext.__reserved;
1215
1216 /* set up the stack frame for unwinding */
1217 __put_user(env->xregs[29], &sf->fp);
1218 __put_user(env->xregs[30], &sf->lr);
1219
1220 for (i = 0; i < 31; i++) {
1221 __put_user(env->xregs[i], &sf->uc.tuc_mcontext.regs[i]);
1222 }
1223 __put_user(env->xregs[31], &sf->uc.tuc_mcontext.sp);
1224 __put_user(env->pc, &sf->uc.tuc_mcontext.pc);
Peter Maydelld3563122013-12-17 19:42:30 +00001225 __put_user(pstate_read(env), &sf->uc.tuc_mcontext.pstate);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001226
Peter Maydell7af03922014-05-01 18:36:17 +01001227 __put_user(env->exception.vaddress, &sf->uc.tuc_mcontext.fault_address);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001228
1229 for (i = 0; i < TARGET_NSIG_WORDS; i++) {
1230 __put_user(set->sig[i], &sf->uc.tuc_sigmask.sig[i]);
1231 }
1232
1233 for (i = 0; i < 32; i++) {
1234#ifdef TARGET_WORDS_BIGENDIAN
1235 __put_user(env->vfp.regs[i * 2], &aux->fpsimd.vregs[i * 2 + 1]);
1236 __put_user(env->vfp.regs[i * 2 + 1], &aux->fpsimd.vregs[i * 2]);
1237#else
1238 __put_user(env->vfp.regs[i * 2], &aux->fpsimd.vregs[i * 2]);
1239 __put_user(env->vfp.regs[i * 2 + 1], &aux->fpsimd.vregs[i * 2 + 1]);
1240#endif
1241 }
Will Newtone0ee1382014-01-04 22:15:48 +00001242 __put_user(vfp_get_fpsr(env), &aux->fpsimd.fpsr);
1243 __put_user(vfp_get_fpcr(env), &aux->fpsimd.fpcr);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001244 __put_user(TARGET_FPSIMD_MAGIC, &aux->fpsimd.head.magic);
1245 __put_user(sizeof(struct target_fpsimd_context),
1246 &aux->fpsimd.head.size);
1247
1248 /* set the "end" magic */
1249 __put_user(0, &aux->end.magic);
1250 __put_user(0, &aux->end.size);
1251
1252 return 0;
1253}
1254
1255static int target_restore_sigframe(CPUARMState *env,
1256 struct target_rt_sigframe *sf)
1257{
1258 sigset_t set;
1259 int i;
1260 struct target_aux_context *aux =
1261 (struct target_aux_context *)sf->uc.tuc_mcontext.__reserved;
Will Newtone0ee1382014-01-04 22:15:48 +00001262 uint32_t magic, size, fpsr, fpcr;
Peter Maydelld3563122013-12-17 19:42:30 +00001263 uint64_t pstate;
Andreas Schwab1744aea2013-09-03 20:12:16 +01001264
1265 target_to_host_sigset(&set, &sf->uc.tuc_sigmask);
Alex Barcelo1c275922014-03-14 14:36:55 +00001266 do_sigprocmask(SIG_SETMASK, &set, NULL);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001267
1268 for (i = 0; i < 31; i++) {
1269 __get_user(env->xregs[i], &sf->uc.tuc_mcontext.regs[i]);
1270 }
1271
1272 __get_user(env->xregs[31], &sf->uc.tuc_mcontext.sp);
1273 __get_user(env->pc, &sf->uc.tuc_mcontext.pc);
Peter Maydelld3563122013-12-17 19:42:30 +00001274 __get_user(pstate, &sf->uc.tuc_mcontext.pstate);
1275 pstate_write(env, pstate);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001276
1277 __get_user(magic, &aux->fpsimd.head.magic);
1278 __get_user(size, &aux->fpsimd.head.size);
1279
1280 if (magic != TARGET_FPSIMD_MAGIC
1281 || size != sizeof(struct target_fpsimd_context)) {
1282 return 1;
1283 }
1284
Peter Maydell4cf23482014-03-02 19:36:38 +00001285 for (i = 0; i < 32; i++) {
1286#ifdef TARGET_WORDS_BIGENDIAN
1287 __get_user(env->vfp.regs[i * 2], &aux->fpsimd.vregs[i * 2 + 1]);
1288 __get_user(env->vfp.regs[i * 2 + 1], &aux->fpsimd.vregs[i * 2]);
1289#else
1290 __get_user(env->vfp.regs[i * 2], &aux->fpsimd.vregs[i * 2]);
1291 __get_user(env->vfp.regs[i * 2 + 1], &aux->fpsimd.vregs[i * 2 + 1]);
1292#endif
Andreas Schwab1744aea2013-09-03 20:12:16 +01001293 }
Will Newtone0ee1382014-01-04 22:15:48 +00001294 __get_user(fpsr, &aux->fpsimd.fpsr);
1295 vfp_set_fpsr(env, fpsr);
1296 __get_user(fpcr, &aux->fpsimd.fpcr);
1297 vfp_set_fpcr(env, fpcr);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001298
1299 return 0;
1300}
1301
1302static abi_ulong get_sigframe(struct target_sigaction *ka, CPUARMState *env)
1303{
1304 abi_ulong sp;
1305
1306 sp = env->xregs[31];
1307
1308 /*
1309 * This is the X/Open sanctioned signal stack switching.
1310 */
Riku Voipiob545f632014-07-15 17:01:55 +03001311 if ((ka->sa_flags & TARGET_SA_ONSTACK) && !sas_ss_flags(sp)) {
Andreas Schwab1744aea2013-09-03 20:12:16 +01001312 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
1313 }
1314
1315 sp = (sp - sizeof(struct target_rt_sigframe)) & ~15;
1316
1317 return sp;
1318}
1319
1320static void target_setup_frame(int usig, struct target_sigaction *ka,
1321 target_siginfo_t *info, target_sigset_t *set,
1322 CPUARMState *env)
1323{
1324 struct target_rt_sigframe *frame;
Michael Matz8a3ae912014-03-02 19:36:39 +00001325 abi_ulong frame_addr, return_addr;
Andreas Schwab1744aea2013-09-03 20:12:16 +01001326
1327 frame_addr = get_sigframe(ka, env);
1328 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
1329 goto give_sigsegv;
1330 }
1331
1332 __put_user(0, &frame->uc.tuc_flags);
1333 __put_user(0, &frame->uc.tuc_link);
1334
1335 __put_user(target_sigaltstack_used.ss_sp,
1336 &frame->uc.tuc_stack.ss_sp);
1337 __put_user(sas_ss_flags(env->xregs[31]),
1338 &frame->uc.tuc_stack.ss_flags);
1339 __put_user(target_sigaltstack_used.ss_size,
1340 &frame->uc.tuc_stack.ss_size);
1341 target_setup_sigframe(frame, env, set);
Michael Matz8a3ae912014-03-02 19:36:39 +00001342 if (ka->sa_flags & TARGET_SA_RESTORER) {
1343 return_addr = ka->sa_restorer;
1344 } else {
1345 /* mov x8,#__NR_rt_sigreturn; svc #0 */
1346 __put_user(0xd2801168, &frame->tramp[0]);
1347 __put_user(0xd4000001, &frame->tramp[1]);
1348 return_addr = frame_addr + offsetof(struct target_rt_sigframe, tramp);
1349 }
Andreas Schwab1744aea2013-09-03 20:12:16 +01001350 env->xregs[0] = usig;
1351 env->xregs[31] = frame_addr;
1352 env->xregs[29] = env->xregs[31] + offsetof(struct target_rt_sigframe, fp);
1353 env->pc = ka->_sa_handler;
Michael Matz8a3ae912014-03-02 19:36:39 +00001354 env->xregs[30] = return_addr;
Andreas Schwab1744aea2013-09-03 20:12:16 +01001355 if (info) {
Riku Voipiob0fd8d12014-04-23 10:46:13 +03001356 copy_siginfo_to_user(&frame->info, info);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001357 env->xregs[1] = frame_addr + offsetof(struct target_rt_sigframe, info);
1358 env->xregs[2] = frame_addr + offsetof(struct target_rt_sigframe, uc);
1359 }
1360
1361 unlock_user_struct(frame, frame_addr, 1);
1362 return;
1363
1364 give_sigsegv:
1365 unlock_user_struct(frame, frame_addr, 1);
1366 force_sig(TARGET_SIGSEGV);
1367}
1368
1369static void setup_rt_frame(int sig, struct target_sigaction *ka,
1370 target_siginfo_t *info, target_sigset_t *set,
1371 CPUARMState *env)
1372{
1373 target_setup_frame(sig, ka, info, set, env);
1374}
1375
1376static void setup_frame(int sig, struct target_sigaction *ka,
1377 target_sigset_t *set, CPUARMState *env)
1378{
1379 target_setup_frame(sig, ka, 0, set, env);
1380}
1381
1382long do_rt_sigreturn(CPUARMState *env)
1383{
Peter Maydell7f72cd22014-03-12 13:06:00 +00001384 struct target_rt_sigframe *frame = NULL;
Andreas Schwab1744aea2013-09-03 20:12:16 +01001385 abi_ulong frame_addr = env->xregs[31];
1386
1387 if (frame_addr & 15) {
1388 goto badframe;
1389 }
1390
1391 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
1392 goto badframe;
1393 }
1394
1395 if (target_restore_sigframe(env, frame)) {
1396 goto badframe;
1397 }
1398
1399 if (do_sigaltstack(frame_addr +
1400 offsetof(struct target_rt_sigframe, uc.tuc_stack),
1401 0, get_sp_from_cpustate(env)) == -EFAULT) {
1402 goto badframe;
1403 }
1404
1405 unlock_user_struct(frame, frame_addr, 0);
1406 return env->xregs[0];
1407
1408 badframe:
1409 unlock_user_struct(frame, frame_addr, 0);
1410 force_sig(TARGET_SIGSEGV);
1411 return 0;
1412}
1413
1414long do_sigreturn(CPUARMState *env)
1415{
1416 return do_rt_sigreturn(env);
1417}
1418
bellard43fff232003-07-09 19:31:39 +00001419#elif defined(TARGET_ARM)
1420
1421struct target_sigcontext {
blueswir1992f48a2007-10-14 16:27:31 +00001422 abi_ulong trap_no;
1423 abi_ulong error_code;
1424 abi_ulong oldmask;
1425 abi_ulong arm_r0;
1426 abi_ulong arm_r1;
1427 abi_ulong arm_r2;
1428 abi_ulong arm_r3;
1429 abi_ulong arm_r4;
1430 abi_ulong arm_r5;
1431 abi_ulong arm_r6;
1432 abi_ulong arm_r7;
1433 abi_ulong arm_r8;
1434 abi_ulong arm_r9;
1435 abi_ulong arm_r10;
1436 abi_ulong arm_fp;
1437 abi_ulong arm_ip;
1438 abi_ulong arm_sp;
1439 abi_ulong arm_lr;
1440 abi_ulong arm_pc;
1441 abi_ulong arm_cpsr;
1442 abi_ulong fault_address;
bellard43fff232003-07-09 19:31:39 +00001443};
1444
pbrooka745ec62008-05-06 15:36:17 +00001445struct target_ucontext_v1 {
blueswir1992f48a2007-10-14 16:27:31 +00001446 abi_ulong tuc_flags;
1447 abi_ulong tuc_link;
Anthony Liguoric227f092009-10-01 16:12:16 -05001448 target_stack_t tuc_stack;
bellardb8076a72005-04-07 22:20:31 +00001449 struct target_sigcontext tuc_mcontext;
Anthony Liguoric227f092009-10-01 16:12:16 -05001450 target_sigset_t tuc_sigmask; /* mask last for extensibility */
bellard43fff232003-07-09 19:31:39 +00001451};
1452
pbrooka745ec62008-05-06 15:36:17 +00001453struct target_ucontext_v2 {
1454 abi_ulong tuc_flags;
1455 abi_ulong tuc_link;
Anthony Liguoric227f092009-10-01 16:12:16 -05001456 target_stack_t tuc_stack;
pbrooka745ec62008-05-06 15:36:17 +00001457 struct target_sigcontext tuc_mcontext;
Anthony Liguoric227f092009-10-01 16:12:16 -05001458 target_sigset_t tuc_sigmask; /* mask last for extensibility */
Peter Maydell5f0b7c82010-11-24 15:20:03 +00001459 char __unused[128 - sizeof(target_sigset_t)];
pbrooka745ec62008-05-06 15:36:17 +00001460 abi_ulong tuc_regspace[128] __attribute__((__aligned__(8)));
1461};
1462
Peter Maydell0d871bd2010-11-24 15:20:05 +00001463struct target_user_vfp {
1464 uint64_t fpregs[32];
1465 abi_ulong fpscr;
1466};
1467
1468struct target_user_vfp_exc {
1469 abi_ulong fpexc;
1470 abi_ulong fpinst;
1471 abi_ulong fpinst2;
1472};
1473
1474struct target_vfp_sigframe {
1475 abi_ulong magic;
1476 abi_ulong size;
1477 struct target_user_vfp ufp;
1478 struct target_user_vfp_exc ufp_exc;
1479} __attribute__((__aligned__(8)));
1480
Peter Maydell08e11252010-11-24 15:20:07 +00001481struct target_iwmmxt_sigframe {
1482 abi_ulong magic;
1483 abi_ulong size;
1484 uint64_t regs[16];
1485 /* Note that not all the coprocessor control registers are stored here */
1486 uint32_t wcssf;
1487 uint32_t wcasf;
1488 uint32_t wcgr0;
1489 uint32_t wcgr1;
1490 uint32_t wcgr2;
1491 uint32_t wcgr3;
1492} __attribute__((__aligned__(8)));
1493
Peter Maydell0d871bd2010-11-24 15:20:05 +00001494#define TARGET_VFP_MAGIC 0x56465001
Peter Maydell08e11252010-11-24 15:20:07 +00001495#define TARGET_IWMMXT_MAGIC 0x12ef842a
Peter Maydell0d871bd2010-11-24 15:20:05 +00001496
pbrooka8c33202008-05-07 23:22:46 +00001497struct sigframe_v1
bellard43fff232003-07-09 19:31:39 +00001498{
1499 struct target_sigcontext sc;
blueswir1992f48a2007-10-14 16:27:31 +00001500 abi_ulong extramask[TARGET_NSIG_WORDS-1];
1501 abi_ulong retcode;
bellard43fff232003-07-09 19:31:39 +00001502};
1503
pbrooka8c33202008-05-07 23:22:46 +00001504struct sigframe_v2
1505{
1506 struct target_ucontext_v2 uc;
1507 abi_ulong retcode;
1508};
1509
pbrooka745ec62008-05-06 15:36:17 +00001510struct rt_sigframe_v1
bellard43fff232003-07-09 19:31:39 +00001511{
bellardf8b0aa22007-11-11 23:03:42 +00001512 abi_ulong pinfo;
1513 abi_ulong puc;
bellard43fff232003-07-09 19:31:39 +00001514 struct target_siginfo info;
pbrooka745ec62008-05-06 15:36:17 +00001515 struct target_ucontext_v1 uc;
1516 abi_ulong retcode;
1517};
1518
1519struct rt_sigframe_v2
1520{
1521 struct target_siginfo info;
1522 struct target_ucontext_v2 uc;
blueswir1992f48a2007-10-14 16:27:31 +00001523 abi_ulong retcode;
bellard43fff232003-07-09 19:31:39 +00001524};
1525
1526#define TARGET_CONFIG_CPU_32 1
1527
1528/*
1529 * For ARM syscalls, we encode the syscall number into the instruction.
1530 */
1531#define SWI_SYS_SIGRETURN (0xef000000|(TARGET_NR_sigreturn + ARM_SYSCALL_BASE))
1532#define SWI_SYS_RT_SIGRETURN (0xef000000|(TARGET_NR_rt_sigreturn + ARM_SYSCALL_BASE))
1533
1534/*
1535 * For Thumb syscalls, we pass the syscall number via r7. We therefore
1536 * need two 16-bit instructions.
1537 */
1538#define SWI_THUMB_SIGRETURN (0xdf00 << 16 | 0x2700 | (TARGET_NR_sigreturn))
1539#define SWI_THUMB_RT_SIGRETURN (0xdf00 << 16 | 0x2700 | (TARGET_NR_rt_sigreturn))
1540
blueswir1992f48a2007-10-14 16:27:31 +00001541static const abi_ulong retcodes[4] = {
bellard43fff232003-07-09 19:31:39 +00001542 SWI_SYS_SIGRETURN, SWI_THUMB_SIGRETURN,
1543 SWI_SYS_RT_SIGRETURN, SWI_THUMB_RT_SIGRETURN
1544};
1545
1546
Andreas Färber05390242012-02-25 03:37:53 +01001547static inline int valid_user_regs(CPUARMState *regs)
bellard43fff232003-07-09 19:31:39 +00001548{
1549 return 1;
1550}
1551
pbrooka8c33202008-05-07 23:22:46 +00001552static void
bellard43fff232003-07-09 19:31:39 +00001553setup_sigcontext(struct target_sigcontext *sc, /*struct _fpstate *fpstate,*/
Andreas Färber05390242012-02-25 03:37:53 +01001554 CPUARMState *env, abi_ulong mask)
bellard43fff232003-07-09 19:31:39 +00001555{
pbrooka8c33202008-05-07 23:22:46 +00001556 __put_user(env->regs[0], &sc->arm_r0);
1557 __put_user(env->regs[1], &sc->arm_r1);
1558 __put_user(env->regs[2], &sc->arm_r2);
1559 __put_user(env->regs[3], &sc->arm_r3);
1560 __put_user(env->regs[4], &sc->arm_r4);
1561 __put_user(env->regs[5], &sc->arm_r5);
1562 __put_user(env->regs[6], &sc->arm_r6);
1563 __put_user(env->regs[7], &sc->arm_r7);
1564 __put_user(env->regs[8], &sc->arm_r8);
1565 __put_user(env->regs[9], &sc->arm_r9);
1566 __put_user(env->regs[10], &sc->arm_r10);
1567 __put_user(env->regs[11], &sc->arm_fp);
1568 __put_user(env->regs[12], &sc->arm_ip);
1569 __put_user(env->regs[13], &sc->arm_sp);
1570 __put_user(env->regs[14], &sc->arm_lr);
1571 __put_user(env->regs[15], &sc->arm_pc);
bellard43fff232003-07-09 19:31:39 +00001572#ifdef TARGET_CONFIG_CPU_32
pbrooka8c33202008-05-07 23:22:46 +00001573 __put_user(cpsr_read(env), &sc->arm_cpsr);
bellard43fff232003-07-09 19:31:39 +00001574#endif
1575
pbrooka8c33202008-05-07 23:22:46 +00001576 __put_user(/* current->thread.trap_no */ 0, &sc->trap_no);
1577 __put_user(/* current->thread.error_code */ 0, &sc->error_code);
1578 __put_user(/* current->thread.address */ 0, &sc->fault_address);
1579 __put_user(mask, &sc->oldmask);
bellard43fff232003-07-09 19:31:39 +00001580}
1581
bellard579a97f2007-11-11 14:26:47 +00001582static inline abi_ulong
Andreas Färber05390242012-02-25 03:37:53 +01001583get_sigframe(struct target_sigaction *ka, CPUARMState *regs, int framesize)
bellard43fff232003-07-09 19:31:39 +00001584{
1585 unsigned long sp = regs->regs[13];
1586
bellard43fff232003-07-09 19:31:39 +00001587 /*
1588 * This is the X/Open sanctioned signal stack switching.
1589 */
pbrook624f7972008-05-31 16:11:38 +00001590 if ((ka->sa_flags & TARGET_SA_ONSTACK) && !sas_ss_flags(sp))
thsa04e1342007-09-27 13:57:58 +00001591 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
bellard43fff232003-07-09 19:31:39 +00001592 /*
1593 * ATPCS B01 mandates 8-byte alignment
1594 */
bellard579a97f2007-11-11 14:26:47 +00001595 return (sp - framesize) & ~7;
bellard43fff232003-07-09 19:31:39 +00001596}
1597
Riku Voipio0188fad2014-04-23 13:34:15 +03001598static void
Andreas Färber05390242012-02-25 03:37:53 +01001599setup_return(CPUARMState *env, struct target_sigaction *ka,
bellardf8b0aa22007-11-11 23:03:42 +00001600 abi_ulong *rc, abi_ulong frame_addr, int usig, abi_ulong rc_addr)
bellard43fff232003-07-09 19:31:39 +00001601{
pbrook624f7972008-05-31 16:11:38 +00001602 abi_ulong handler = ka->_sa_handler;
blueswir1992f48a2007-10-14 16:27:31 +00001603 abi_ulong retcode;
pbrook75b680e2008-03-21 16:07:30 +00001604 int thumb = handler & 1;
Peter Maydell964413d2011-01-14 20:39:19 +01001605 uint32_t cpsr = cpsr_read(env);
1606
1607 cpsr &= ~CPSR_IT;
1608 if (thumb) {
1609 cpsr |= CPSR_T;
1610 } else {
1611 cpsr &= ~CPSR_T;
1612 }
bellard43fff232003-07-09 19:31:39 +00001613
pbrook624f7972008-05-31 16:11:38 +00001614 if (ka->sa_flags & TARGET_SA_RESTORER) {
1615 retcode = ka->sa_restorer;
bellard43fff232003-07-09 19:31:39 +00001616 } else {
1617 unsigned int idx = thumb;
1618
pbrook624f7972008-05-31 16:11:38 +00001619 if (ka->sa_flags & TARGET_SA_SIGINFO)
bellard43fff232003-07-09 19:31:39 +00001620 idx += 2;
1621
Riku Voipio0188fad2014-04-23 13:34:15 +03001622 __put_user(retcodes[idx], rc);
Stefan Weilca8a2772011-10-03 22:43:19 +02001623
bellardf8b0aa22007-11-11 23:03:42 +00001624 retcode = rc_addr + thumb;
bellard43fff232003-07-09 19:31:39 +00001625 }
1626
1627 env->regs[0] = usig;
bellardf8b0aa22007-11-11 23:03:42 +00001628 env->regs[13] = frame_addr;
bellard43fff232003-07-09 19:31:39 +00001629 env->regs[14] = retcode;
1630 env->regs[15] = handler & (thumb ? ~1 : ~3);
Peter Maydell964413d2011-01-14 20:39:19 +01001631 cpsr_write(env, cpsr, 0xffffffff);
bellard43fff232003-07-09 19:31:39 +00001632}
1633
Andreas Färber05390242012-02-25 03:37:53 +01001634static abi_ulong *setup_sigframe_v2_vfp(abi_ulong *regspace, CPUARMState *env)
Peter Maydell0d871bd2010-11-24 15:20:05 +00001635{
1636 int i;
1637 struct target_vfp_sigframe *vfpframe;
1638 vfpframe = (struct target_vfp_sigframe *)regspace;
1639 __put_user(TARGET_VFP_MAGIC, &vfpframe->magic);
1640 __put_user(sizeof(*vfpframe), &vfpframe->size);
1641 for (i = 0; i < 32; i++) {
Peter Maydell005e1a02011-02-10 13:59:35 +00001642 __put_user(float64_val(env->vfp.regs[i]), &vfpframe->ufp.fpregs[i]);
Peter Maydell0d871bd2010-11-24 15:20:05 +00001643 }
1644 __put_user(vfp_get_fpscr(env), &vfpframe->ufp.fpscr);
1645 __put_user(env->vfp.xregs[ARM_VFP_FPEXC], &vfpframe->ufp_exc.fpexc);
1646 __put_user(env->vfp.xregs[ARM_VFP_FPINST], &vfpframe->ufp_exc.fpinst);
1647 __put_user(env->vfp.xregs[ARM_VFP_FPINST2], &vfpframe->ufp_exc.fpinst2);
1648 return (abi_ulong*)(vfpframe+1);
1649}
1650
Andreas Färber05390242012-02-25 03:37:53 +01001651static abi_ulong *setup_sigframe_v2_iwmmxt(abi_ulong *regspace,
1652 CPUARMState *env)
Peter Maydell08e11252010-11-24 15:20:07 +00001653{
1654 int i;
1655 struct target_iwmmxt_sigframe *iwmmxtframe;
1656 iwmmxtframe = (struct target_iwmmxt_sigframe *)regspace;
1657 __put_user(TARGET_IWMMXT_MAGIC, &iwmmxtframe->magic);
1658 __put_user(sizeof(*iwmmxtframe), &iwmmxtframe->size);
1659 for (i = 0; i < 16; i++) {
1660 __put_user(env->iwmmxt.regs[i], &iwmmxtframe->regs[i]);
1661 }
1662 __put_user(env->vfp.xregs[ARM_IWMMXT_wCSSF], &iwmmxtframe->wcssf);
1663 __put_user(env->vfp.xregs[ARM_IWMMXT_wCASF], &iwmmxtframe->wcssf);
1664 __put_user(env->vfp.xregs[ARM_IWMMXT_wCGR0], &iwmmxtframe->wcgr0);
1665 __put_user(env->vfp.xregs[ARM_IWMMXT_wCGR1], &iwmmxtframe->wcgr1);
1666 __put_user(env->vfp.xregs[ARM_IWMMXT_wCGR2], &iwmmxtframe->wcgr2);
1667 __put_user(env->vfp.xregs[ARM_IWMMXT_wCGR3], &iwmmxtframe->wcgr3);
1668 return (abi_ulong*)(iwmmxtframe+1);
1669}
1670
pbrooka8c33202008-05-07 23:22:46 +00001671static void setup_sigframe_v2(struct target_ucontext_v2 *uc,
Andreas Färber05390242012-02-25 03:37:53 +01001672 target_sigset_t *set, CPUARMState *env)
bellard43fff232003-07-09 19:31:39 +00001673{
pbrooka8c33202008-05-07 23:22:46 +00001674 struct target_sigaltstack stack;
1675 int i;
Peter Maydell0d871bd2010-11-24 15:20:05 +00001676 abi_ulong *regspace;
pbrooka8c33202008-05-07 23:22:46 +00001677
1678 /* Clear all the bits of the ucontext we don't use. */
1679 memset(uc, 0, offsetof(struct target_ucontext_v2, tuc_mcontext));
1680
1681 memset(&stack, 0, sizeof(stack));
1682 __put_user(target_sigaltstack_used.ss_sp, &stack.ss_sp);
1683 __put_user(target_sigaltstack_used.ss_size, &stack.ss_size);
1684 __put_user(sas_ss_flags(get_sp_from_cpustate(env)), &stack.ss_flags);
1685 memcpy(&uc->tuc_stack, &stack, sizeof(stack));
1686
1687 setup_sigcontext(&uc->tuc_mcontext, env, set->sig[0]);
Peter Maydell0d871bd2010-11-24 15:20:05 +00001688 /* Save coprocessor signal frame. */
1689 regspace = uc->tuc_regspace;
1690 if (arm_feature(env, ARM_FEATURE_VFP)) {
1691 regspace = setup_sigframe_v2_vfp(regspace, env);
1692 }
Peter Maydell08e11252010-11-24 15:20:07 +00001693 if (arm_feature(env, ARM_FEATURE_IWMMXT)) {
1694 regspace = setup_sigframe_v2_iwmmxt(regspace, env);
1695 }
1696
Peter Maydell0d871bd2010-11-24 15:20:05 +00001697 /* Write terminating magic word */
1698 __put_user(0, regspace);
1699
pbrooka8c33202008-05-07 23:22:46 +00001700 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
1701 __put_user(set->sig[i], &uc->tuc_sigmask.sig[i]);
1702 }
1703}
1704
1705/* compare linux/arch/arm/kernel/signal.c:setup_frame() */
pbrook624f7972008-05-31 16:11:38 +00001706static void setup_frame_v1(int usig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01001707 target_sigset_t *set, CPUARMState *regs)
pbrooka8c33202008-05-07 23:22:46 +00001708{
1709 struct sigframe_v1 *frame;
bellard579a97f2007-11-11 14:26:47 +00001710 abi_ulong frame_addr = get_sigframe(ka, regs, sizeof(*frame));
pbrooka8c33202008-05-07 23:22:46 +00001711 int i;
bellard43fff232003-07-09 19:31:39 +00001712
bellard579a97f2007-11-11 14:26:47 +00001713 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
1714 return;
1715
pbrooka8c33202008-05-07 23:22:46 +00001716 setup_sigcontext(&frame->sc, regs, set->sig[0]);
bellard43fff232003-07-09 19:31:39 +00001717
Riku Voipio0188fad2014-04-23 13:34:15 +03001718 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
1719 __put_user(set->sig[i], &frame->extramask[i - 1]);
1720 }
bellard43fff232003-07-09 19:31:39 +00001721
pbrooka8c33202008-05-07 23:22:46 +00001722 setup_return(regs, ka, &frame->retcode, frame_addr, usig,
1723 frame_addr + offsetof(struct sigframe_v1, retcode));
bellard579a97f2007-11-11 14:26:47 +00001724
bellard579a97f2007-11-11 14:26:47 +00001725 unlock_user_struct(frame, frame_addr, 1);
pbrooka8c33202008-05-07 23:22:46 +00001726}
1727
pbrook624f7972008-05-31 16:11:38 +00001728static void setup_frame_v2(int usig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01001729 target_sigset_t *set, CPUARMState *regs)
pbrooka8c33202008-05-07 23:22:46 +00001730{
1731 struct sigframe_v2 *frame;
1732 abi_ulong frame_addr = get_sigframe(ka, regs, sizeof(*frame));
1733
1734 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
1735 return;
1736
1737 setup_sigframe_v2(&frame->uc, set, regs);
1738
1739 setup_return(regs, ka, &frame->retcode, frame_addr, usig,
1740 frame_addr + offsetof(struct sigframe_v2, retcode));
1741
1742 unlock_user_struct(frame, frame_addr, 1);
1743}
1744
pbrook624f7972008-05-31 16:11:38 +00001745static void setup_frame(int usig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01001746 target_sigset_t *set, CPUARMState *regs)
pbrooka8c33202008-05-07 23:22:46 +00001747{
1748 if (get_osversion() >= 0x020612) {
1749 setup_frame_v2(usig, ka, set, regs);
1750 } else {
1751 setup_frame_v1(usig, ka, set, regs);
1752 }
bellard43fff232003-07-09 19:31:39 +00001753}
1754
bellard579a97f2007-11-11 14:26:47 +00001755/* compare linux/arch/arm/kernel/signal.c:setup_rt_frame() */
pbrook624f7972008-05-31 16:11:38 +00001756static void setup_rt_frame_v1(int usig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05001757 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01001758 target_sigset_t *set, CPUARMState *env)
bellard43fff232003-07-09 19:31:39 +00001759{
pbrooka745ec62008-05-06 15:36:17 +00001760 struct rt_sigframe_v1 *frame;
bellard579a97f2007-11-11 14:26:47 +00001761 abi_ulong frame_addr = get_sigframe(ka, env, sizeof(*frame));
thsa04e1342007-09-27 13:57:58 +00001762 struct target_sigaltstack stack;
pbrooka8c33202008-05-07 23:22:46 +00001763 int i;
bellardf8b0aa22007-11-11 23:03:42 +00001764 abi_ulong info_addr, uc_addr;
bellard43fff232003-07-09 19:31:39 +00001765
bellard579a97f2007-11-11 14:26:47 +00001766 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
bellardedf779f2004-02-22 13:40:13 +00001767 return /* 1 */;
1768
pbrooka745ec62008-05-06 15:36:17 +00001769 info_addr = frame_addr + offsetof(struct rt_sigframe_v1, info);
pbrooka8c33202008-05-07 23:22:46 +00001770 __put_user(info_addr, &frame->pinfo);
pbrooka745ec62008-05-06 15:36:17 +00001771 uc_addr = frame_addr + offsetof(struct rt_sigframe_v1, uc);
pbrooka8c33202008-05-07 23:22:46 +00001772 __put_user(uc_addr, &frame->puc);
1773 copy_siginfo_to_user(&frame->info, info);
bellard43fff232003-07-09 19:31:39 +00001774
1775 /* Clear all the bits of the ucontext we don't use. */
pbrooka745ec62008-05-06 15:36:17 +00001776 memset(&frame->uc, 0, offsetof(struct target_ucontext_v1, tuc_mcontext));
bellard43fff232003-07-09 19:31:39 +00001777
thsa04e1342007-09-27 13:57:58 +00001778 memset(&stack, 0, sizeof(stack));
1779 __put_user(target_sigaltstack_used.ss_sp, &stack.ss_sp);
1780 __put_user(target_sigaltstack_used.ss_size, &stack.ss_size);
1781 __put_user(sas_ss_flags(get_sp_from_cpustate(env)), &stack.ss_flags);
bellard775b58d2007-11-11 16:22:17 +00001782 memcpy(&frame->uc.tuc_stack, &stack, sizeof(stack));
thsa04e1342007-09-27 13:57:58 +00001783
pbrooka8c33202008-05-07 23:22:46 +00001784 setup_sigcontext(&frame->uc.tuc_mcontext, env, set->sig[0]);
bellard92319442004-06-19 16:58:13 +00001785 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
Riku Voipio0188fad2014-04-23 13:34:15 +03001786 __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
bellard92319442004-06-19 16:58:13 +00001787 }
bellard43fff232003-07-09 19:31:39 +00001788
pbrooka8c33202008-05-07 23:22:46 +00001789 setup_return(env, ka, &frame->retcode, frame_addr, usig,
1790 frame_addr + offsetof(struct rt_sigframe_v1, retcode));
pbrooka745ec62008-05-06 15:36:17 +00001791
pbrooka8c33202008-05-07 23:22:46 +00001792 env->regs[1] = info_addr;
1793 env->regs[2] = uc_addr;
pbrooka745ec62008-05-06 15:36:17 +00001794
pbrooka745ec62008-05-06 15:36:17 +00001795 unlock_user_struct(frame, frame_addr, 1);
pbrooka745ec62008-05-06 15:36:17 +00001796}
1797
pbrook624f7972008-05-31 16:11:38 +00001798static void setup_rt_frame_v2(int usig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05001799 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01001800 target_sigset_t *set, CPUARMState *env)
pbrooka745ec62008-05-06 15:36:17 +00001801{
1802 struct rt_sigframe_v2 *frame;
1803 abi_ulong frame_addr = get_sigframe(ka, env, sizeof(*frame));
pbrooka745ec62008-05-06 15:36:17 +00001804 abi_ulong info_addr, uc_addr;
1805
1806 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
1807 return /* 1 */;
1808
1809 info_addr = frame_addr + offsetof(struct rt_sigframe_v2, info);
1810 uc_addr = frame_addr + offsetof(struct rt_sigframe_v2, uc);
pbrooka8c33202008-05-07 23:22:46 +00001811 copy_siginfo_to_user(&frame->info, info);
pbrooka745ec62008-05-06 15:36:17 +00001812
pbrooka8c33202008-05-07 23:22:46 +00001813 setup_sigframe_v2(&frame->uc, set, env);
pbrooka745ec62008-05-06 15:36:17 +00001814
pbrooka8c33202008-05-07 23:22:46 +00001815 setup_return(env, ka, &frame->retcode, frame_addr, usig,
1816 frame_addr + offsetof(struct rt_sigframe_v2, retcode));
pbrooka745ec62008-05-06 15:36:17 +00001817
pbrooka8c33202008-05-07 23:22:46 +00001818 env->regs[1] = info_addr;
1819 env->regs[2] = uc_addr;
pbrooka745ec62008-05-06 15:36:17 +00001820
bellard579a97f2007-11-11 14:26:47 +00001821 unlock_user_struct(frame, frame_addr, 1);
bellard43fff232003-07-09 19:31:39 +00001822}
1823
pbrook624f7972008-05-31 16:11:38 +00001824static void setup_rt_frame(int usig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05001825 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01001826 target_sigset_t *set, CPUARMState *env)
pbrooka745ec62008-05-06 15:36:17 +00001827{
1828 if (get_osversion() >= 0x020612) {
1829 setup_rt_frame_v2(usig, ka, info, set, env);
1830 } else {
1831 setup_rt_frame_v1(usig, ka, info, set, env);
1832 }
1833}
1834
bellard43fff232003-07-09 19:31:39 +00001835static int
Andreas Färber05390242012-02-25 03:37:53 +01001836restore_sigcontext(CPUARMState *env, struct target_sigcontext *sc)
bellard43fff232003-07-09 19:31:39 +00001837{
1838 int err = 0;
bellardb5ff1b32005-11-26 10:38:39 +00001839 uint32_t cpsr;
bellard43fff232003-07-09 19:31:39 +00001840
Riku Voipio1d8b5122014-04-23 10:26:05 +03001841 __get_user(env->regs[0], &sc->arm_r0);
1842 __get_user(env->regs[1], &sc->arm_r1);
1843 __get_user(env->regs[2], &sc->arm_r2);
1844 __get_user(env->regs[3], &sc->arm_r3);
1845 __get_user(env->regs[4], &sc->arm_r4);
1846 __get_user(env->regs[5], &sc->arm_r5);
1847 __get_user(env->regs[6], &sc->arm_r6);
1848 __get_user(env->regs[7], &sc->arm_r7);
1849 __get_user(env->regs[8], &sc->arm_r8);
1850 __get_user(env->regs[9], &sc->arm_r9);
1851 __get_user(env->regs[10], &sc->arm_r10);
1852 __get_user(env->regs[11], &sc->arm_fp);
1853 __get_user(env->regs[12], &sc->arm_ip);
1854 __get_user(env->regs[13], &sc->arm_sp);
1855 __get_user(env->regs[14], &sc->arm_lr);
1856 __get_user(env->regs[15], &sc->arm_pc);
bellard43fff232003-07-09 19:31:39 +00001857#ifdef TARGET_CONFIG_CPU_32
Riku Voipio1d8b5122014-04-23 10:26:05 +03001858 __get_user(cpsr, &sc->arm_cpsr);
pbrook75b680e2008-03-21 16:07:30 +00001859 cpsr_write(env, cpsr, CPSR_USER | CPSR_EXEC);
bellard43fff232003-07-09 19:31:39 +00001860#endif
1861
1862 err |= !valid_user_regs(env);
1863
1864 return err;
1865}
1866
Andreas Färber05390242012-02-25 03:37:53 +01001867static long do_sigreturn_v1(CPUARMState *env)
bellard43fff232003-07-09 19:31:39 +00001868{
bellardf8b0aa22007-11-11 23:03:42 +00001869 abi_ulong frame_addr;
Peter Maydell978fae92013-07-29 12:00:32 +01001870 struct sigframe_v1 *frame = NULL;
Anthony Liguoric227f092009-10-01 16:12:16 -05001871 target_sigset_t set;
bellard43fff232003-07-09 19:31:39 +00001872 sigset_t host_set;
bellard92319442004-06-19 16:58:13 +00001873 int i;
bellard43fff232003-07-09 19:31:39 +00001874
1875 /*
1876 * Since we stacked the signal on a 64-bit boundary,
1877 * then 'sp' should be word aligned here. If it's
1878 * not, then the user is trying to mess with us.
1879 */
bellardf8b0aa22007-11-11 23:03:42 +00001880 frame_addr = env->regs[13];
Peter Maydell978fae92013-07-29 12:00:32 +01001881 if (frame_addr & 7) {
1882 goto badframe;
1883 }
1884
bellardf8b0aa22007-11-11 23:03:42 +00001885 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
1886 goto badframe;
bellard43fff232003-07-09 19:31:39 +00001887
Riku Voipiof5f601a2014-04-23 13:00:17 +03001888 __get_user(set.sig[0], &frame->sc.oldmask);
1889 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
1890 __get_user(set.sig[i], &frame->extramask[i - 1]);
1891 }
bellard43fff232003-07-09 19:31:39 +00001892
bellard92319442004-06-19 16:58:13 +00001893 target_to_host_sigset_internal(&host_set, &set);
Alex Barcelo1c275922014-03-14 14:36:55 +00001894 do_sigprocmask(SIG_SETMASK, &host_set, NULL);
bellard43fff232003-07-09 19:31:39 +00001895
1896 if (restore_sigcontext(env, &frame->sc))
1897 goto badframe;
1898
1899#if 0
1900 /* Send SIGTRAP if we're single-stepping */
1901 if (ptrace_cancel_bpt(current))
1902 send_sig(SIGTRAP, current, 1);
1903#endif
bellardf8b0aa22007-11-11 23:03:42 +00001904 unlock_user_struct(frame, frame_addr, 0);
1905 return env->regs[0];
bellard43fff232003-07-09 19:31:39 +00001906
1907badframe:
Riku Voipio66393fb2009-12-04 15:16:32 +02001908 force_sig(TARGET_SIGSEGV /* , current */);
bellard43fff232003-07-09 19:31:39 +00001909 return 0;
1910}
1911
Andreas Färber05390242012-02-25 03:37:53 +01001912static abi_ulong *restore_sigframe_v2_vfp(CPUARMState *env, abi_ulong *regspace)
Peter Maydell5f9099d2010-11-24 15:20:06 +00001913{
1914 int i;
1915 abi_ulong magic, sz;
1916 uint32_t fpscr, fpexc;
1917 struct target_vfp_sigframe *vfpframe;
1918 vfpframe = (struct target_vfp_sigframe *)regspace;
1919
1920 __get_user(magic, &vfpframe->magic);
1921 __get_user(sz, &vfpframe->size);
1922 if (magic != TARGET_VFP_MAGIC || sz != sizeof(*vfpframe)) {
1923 return 0;
1924 }
1925 for (i = 0; i < 32; i++) {
Peter Maydell005e1a02011-02-10 13:59:35 +00001926 __get_user(float64_val(env->vfp.regs[i]), &vfpframe->ufp.fpregs[i]);
Peter Maydell5f9099d2010-11-24 15:20:06 +00001927 }
1928 __get_user(fpscr, &vfpframe->ufp.fpscr);
1929 vfp_set_fpscr(env, fpscr);
1930 __get_user(fpexc, &vfpframe->ufp_exc.fpexc);
1931 /* Sanitise FPEXC: ensure VFP is enabled, FPINST2 is invalid
1932 * and the exception flag is cleared
1933 */
1934 fpexc |= (1 << 30);
1935 fpexc &= ~((1 << 31) | (1 << 28));
1936 env->vfp.xregs[ARM_VFP_FPEXC] = fpexc;
1937 __get_user(env->vfp.xregs[ARM_VFP_FPINST], &vfpframe->ufp_exc.fpinst);
1938 __get_user(env->vfp.xregs[ARM_VFP_FPINST2], &vfpframe->ufp_exc.fpinst2);
1939 return (abi_ulong*)(vfpframe + 1);
1940}
1941
Andreas Färber05390242012-02-25 03:37:53 +01001942static abi_ulong *restore_sigframe_v2_iwmmxt(CPUARMState *env,
1943 abi_ulong *regspace)
Peter Maydella59d69d2010-11-24 15:20:08 +00001944{
1945 int i;
1946 abi_ulong magic, sz;
1947 struct target_iwmmxt_sigframe *iwmmxtframe;
1948 iwmmxtframe = (struct target_iwmmxt_sigframe *)regspace;
1949
1950 __get_user(magic, &iwmmxtframe->magic);
1951 __get_user(sz, &iwmmxtframe->size);
1952 if (magic != TARGET_IWMMXT_MAGIC || sz != sizeof(*iwmmxtframe)) {
1953 return 0;
1954 }
1955 for (i = 0; i < 16; i++) {
1956 __get_user(env->iwmmxt.regs[i], &iwmmxtframe->regs[i]);
1957 }
1958 __get_user(env->vfp.xregs[ARM_IWMMXT_wCSSF], &iwmmxtframe->wcssf);
1959 __get_user(env->vfp.xregs[ARM_IWMMXT_wCASF], &iwmmxtframe->wcssf);
1960 __get_user(env->vfp.xregs[ARM_IWMMXT_wCGR0], &iwmmxtframe->wcgr0);
1961 __get_user(env->vfp.xregs[ARM_IWMMXT_wCGR1], &iwmmxtframe->wcgr1);
1962 __get_user(env->vfp.xregs[ARM_IWMMXT_wCGR2], &iwmmxtframe->wcgr2);
1963 __get_user(env->vfp.xregs[ARM_IWMMXT_wCGR3], &iwmmxtframe->wcgr3);
1964 return (abi_ulong*)(iwmmxtframe + 1);
1965}
1966
Andreas Färber05390242012-02-25 03:37:53 +01001967static int do_sigframe_return_v2(CPUARMState *env, target_ulong frame_addr,
pbrooka8c33202008-05-07 23:22:46 +00001968 struct target_ucontext_v2 *uc)
1969{
1970 sigset_t host_set;
Peter Maydell5f9099d2010-11-24 15:20:06 +00001971 abi_ulong *regspace;
pbrooka8c33202008-05-07 23:22:46 +00001972
1973 target_to_host_sigset(&host_set, &uc->tuc_sigmask);
Alex Barcelo1c275922014-03-14 14:36:55 +00001974 do_sigprocmask(SIG_SETMASK, &host_set, NULL);
pbrooka8c33202008-05-07 23:22:46 +00001975
1976 if (restore_sigcontext(env, &uc->tuc_mcontext))
1977 return 1;
1978
Peter Maydell5f9099d2010-11-24 15:20:06 +00001979 /* Restore coprocessor signal frame */
1980 regspace = uc->tuc_regspace;
1981 if (arm_feature(env, ARM_FEATURE_VFP)) {
1982 regspace = restore_sigframe_v2_vfp(env, regspace);
1983 if (!regspace) {
1984 return 1;
1985 }
1986 }
Peter Maydella59d69d2010-11-24 15:20:08 +00001987 if (arm_feature(env, ARM_FEATURE_IWMMXT)) {
1988 regspace = restore_sigframe_v2_iwmmxt(env, regspace);
1989 if (!regspace) {
1990 return 1;
1991 }
1992 }
Peter Maydell5f9099d2010-11-24 15:20:06 +00001993
pbrooka8c33202008-05-07 23:22:46 +00001994 if (do_sigaltstack(frame_addr + offsetof(struct target_ucontext_v2, tuc_stack), 0, get_sp_from_cpustate(env)) == -EFAULT)
1995 return 1;
1996
1997#if 0
1998 /* Send SIGTRAP if we're single-stepping */
1999 if (ptrace_cancel_bpt(current))
2000 send_sig(SIGTRAP, current, 1);
2001#endif
2002
2003 return 0;
2004}
2005
Andreas Färber05390242012-02-25 03:37:53 +01002006static long do_sigreturn_v2(CPUARMState *env)
pbrooka8c33202008-05-07 23:22:46 +00002007{
2008 abi_ulong frame_addr;
Peter Maydell978fae92013-07-29 12:00:32 +01002009 struct sigframe_v2 *frame = NULL;
pbrooka8c33202008-05-07 23:22:46 +00002010
2011 /*
2012 * Since we stacked the signal on a 64-bit boundary,
2013 * then 'sp' should be word aligned here. If it's
2014 * not, then the user is trying to mess with us.
2015 */
pbrooka8c33202008-05-07 23:22:46 +00002016 frame_addr = env->regs[13];
Peter Maydell978fae92013-07-29 12:00:32 +01002017 if (frame_addr & 7) {
2018 goto badframe;
2019 }
2020
pbrooka8c33202008-05-07 23:22:46 +00002021 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
2022 goto badframe;
2023
2024 if (do_sigframe_return_v2(env, frame_addr, &frame->uc))
2025 goto badframe;
2026
2027 unlock_user_struct(frame, frame_addr, 0);
2028 return env->regs[0];
2029
2030badframe:
2031 unlock_user_struct(frame, frame_addr, 0);
Riku Voipio66393fb2009-12-04 15:16:32 +02002032 force_sig(TARGET_SIGSEGV /* , current */);
pbrooka8c33202008-05-07 23:22:46 +00002033 return 0;
2034}
2035
Andreas Färber05390242012-02-25 03:37:53 +01002036long do_sigreturn(CPUARMState *env)
pbrooka8c33202008-05-07 23:22:46 +00002037{
2038 if (get_osversion() >= 0x020612) {
2039 return do_sigreturn_v2(env);
2040 } else {
2041 return do_sigreturn_v1(env);
2042 }
2043}
2044
Andreas Färber05390242012-02-25 03:37:53 +01002045static long do_rt_sigreturn_v1(CPUARMState *env)
bellard43fff232003-07-09 19:31:39 +00002046{
bellardf8b0aa22007-11-11 23:03:42 +00002047 abi_ulong frame_addr;
Peter Maydell978fae92013-07-29 12:00:32 +01002048 struct rt_sigframe_v1 *frame = NULL;
bellard43fff232003-07-09 19:31:39 +00002049 sigset_t host_set;
2050
2051 /*
2052 * Since we stacked the signal on a 64-bit boundary,
2053 * then 'sp' should be word aligned here. If it's
2054 * not, then the user is trying to mess with us.
2055 */
bellardf8b0aa22007-11-11 23:03:42 +00002056 frame_addr = env->regs[13];
Peter Maydell978fae92013-07-29 12:00:32 +01002057 if (frame_addr & 7) {
2058 goto badframe;
2059 }
2060
bellardf8b0aa22007-11-11 23:03:42 +00002061 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
2062 goto badframe;
bellard43fff232003-07-09 19:31:39 +00002063
bellardb8076a72005-04-07 22:20:31 +00002064 target_to_host_sigset(&host_set, &frame->uc.tuc_sigmask);
Alex Barcelo1c275922014-03-14 14:36:55 +00002065 do_sigprocmask(SIG_SETMASK, &host_set, NULL);
bellard43fff232003-07-09 19:31:39 +00002066
bellardb8076a72005-04-07 22:20:31 +00002067 if (restore_sigcontext(env, &frame->uc.tuc_mcontext))
bellard43fff232003-07-09 19:31:39 +00002068 goto badframe;
2069
pbrooka745ec62008-05-06 15:36:17 +00002070 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 +00002071 goto badframe;
2072
bellard43fff232003-07-09 19:31:39 +00002073#if 0
2074 /* Send SIGTRAP if we're single-stepping */
2075 if (ptrace_cancel_bpt(current))
2076 send_sig(SIGTRAP, current, 1);
2077#endif
bellardf8b0aa22007-11-11 23:03:42 +00002078 unlock_user_struct(frame, frame_addr, 0);
bellard43fff232003-07-09 19:31:39 +00002079 return env->regs[0];
2080
2081badframe:
bellardf8b0aa22007-11-11 23:03:42 +00002082 unlock_user_struct(frame, frame_addr, 0);
Riku Voipio66393fb2009-12-04 15:16:32 +02002083 force_sig(TARGET_SIGSEGV /* , current */);
bellard43fff232003-07-09 19:31:39 +00002084 return 0;
2085}
2086
Andreas Färber05390242012-02-25 03:37:53 +01002087static long do_rt_sigreturn_v2(CPUARMState *env)
pbrooka745ec62008-05-06 15:36:17 +00002088{
2089 abi_ulong frame_addr;
Peter Maydell978fae92013-07-29 12:00:32 +01002090 struct rt_sigframe_v2 *frame = NULL;
pbrooka745ec62008-05-06 15:36:17 +00002091
2092 /*
2093 * Since we stacked the signal on a 64-bit boundary,
2094 * then 'sp' should be word aligned here. If it's
2095 * not, then the user is trying to mess with us.
2096 */
pbrooka745ec62008-05-06 15:36:17 +00002097 frame_addr = env->regs[13];
Peter Maydell978fae92013-07-29 12:00:32 +01002098 if (frame_addr & 7) {
2099 goto badframe;
2100 }
2101
pbrooka745ec62008-05-06 15:36:17 +00002102 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
2103 goto badframe;
2104
pbrooka8c33202008-05-07 23:22:46 +00002105 if (do_sigframe_return_v2(env, frame_addr, &frame->uc))
2106 goto badframe;
pbrooka745ec62008-05-06 15:36:17 +00002107
pbrooka745ec62008-05-06 15:36:17 +00002108 unlock_user_struct(frame, frame_addr, 0);
2109 return env->regs[0];
2110
2111badframe:
2112 unlock_user_struct(frame, frame_addr, 0);
Riku Voipio66393fb2009-12-04 15:16:32 +02002113 force_sig(TARGET_SIGSEGV /* , current */);
pbrooka745ec62008-05-06 15:36:17 +00002114 return 0;
2115}
2116
Andreas Färber05390242012-02-25 03:37:53 +01002117long do_rt_sigreturn(CPUARMState *env)
pbrooka745ec62008-05-06 15:36:17 +00002118{
2119 if (get_osversion() >= 0x020612) {
2120 return do_rt_sigreturn_v2(env);
2121 } else {
2122 return do_rt_sigreturn_v1(env);
2123 }
2124}
2125
bellard6d5e2162004-09-30 22:04:13 +00002126#elif defined(TARGET_SPARC)
bellard80a9d032005-01-03 23:31:27 +00002127
bellard6d5e2162004-09-30 22:04:13 +00002128#define __SUNOS_MAXWIN 31
2129
2130/* This is what SunOS does, so shall I. */
2131struct target_sigcontext {
blueswir1992f48a2007-10-14 16:27:31 +00002132 abi_ulong sigc_onstack; /* state to restore */
bellard6d5e2162004-09-30 22:04:13 +00002133
blueswir1992f48a2007-10-14 16:27:31 +00002134 abi_ulong sigc_mask; /* sigmask to restore */
2135 abi_ulong sigc_sp; /* stack pointer */
2136 abi_ulong sigc_pc; /* program counter */
2137 abi_ulong sigc_npc; /* next program counter */
2138 abi_ulong sigc_psr; /* for condition codes etc */
2139 abi_ulong sigc_g1; /* User uses these two registers */
2140 abi_ulong sigc_o0; /* within the trampoline code. */
bellard6d5e2162004-09-30 22:04:13 +00002141
2142 /* Now comes information regarding the users window set
2143 * at the time of the signal.
2144 */
blueswir1992f48a2007-10-14 16:27:31 +00002145 abi_ulong sigc_oswins; /* outstanding windows */
bellard6d5e2162004-09-30 22:04:13 +00002146
2147 /* stack ptrs for each regwin buf */
2148 char *sigc_spbuf[__SUNOS_MAXWIN];
2149
2150 /* Windows to restore after signal */
2151 struct {
blueswir1992f48a2007-10-14 16:27:31 +00002152 abi_ulong locals[8];
2153 abi_ulong ins[8];
bellard6d5e2162004-09-30 22:04:13 +00002154 } sigc_wbuf[__SUNOS_MAXWIN];
2155};
2156/* A Sparc stack frame */
2157struct sparc_stackf {
blueswir1992f48a2007-10-14 16:27:31 +00002158 abi_ulong locals[8];
Peter Maydelle321c342011-02-01 15:54:52 +00002159 abi_ulong ins[8];
2160 /* It's simpler to treat fp and callers_pc as elements of ins[]
2161 * since we never need to access them ourselves.
2162 */
bellard6d5e2162004-09-30 22:04:13 +00002163 char *structptr;
blueswir1992f48a2007-10-14 16:27:31 +00002164 abi_ulong xargs[6];
2165 abi_ulong xxargs[1];
bellard6d5e2162004-09-30 22:04:13 +00002166};
2167
2168typedef struct {
2169 struct {
blueswir1992f48a2007-10-14 16:27:31 +00002170 abi_ulong psr;
2171 abi_ulong pc;
2172 abi_ulong npc;
2173 abi_ulong y;
2174 abi_ulong u_regs[16]; /* globals and ins */
bellard6d5e2162004-09-30 22:04:13 +00002175 } si_regs;
2176 int si_mask;
2177} __siginfo_t;
2178
2179typedef struct {
Blue Swirl8954bae2012-07-30 15:29:11 +00002180 abi_ulong si_float_regs[32];
bellard6d5e2162004-09-30 22:04:13 +00002181 unsigned long si_fsr;
2182 unsigned long si_fpqdepth;
2183 struct {
2184 unsigned long *insn_addr;
2185 unsigned long insn;
2186 } si_fpqueue [16];
Anthony Liguoric227f092009-10-01 16:12:16 -05002187} qemu_siginfo_fpu_t;
bellard6d5e2162004-09-30 22:04:13 +00002188
2189
2190struct target_signal_frame {
2191 struct sparc_stackf ss;
2192 __siginfo_t info;
bellardf8b0aa22007-11-11 23:03:42 +00002193 abi_ulong fpu_save;
blueswir1992f48a2007-10-14 16:27:31 +00002194 abi_ulong insns[2] __attribute__ ((aligned (8)));
2195 abi_ulong extramask[TARGET_NSIG_WORDS - 1];
2196 abi_ulong extra_size; /* Should be 0 */
Anthony Liguoric227f092009-10-01 16:12:16 -05002197 qemu_siginfo_fpu_t fpu_state;
bellard6d5e2162004-09-30 22:04:13 +00002198};
2199struct target_rt_signal_frame {
2200 struct sparc_stackf ss;
2201 siginfo_t info;
blueswir1992f48a2007-10-14 16:27:31 +00002202 abi_ulong regs[20];
bellard6d5e2162004-09-30 22:04:13 +00002203 sigset_t mask;
bellardf8b0aa22007-11-11 23:03:42 +00002204 abi_ulong fpu_save;
bellard6d5e2162004-09-30 22:04:13 +00002205 unsigned int insns[2];
2206 stack_t stack;
2207 unsigned int extra_size; /* Should be 0 */
Anthony Liguoric227f092009-10-01 16:12:16 -05002208 qemu_siginfo_fpu_t fpu_state;
bellard6d5e2162004-09-30 22:04:13 +00002209};
2210
bellarde80cfcf2004-12-19 23:18:01 +00002211#define UREG_O0 16
2212#define UREG_O6 22
2213#define UREG_I0 0
2214#define UREG_I1 1
2215#define UREG_I2 2
blueswir15bfb56b2007-10-05 17:01:51 +00002216#define UREG_I3 3
2217#define UREG_I4 4
2218#define UREG_I5 5
bellarde80cfcf2004-12-19 23:18:01 +00002219#define UREG_I6 6
2220#define UREG_I7 7
2221#define UREG_L0 8
bellard6d5e2162004-09-30 22:04:13 +00002222#define UREG_FP UREG_I6
2223#define UREG_SP UREG_O6
2224
pbrook624f7972008-05-31 16:11:38 +00002225static inline abi_ulong get_sigframe(struct target_sigaction *sa,
Andreas Färber05390242012-02-25 03:37:53 +01002226 CPUSPARCState *env,
2227 unsigned long framesize)
bellard6d5e2162004-09-30 22:04:13 +00002228{
bellard459a4012007-11-11 19:45:10 +00002229 abi_ulong sp;
bellard6d5e2162004-09-30 22:04:13 +00002230
2231 sp = env->regwptr[UREG_FP];
bellard6d5e2162004-09-30 22:04:13 +00002232
2233 /* This is the X/Open sanctioned signal stack switching. */
pbrook624f7972008-05-31 16:11:38 +00002234 if (sa->sa_flags & TARGET_SA_ONSTACK) {
thsa04e1342007-09-27 13:57:58 +00002235 if (!on_sig_stack(sp)
2236 && !((target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size) & 7))
2237 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
bellard6d5e2162004-09-30 22:04:13 +00002238 }
bellard459a4012007-11-11 19:45:10 +00002239 return sp - framesize;
bellard6d5e2162004-09-30 22:04:13 +00002240}
2241
2242static int
Andreas Färber05390242012-02-25 03:37:53 +01002243setup___siginfo(__siginfo_t *si, CPUSPARCState *env, abi_ulong mask)
bellard6d5e2162004-09-30 22:04:13 +00002244{
2245 int err = 0, i;
2246
Riku Voipio1d8b5122014-04-23 10:26:05 +03002247 __put_user(env->psr, &si->si_regs.psr);
2248 __put_user(env->pc, &si->si_regs.pc);
2249 __put_user(env->npc, &si->si_regs.npc);
2250 __put_user(env->y, &si->si_regs.y);
bellarda315a142005-01-30 22:59:18 +00002251 for (i=0; i < 8; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002252 __put_user(env->gregs[i], &si->si_regs.u_regs[i]);
bellard6d5e2162004-09-30 22:04:13 +00002253 }
bellarda315a142005-01-30 22:59:18 +00002254 for (i=0; i < 8; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002255 __put_user(env->regwptr[UREG_I0 + i], &si->si_regs.u_regs[i+8]);
bellard6d5e2162004-09-30 22:04:13 +00002256 }
Riku Voipio1d8b5122014-04-23 10:26:05 +03002257 __put_user(mask, &si->si_mask);
bellard6d5e2162004-09-30 22:04:13 +00002258 return err;
2259}
bellarde80cfcf2004-12-19 23:18:01 +00002260
bellard80a9d032005-01-03 23:31:27 +00002261#if 0
bellard6d5e2162004-09-30 22:04:13 +00002262static int
2263setup_sigcontext(struct target_sigcontext *sc, /*struct _fpstate *fpstate,*/
Andreas Färber05390242012-02-25 03:37:53 +01002264 CPUSPARCState *env, unsigned long mask)
bellard6d5e2162004-09-30 22:04:13 +00002265{
2266 int err = 0;
2267
Riku Voipio1d8b5122014-04-23 10:26:05 +03002268 __put_user(mask, &sc->sigc_mask);
2269 __put_user(env->regwptr[UREG_SP], &sc->sigc_sp);
2270 __put_user(env->pc, &sc->sigc_pc);
2271 __put_user(env->npc, &sc->sigc_npc);
2272 __put_user(env->psr, &sc->sigc_psr);
2273 __put_user(env->gregs[1], &sc->sigc_g1);
2274 __put_user(env->regwptr[UREG_O0], &sc->sigc_o0);
bellard6d5e2162004-09-30 22:04:13 +00002275
2276 return err;
2277}
bellard80a9d032005-01-03 23:31:27 +00002278#endif
bellard6d5e2162004-09-30 22:04:13 +00002279#define NF_ALIGNEDSZ (((sizeof(struct target_signal_frame) + 7) & (~7)))
2280
pbrook624f7972008-05-31 16:11:38 +00002281static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01002282 target_sigset_t *set, CPUSPARCState *env)
bellard6d5e2162004-09-30 22:04:13 +00002283{
bellard459a4012007-11-11 19:45:10 +00002284 abi_ulong sf_addr;
bellard6d5e2162004-09-30 22:04:13 +00002285 struct target_signal_frame *sf;
2286 int sigframe_size, err, i;
2287
2288 /* 1. Make sure everything is clean */
2289 //synchronize_user_stack();
2290
2291 sigframe_size = NF_ALIGNEDSZ;
bellard459a4012007-11-11 19:45:10 +00002292 sf_addr = get_sigframe(ka, env, sigframe_size);
bellard6d5e2162004-09-30 22:04:13 +00002293
bellard459a4012007-11-11 19:45:10 +00002294 sf = lock_user(VERIFY_WRITE, sf_addr,
2295 sizeof(struct target_signal_frame), 0);
2296 if (!sf)
2297 goto sigsegv;
2298
bellarde80cfcf2004-12-19 23:18:01 +00002299 //fprintf(stderr, "sf: %x pc %x fp %x sp %x\n", sf, env->pc, env->regwptr[UREG_FP], env->regwptr[UREG_SP]);
bellard6d5e2162004-09-30 22:04:13 +00002300#if 0
2301 if (invalid_frame_pointer(sf, sigframe_size))
2302 goto sigill_and_return;
2303#endif
2304 /* 2. Save the current process state */
2305 err = setup___siginfo(&sf->info, env, set->sig[0]);
Riku Voipio1d8b5122014-04-23 10:26:05 +03002306 __put_user(0, &sf->extra_size);
bellard6d5e2162004-09-30 22:04:13 +00002307
Riku Voipio1d8b5122014-04-23 10:26:05 +03002308 //save_fpu_state(regs, &sf->fpu_state);
2309 //__put_user(&sf->fpu_state, &sf->fpu_save);
bellard6d5e2162004-09-30 22:04:13 +00002310
Riku Voipio1d8b5122014-04-23 10:26:05 +03002311 __put_user(set->sig[0], &sf->info.si_mask);
bellard6d5e2162004-09-30 22:04:13 +00002312 for (i = 0; i < TARGET_NSIG_WORDS - 1; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002313 __put_user(set->sig[i + 1], &sf->extramask[i]);
bellard6d5e2162004-09-30 22:04:13 +00002314 }
2315
bellarda315a142005-01-30 22:59:18 +00002316 for (i = 0; i < 8; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002317 __put_user(env->regwptr[i + UREG_L0], &sf->ss.locals[i]);
bellard6d5e2162004-09-30 22:04:13 +00002318 }
bellarda315a142005-01-30 22:59:18 +00002319 for (i = 0; i < 8; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002320 __put_user(env->regwptr[i + UREG_I0], &sf->ss.ins[i]);
bellard6d5e2162004-09-30 22:04:13 +00002321 }
bellard6d5e2162004-09-30 22:04:13 +00002322 if (err)
2323 goto sigsegv;
2324
2325 /* 3. signal handler back-trampoline and parameters */
bellard459a4012007-11-11 19:45:10 +00002326 env->regwptr[UREG_FP] = sf_addr;
bellard6d5e2162004-09-30 22:04:13 +00002327 env->regwptr[UREG_I0] = sig;
bellard459a4012007-11-11 19:45:10 +00002328 env->regwptr[UREG_I1] = sf_addr +
2329 offsetof(struct target_signal_frame, info);
2330 env->regwptr[UREG_I2] = sf_addr +
2331 offsetof(struct target_signal_frame, info);
bellard6d5e2162004-09-30 22:04:13 +00002332
2333 /* 4. signal handler */
pbrook624f7972008-05-31 16:11:38 +00002334 env->pc = ka->_sa_handler;
bellard6d5e2162004-09-30 22:04:13 +00002335 env->npc = (env->pc + 4);
2336 /* 5. return to kernel instructions */
pbrook624f7972008-05-31 16:11:38 +00002337 if (ka->sa_restorer)
2338 env->regwptr[UREG_I7] = ka->sa_restorer;
bellard6d5e2162004-09-30 22:04:13 +00002339 else {
bellard775b58d2007-11-11 16:22:17 +00002340 uint32_t val32;
bellard459a4012007-11-11 19:45:10 +00002341
2342 env->regwptr[UREG_I7] = sf_addr +
2343 offsetof(struct target_signal_frame, insns) - 2 * 4;
bellard6d5e2162004-09-30 22:04:13 +00002344
2345 /* mov __NR_sigreturn, %g1 */
bellard775b58d2007-11-11 16:22:17 +00002346 val32 = 0x821020d8;
Riku Voipio1d8b5122014-04-23 10:26:05 +03002347 __put_user(val32, &sf->insns[0]);
bellard6d5e2162004-09-30 22:04:13 +00002348
2349 /* t 0x10 */
bellard775b58d2007-11-11 16:22:17 +00002350 val32 = 0x91d02010;
Riku Voipio1d8b5122014-04-23 10:26:05 +03002351 __put_user(val32, &sf->insns[1]);
bellard6d5e2162004-09-30 22:04:13 +00002352 if (err)
2353 goto sigsegv;
2354
2355 /* Flush instruction space. */
2356 //flush_sig_insns(current->mm, (unsigned long) &(sf->insns[0]));
bellard80a9d032005-01-03 23:31:27 +00002357 // tb_flush(env);
bellard6d5e2162004-09-30 22:04:13 +00002358 }
bellard459a4012007-11-11 19:45:10 +00002359 unlock_user(sf, sf_addr, sizeof(struct target_signal_frame));
bellard6d5e2162004-09-30 22:04:13 +00002360 return;
bellard459a4012007-11-11 19:45:10 +00002361#if 0
2362sigill_and_return:
bellard6d5e2162004-09-30 22:04:13 +00002363 force_sig(TARGET_SIGILL);
bellard459a4012007-11-11 19:45:10 +00002364#endif
bellard6d5e2162004-09-30 22:04:13 +00002365sigsegv:
bellarde80cfcf2004-12-19 23:18:01 +00002366 //fprintf(stderr, "force_sig\n");
bellard459a4012007-11-11 19:45:10 +00002367 unlock_user(sf, sf_addr, sizeof(struct target_signal_frame));
bellard6d5e2162004-09-30 22:04:13 +00002368 force_sig(TARGET_SIGSEGV);
2369}
bellard6d5e2162004-09-30 22:04:13 +00002370
pbrook624f7972008-05-31 16:11:38 +00002371static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05002372 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01002373 target_sigset_t *set, CPUSPARCState *env)
bellard6d5e2162004-09-30 22:04:13 +00002374{
2375 fprintf(stderr, "setup_rt_frame: not implemented\n");
2376}
2377
Andreas Färber05390242012-02-25 03:37:53 +01002378long do_sigreturn(CPUSPARCState *env)
bellard6d5e2162004-09-30 22:04:13 +00002379{
bellardf8b0aa22007-11-11 23:03:42 +00002380 abi_ulong sf_addr;
bellard6d5e2162004-09-30 22:04:13 +00002381 struct target_signal_frame *sf;
bellarde80cfcf2004-12-19 23:18:01 +00002382 uint32_t up_psr, pc, npc;
Anthony Liguoric227f092009-10-01 16:12:16 -05002383 target_sigset_t set;
bellarde80cfcf2004-12-19 23:18:01 +00002384 sigset_t host_set;
Riku Voipio1d8b5122014-04-23 10:26:05 +03002385 int err=0, i;
bellard6d5e2162004-09-30 22:04:13 +00002386
bellardf8b0aa22007-11-11 23:03:42 +00002387 sf_addr = env->regwptr[UREG_FP];
2388 if (!lock_user_struct(VERIFY_READ, sf, sf_addr, 1))
2389 goto segv_and_exit;
bellard80a9d032005-01-03 23:31:27 +00002390#if 0
bellarde80cfcf2004-12-19 23:18:01 +00002391 fprintf(stderr, "sigreturn\n");
2392 fprintf(stderr, "sf: %x pc %x fp %x sp %x\n", sf, env->pc, env->regwptr[UREG_FP], env->regwptr[UREG_SP]);
bellard80a9d032005-01-03 23:31:27 +00002393#endif
bellarde80cfcf2004-12-19 23:18:01 +00002394 //cpu_dump_state(env, stderr, fprintf, 0);
bellard6d5e2162004-09-30 22:04:13 +00002395
2396 /* 1. Make sure we are not getting garbage from the user */
bellard6d5e2162004-09-30 22:04:13 +00002397
bellardf8b0aa22007-11-11 23:03:42 +00002398 if (sf_addr & 3)
bellard6d5e2162004-09-30 22:04:13 +00002399 goto segv_and_exit;
2400
Riku Voipio1d8b5122014-04-23 10:26:05 +03002401 __get_user(pc, &sf->info.si_regs.pc);
2402 __get_user(npc, &sf->info.si_regs.npc);
bellard6d5e2162004-09-30 22:04:13 +00002403
bellard6d5e2162004-09-30 22:04:13 +00002404 if ((pc | npc) & 3)
2405 goto segv_and_exit;
2406
2407 /* 2. Restore the state */
Riku Voipio1d8b5122014-04-23 10:26:05 +03002408 __get_user(up_psr, &sf->info.si_regs.psr);
bellarde80cfcf2004-12-19 23:18:01 +00002409
bellard6d5e2162004-09-30 22:04:13 +00002410 /* User can only change condition codes and FPU enabling in %psr. */
bellarda315a142005-01-30 22:59:18 +00002411 env->psr = (up_psr & (PSR_ICC /* | PSR_EF */))
2412 | (env->psr & ~(PSR_ICC /* | PSR_EF */));
2413
2414 env->pc = pc;
2415 env->npc = npc;
Riku Voipio1d8b5122014-04-23 10:26:05 +03002416 __get_user(env->y, &sf->info.si_regs.y);
bellarda315a142005-01-30 22:59:18 +00002417 for (i=0; i < 8; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002418 __get_user(env->gregs[i], &sf->info.si_regs.u_regs[i]);
bellarde80cfcf2004-12-19 23:18:01 +00002419 }
bellarda315a142005-01-30 22:59:18 +00002420 for (i=0; i < 8; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002421 __get_user(env->regwptr[i + UREG_I0], &sf->info.si_regs.u_regs[i+8]);
bellarde80cfcf2004-12-19 23:18:01 +00002422 }
bellard6d5e2162004-09-30 22:04:13 +00002423
Peter Maydell2aec3a22011-06-16 17:37:14 +01002424 /* FIXME: implement FPU save/restore:
2425 * __get_user(fpu_save, &sf->fpu_save);
2426 * if (fpu_save)
2427 * err |= restore_fpu_state(env, fpu_save);
2428 */
bellard6d5e2162004-09-30 22:04:13 +00002429
2430 /* This is pretty much atomic, no amount locking would prevent
2431 * the races which exist anyways.
2432 */
Riku Voipio1d8b5122014-04-23 10:26:05 +03002433 __get_user(set.sig[0], &sf->info.si_mask);
bellarde80cfcf2004-12-19 23:18:01 +00002434 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002435 __get_user(set.sig[i], &sf->extramask[i - 1]);
bellarde80cfcf2004-12-19 23:18:01 +00002436 }
2437
2438 target_to_host_sigset_internal(&host_set, &set);
Alex Barcelo1c275922014-03-14 14:36:55 +00002439 do_sigprocmask(SIG_SETMASK, &host_set, NULL);
bellard6d5e2162004-09-30 22:04:13 +00002440
2441 if (err)
2442 goto segv_and_exit;
bellardf8b0aa22007-11-11 23:03:42 +00002443 unlock_user_struct(sf, sf_addr, 0);
bellard6d5e2162004-09-30 22:04:13 +00002444 return env->regwptr[0];
2445
2446segv_and_exit:
bellardf8b0aa22007-11-11 23:03:42 +00002447 unlock_user_struct(sf, sf_addr, 0);
bellard6d5e2162004-09-30 22:04:13 +00002448 force_sig(TARGET_SIGSEGV);
2449}
2450
Andreas Färber05390242012-02-25 03:37:53 +01002451long do_rt_sigreturn(CPUSPARCState *env)
bellard6d5e2162004-09-30 22:04:13 +00002452{
2453 fprintf(stderr, "do_rt_sigreturn: not implemented\n");
bellardf8b0aa22007-11-11 23:03:42 +00002454 return -TARGET_ENOSYS;
bellard6d5e2162004-09-30 22:04:13 +00002455}
2456
bellard459a4012007-11-11 19:45:10 +00002457#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
blueswir15bfb56b2007-10-05 17:01:51 +00002458#define MC_TSTATE 0
2459#define MC_PC 1
2460#define MC_NPC 2
2461#define MC_Y 3
2462#define MC_G1 4
2463#define MC_G2 5
2464#define MC_G3 6
2465#define MC_G4 7
2466#define MC_G5 8
2467#define MC_G6 9
2468#define MC_G7 10
2469#define MC_O0 11
2470#define MC_O1 12
2471#define MC_O2 13
2472#define MC_O3 14
2473#define MC_O4 15
2474#define MC_O5 16
2475#define MC_O6 17
2476#define MC_O7 18
2477#define MC_NGREG 19
2478
Anthony Liguoric227f092009-10-01 16:12:16 -05002479typedef abi_ulong target_mc_greg_t;
2480typedef target_mc_greg_t target_mc_gregset_t[MC_NGREG];
blueswir15bfb56b2007-10-05 17:01:51 +00002481
2482struct target_mc_fq {
blueswir1992f48a2007-10-14 16:27:31 +00002483 abi_ulong *mcfq_addr;
blueswir15bfb56b2007-10-05 17:01:51 +00002484 uint32_t mcfq_insn;
2485};
2486
2487struct target_mc_fpu {
2488 union {
2489 uint32_t sregs[32];
2490 uint64_t dregs[32];
2491 //uint128_t qregs[16];
2492 } mcfpu_fregs;
blueswir1992f48a2007-10-14 16:27:31 +00002493 abi_ulong mcfpu_fsr;
2494 abi_ulong mcfpu_fprs;
2495 abi_ulong mcfpu_gsr;
blueswir15bfb56b2007-10-05 17:01:51 +00002496 struct target_mc_fq *mcfpu_fq;
2497 unsigned char mcfpu_qcnt;
2498 unsigned char mcfpu_qentsz;
2499 unsigned char mcfpu_enab;
2500};
Anthony Liguoric227f092009-10-01 16:12:16 -05002501typedef struct target_mc_fpu target_mc_fpu_t;
blueswir15bfb56b2007-10-05 17:01:51 +00002502
2503typedef struct {
Anthony Liguoric227f092009-10-01 16:12:16 -05002504 target_mc_gregset_t mc_gregs;
2505 target_mc_greg_t mc_fp;
2506 target_mc_greg_t mc_i7;
2507 target_mc_fpu_t mc_fpregs;
2508} target_mcontext_t;
blueswir15bfb56b2007-10-05 17:01:51 +00002509
2510struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02002511 struct target_ucontext *tuc_link;
2512 abi_ulong tuc_flags;
2513 target_sigset_t tuc_sigmask;
2514 target_mcontext_t tuc_mcontext;
blueswir15bfb56b2007-10-05 17:01:51 +00002515};
2516
2517/* A V9 register window */
2518struct target_reg_window {
blueswir1992f48a2007-10-14 16:27:31 +00002519 abi_ulong locals[8];
2520 abi_ulong ins[8];
blueswir15bfb56b2007-10-05 17:01:51 +00002521};
2522
2523#define TARGET_STACK_BIAS 2047
2524
2525/* {set, get}context() needed for 64-bit SparcLinux userland. */
2526void sparc64_set_context(CPUSPARCState *env)
2527{
bellard459a4012007-11-11 19:45:10 +00002528 abi_ulong ucp_addr;
2529 struct target_ucontext *ucp;
Anthony Liguoric227f092009-10-01 16:12:16 -05002530 target_mc_gregset_t *grp;
blueswir1992f48a2007-10-14 16:27:31 +00002531 abi_ulong pc, npc, tstate;
bellard459a4012007-11-11 19:45:10 +00002532 abi_ulong fp, i7, w_addr;
blueswir15bfb56b2007-10-05 17:01:51 +00002533 unsigned int i;
blueswir15bfb56b2007-10-05 17:01:51 +00002534
bellard459a4012007-11-11 19:45:10 +00002535 ucp_addr = env->regwptr[UREG_I0];
2536 if (!lock_user_struct(VERIFY_READ, ucp, ucp_addr, 1))
2537 goto do_sigsegv;
Aurelien Jarno60e99242010-03-29 02:12:51 +02002538 grp = &ucp->tuc_mcontext.mc_gregs;
Riku Voipio1d8b5122014-04-23 10:26:05 +03002539 __get_user(pc, &((*grp)[MC_PC]));
2540 __get_user(npc, &((*grp)[MC_NPC]));
Riku Voipiobe3ef5c2014-04-23 14:02:36 +03002541 if ((pc | npc) & 3)
blueswir15bfb56b2007-10-05 17:01:51 +00002542 goto do_sigsegv;
2543 if (env->regwptr[UREG_I1]) {
Anthony Liguoric227f092009-10-01 16:12:16 -05002544 target_sigset_t target_set;
blueswir15bfb56b2007-10-05 17:01:51 +00002545 sigset_t set;
2546
2547 if (TARGET_NSIG_WORDS == 1) {
Riku Voipiobe3ef5c2014-04-23 14:02:36 +03002548 __get_user(target_set.sig[0], &ucp->tuc_sigmask.sig[0]);
blueswir15bfb56b2007-10-05 17:01:51 +00002549 } else {
bellard459a4012007-11-11 19:45:10 +00002550 abi_ulong *src, *dst;
Aurelien Jarno60e99242010-03-29 02:12:51 +02002551 src = ucp->tuc_sigmask.sig;
bellard459a4012007-11-11 19:45:10 +00002552 dst = target_set.sig;
Stefan Weil0d9e61c2013-12-07 14:48:08 +01002553 for (i = 0; i < TARGET_NSIG_WORDS; i++, dst++, src++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002554 __get_user(*dst, src);
Stefan Weil0d9e61c2013-12-07 14:48:08 +01002555 }
blueswir15bfb56b2007-10-05 17:01:51 +00002556 }
2557 target_to_host_sigset_internal(&set, &target_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00002558 do_sigprocmask(SIG_SETMASK, &set, NULL);
blueswir15bfb56b2007-10-05 17:01:51 +00002559 }
2560 env->pc = pc;
2561 env->npc = npc;
Riku Voipio1d8b5122014-04-23 10:26:05 +03002562 __get_user(env->y, &((*grp)[MC_Y]));
2563 __get_user(tstate, &((*grp)[MC_TSTATE]));
blueswir15bfb56b2007-10-05 17:01:51 +00002564 env->asi = (tstate >> 24) & 0xff;
Blue Swirl5a834bb2010-05-09 20:19:04 +00002565 cpu_put_ccr(env, tstate >> 32);
2566 cpu_put_cwp64(env, tstate & 0x1f);
Riku Voipio1d8b5122014-04-23 10:26:05 +03002567 __get_user(env->gregs[1], (&(*grp)[MC_G1]));
2568 __get_user(env->gregs[2], (&(*grp)[MC_G2]));
2569 __get_user(env->gregs[3], (&(*grp)[MC_G3]));
2570 __get_user(env->gregs[4], (&(*grp)[MC_G4]));
2571 __get_user(env->gregs[5], (&(*grp)[MC_G5]));
2572 __get_user(env->gregs[6], (&(*grp)[MC_G6]));
2573 __get_user(env->gregs[7], (&(*grp)[MC_G7]));
2574 __get_user(env->regwptr[UREG_I0], (&(*grp)[MC_O0]));
2575 __get_user(env->regwptr[UREG_I1], (&(*grp)[MC_O1]));
2576 __get_user(env->regwptr[UREG_I2], (&(*grp)[MC_O2]));
2577 __get_user(env->regwptr[UREG_I3], (&(*grp)[MC_O3]));
2578 __get_user(env->regwptr[UREG_I4], (&(*grp)[MC_O4]));
2579 __get_user(env->regwptr[UREG_I5], (&(*grp)[MC_O5]));
2580 __get_user(env->regwptr[UREG_I6], (&(*grp)[MC_O6]));
2581 __get_user(env->regwptr[UREG_I7], (&(*grp)[MC_O7]));
blueswir15bfb56b2007-10-05 17:01:51 +00002582
Riku Voipio1d8b5122014-04-23 10:26:05 +03002583 __get_user(fp, &(ucp->tuc_mcontext.mc_fp));
2584 __get_user(i7, &(ucp->tuc_mcontext.mc_i7));
blueswir15bfb56b2007-10-05 17:01:51 +00002585
bellard459a4012007-11-11 19:45:10 +00002586 w_addr = TARGET_STACK_BIAS+env->regwptr[UREG_I6];
2587 if (put_user(fp, w_addr + offsetof(struct target_reg_window, ins[6]),
2588 abi_ulong) != 0)
2589 goto do_sigsegv;
2590 if (put_user(i7, w_addr + offsetof(struct target_reg_window, ins[7]),
2591 abi_ulong) != 0)
2592 goto do_sigsegv;
Peter Maydellc7b016b2011-06-16 17:37:15 +01002593 /* FIXME this does not match how the kernel handles the FPU in
2594 * its sparc64_set_context implementation. In particular the FPU
2595 * is only restored if fenab is non-zero in:
2596 * __get_user(fenab, &(ucp->tuc_mcontext.mc_fpregs.mcfpu_enab));
2597 */
Riku Voipiobe3ef5c2014-04-23 14:02:36 +03002598 __get_user(env->fprs, &(ucp->tuc_mcontext.mc_fpregs.mcfpu_fprs));
bellard459a4012007-11-11 19:45:10 +00002599 {
Richard Henderson30038fd2011-10-17 10:42:49 -07002600 uint32_t *src = ucp->tuc_mcontext.mc_fpregs.mcfpu_fregs.sregs;
2601 for (i = 0; i < 64; i++, src++) {
2602 if (i & 1) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002603 __get_user(env->fpr[i/2].l.lower, src);
Richard Henderson30038fd2011-10-17 10:42:49 -07002604 } else {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002605 __get_user(env->fpr[i/2].l.upper, src);
Richard Henderson30038fd2011-10-17 10:42:49 -07002606 }
2607 }
bellard459a4012007-11-11 19:45:10 +00002608 }
Riku Voipio1d8b5122014-04-23 10:26:05 +03002609 __get_user(env->fsr,
2610 &(ucp->tuc_mcontext.mc_fpregs.mcfpu_fsr));
2611 __get_user(env->gsr,
2612 &(ucp->tuc_mcontext.mc_fpregs.mcfpu_gsr));
bellard459a4012007-11-11 19:45:10 +00002613 unlock_user_struct(ucp, ucp_addr, 0);
blueswir15bfb56b2007-10-05 17:01:51 +00002614 return;
2615 do_sigsegv:
bellard459a4012007-11-11 19:45:10 +00002616 unlock_user_struct(ucp, ucp_addr, 0);
Riku Voipio66393fb2009-12-04 15:16:32 +02002617 force_sig(TARGET_SIGSEGV);
blueswir15bfb56b2007-10-05 17:01:51 +00002618}
2619
2620void sparc64_get_context(CPUSPARCState *env)
2621{
bellard459a4012007-11-11 19:45:10 +00002622 abi_ulong ucp_addr;
2623 struct target_ucontext *ucp;
Anthony Liguoric227f092009-10-01 16:12:16 -05002624 target_mc_gregset_t *grp;
2625 target_mcontext_t *mcp;
bellard459a4012007-11-11 19:45:10 +00002626 abi_ulong fp, i7, w_addr;
blueswir15bfb56b2007-10-05 17:01:51 +00002627 int err;
2628 unsigned int i;
Anthony Liguoric227f092009-10-01 16:12:16 -05002629 target_sigset_t target_set;
blueswir15bfb56b2007-10-05 17:01:51 +00002630 sigset_t set;
2631
bellard459a4012007-11-11 19:45:10 +00002632 ucp_addr = env->regwptr[UREG_I0];
2633 if (!lock_user_struct(VERIFY_WRITE, ucp, ucp_addr, 0))
2634 goto do_sigsegv;
2635
Aurelien Jarno60e99242010-03-29 02:12:51 +02002636 mcp = &ucp->tuc_mcontext;
blueswir15bfb56b2007-10-05 17:01:51 +00002637 grp = &mcp->mc_gregs;
2638
2639 /* Skip over the trap instruction, first. */
2640 env->pc = env->npc;
2641 env->npc += 4;
2642
2643 err = 0;
2644
Alex Barcelo1c275922014-03-14 14:36:55 +00002645 do_sigprocmask(0, NULL, &set);
blueswir15bfb56b2007-10-05 17:01:51 +00002646 host_to_target_sigset_internal(&target_set, &set);
bellard459a4012007-11-11 19:45:10 +00002647 if (TARGET_NSIG_WORDS == 1) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002648 __put_user(target_set.sig[0],
2649 (abi_ulong *)&ucp->tuc_sigmask);
bellard459a4012007-11-11 19:45:10 +00002650 } else {
2651 abi_ulong *src, *dst;
2652 src = target_set.sig;
Aurelien Jarno60e99242010-03-29 02:12:51 +02002653 dst = ucp->tuc_sigmask.sig;
Stefan Weil0d9e61c2013-12-07 14:48:08 +01002654 for (i = 0; i < TARGET_NSIG_WORDS; i++, dst++, src++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002655 __put_user(*src, dst);
Stefan Weil0d9e61c2013-12-07 14:48:08 +01002656 }
blueswir15bfb56b2007-10-05 17:01:51 +00002657 if (err)
2658 goto do_sigsegv;
2659 }
2660
bellard459a4012007-11-11 19:45:10 +00002661 /* XXX: tstate must be saved properly */
Riku Voipio1d8b5122014-04-23 10:26:05 +03002662 // __put_user(env->tstate, &((*grp)[MC_TSTATE]));
2663 __put_user(env->pc, &((*grp)[MC_PC]));
2664 __put_user(env->npc, &((*grp)[MC_NPC]));
2665 __put_user(env->y, &((*grp)[MC_Y]));
2666 __put_user(env->gregs[1], &((*grp)[MC_G1]));
2667 __put_user(env->gregs[2], &((*grp)[MC_G2]));
2668 __put_user(env->gregs[3], &((*grp)[MC_G3]));
2669 __put_user(env->gregs[4], &((*grp)[MC_G4]));
2670 __put_user(env->gregs[5], &((*grp)[MC_G5]));
2671 __put_user(env->gregs[6], &((*grp)[MC_G6]));
2672 __put_user(env->gregs[7], &((*grp)[MC_G7]));
2673 __put_user(env->regwptr[UREG_I0], &((*grp)[MC_O0]));
2674 __put_user(env->regwptr[UREG_I1], &((*grp)[MC_O1]));
2675 __put_user(env->regwptr[UREG_I2], &((*grp)[MC_O2]));
2676 __put_user(env->regwptr[UREG_I3], &((*grp)[MC_O3]));
2677 __put_user(env->regwptr[UREG_I4], &((*grp)[MC_O4]));
2678 __put_user(env->regwptr[UREG_I5], &((*grp)[MC_O5]));
2679 __put_user(env->regwptr[UREG_I6], &((*grp)[MC_O6]));
2680 __put_user(env->regwptr[UREG_I7], &((*grp)[MC_O7]));
blueswir15bfb56b2007-10-05 17:01:51 +00002681
bellard459a4012007-11-11 19:45:10 +00002682 w_addr = TARGET_STACK_BIAS+env->regwptr[UREG_I6];
2683 fp = i7 = 0;
2684 if (get_user(fp, w_addr + offsetof(struct target_reg_window, ins[6]),
2685 abi_ulong) != 0)
2686 goto do_sigsegv;
2687 if (get_user(i7, w_addr + offsetof(struct target_reg_window, ins[7]),
2688 abi_ulong) != 0)
2689 goto do_sigsegv;
Riku Voipio1d8b5122014-04-23 10:26:05 +03002690 __put_user(fp, &(mcp->mc_fp));
2691 __put_user(i7, &(mcp->mc_i7));
blueswir15bfb56b2007-10-05 17:01:51 +00002692
bellard459a4012007-11-11 19:45:10 +00002693 {
Richard Henderson30038fd2011-10-17 10:42:49 -07002694 uint32_t *dst = ucp->tuc_mcontext.mc_fpregs.mcfpu_fregs.sregs;
2695 for (i = 0; i < 64; i++, dst++) {
2696 if (i & 1) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002697 __put_user(env->fpr[i/2].l.lower, dst);
Richard Henderson30038fd2011-10-17 10:42:49 -07002698 } else {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002699 __put_user(env->fpr[i/2].l.upper, dst);
Richard Henderson30038fd2011-10-17 10:42:49 -07002700 }
2701 }
bellard459a4012007-11-11 19:45:10 +00002702 }
Riku Voipio1d8b5122014-04-23 10:26:05 +03002703 __put_user(env->fsr, &(mcp->mc_fpregs.mcfpu_fsr));
2704 __put_user(env->gsr, &(mcp->mc_fpregs.mcfpu_gsr));
2705 __put_user(env->fprs, &(mcp->mc_fpregs.mcfpu_fprs));
blueswir15bfb56b2007-10-05 17:01:51 +00002706
2707 if (err)
2708 goto do_sigsegv;
bellard459a4012007-11-11 19:45:10 +00002709 unlock_user_struct(ucp, ucp_addr, 1);
blueswir15bfb56b2007-10-05 17:01:51 +00002710 return;
2711 do_sigsegv:
bellard459a4012007-11-11 19:45:10 +00002712 unlock_user_struct(ucp, ucp_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02002713 force_sig(TARGET_SIGSEGV);
blueswir15bfb56b2007-10-05 17:01:51 +00002714}
2715#endif
Richard Hendersonff970902013-02-10 10:30:42 -08002716#elif defined(TARGET_MIPS) || defined(TARGET_MIPS64)
bellard106ec872006-06-27 21:08:10 +00002717
Richard Hendersonff970902013-02-10 10:30:42 -08002718# if defined(TARGET_ABI_MIPSO32)
bellard106ec872006-06-27 21:08:10 +00002719struct target_sigcontext {
2720 uint32_t sc_regmask; /* Unused */
2721 uint32_t sc_status;
2722 uint64_t sc_pc;
2723 uint64_t sc_regs[32];
2724 uint64_t sc_fpregs[32];
2725 uint32_t sc_ownedfp; /* Unused */
2726 uint32_t sc_fpc_csr;
2727 uint32_t sc_fpc_eir; /* Unused */
2728 uint32_t sc_used_math;
2729 uint32_t sc_dsp; /* dsp status, was sc_ssflags */
Paul Brook94c54952009-07-09 18:40:15 +01002730 uint32_t pad0;
bellard106ec872006-06-27 21:08:10 +00002731 uint64_t sc_mdhi;
2732 uint64_t sc_mdlo;
2733 target_ulong sc_hi1; /* Was sc_cause */
2734 target_ulong sc_lo1; /* Was sc_badvaddr */
2735 target_ulong sc_hi2; /* Was sc_sigset[4] */
2736 target_ulong sc_lo2;
2737 target_ulong sc_hi3;
2738 target_ulong sc_lo3;
2739};
Richard Hendersonff970902013-02-10 10:30:42 -08002740# else /* N32 || N64 */
2741struct target_sigcontext {
2742 uint64_t sc_regs[32];
2743 uint64_t sc_fpregs[32];
2744 uint64_t sc_mdhi;
2745 uint64_t sc_hi1;
2746 uint64_t sc_hi2;
2747 uint64_t sc_hi3;
2748 uint64_t sc_mdlo;
2749 uint64_t sc_lo1;
2750 uint64_t sc_lo2;
2751 uint64_t sc_lo3;
2752 uint64_t sc_pc;
2753 uint32_t sc_fpc_csr;
2754 uint32_t sc_used_math;
2755 uint32_t sc_dsp;
2756 uint32_t sc_reserved;
2757};
2758# endif /* O32 */
bellard106ec872006-06-27 21:08:10 +00002759
2760struct sigframe {
2761 uint32_t sf_ass[4]; /* argument save space for o32 */
2762 uint32_t sf_code[2]; /* signal trampoline */
2763 struct target_sigcontext sf_sc;
Anthony Liguoric227f092009-10-01 16:12:16 -05002764 target_sigset_t sf_mask;
bellard106ec872006-06-27 21:08:10 +00002765};
2766
pbrook0b1bcb02009-04-21 01:41:10 +00002767struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02002768 target_ulong tuc_flags;
2769 target_ulong tuc_link;
2770 target_stack_t tuc_stack;
Paul Brook94c54952009-07-09 18:40:15 +01002771 target_ulong pad0;
Aurelien Jarno60e99242010-03-29 02:12:51 +02002772 struct target_sigcontext tuc_mcontext;
2773 target_sigset_t tuc_sigmask;
pbrook0b1bcb02009-04-21 01:41:10 +00002774};
2775
2776struct target_rt_sigframe {
2777 uint32_t rs_ass[4]; /* argument save space for o32 */
2778 uint32_t rs_code[2]; /* signal trampoline */
2779 struct target_siginfo rs_info;
2780 struct target_ucontext rs_uc;
2781};
2782
bellard106ec872006-06-27 21:08:10 +00002783/* Install trampoline to jump back from signal handler */
2784static inline int install_sigtramp(unsigned int *tramp, unsigned int syscall)
2785{
Richard Henderson084d0492013-02-10 10:30:44 -08002786 int err = 0;
bellard106ec872006-06-27 21:08:10 +00002787
2788 /*
Richard Henderson084d0492013-02-10 10:30:44 -08002789 * Set up the return code ...
2790 *
2791 * li v0, __NR__foo_sigreturn
2792 * syscall
2793 */
bellard106ec872006-06-27 21:08:10 +00002794
Riku Voipio1d8b5122014-04-23 10:26:05 +03002795 __put_user(0x24020000 + syscall, tramp + 0);
2796 __put_user(0x0000000c , tramp + 1);
bellard106ec872006-06-27 21:08:10 +00002797 return err;
2798}
2799
Riku Voipio41ecc722014-04-23 11:01:00 +03002800static inline void setup_sigcontext(CPUMIPSState *regs,
2801 struct target_sigcontext *sc)
bellard106ec872006-06-27 21:08:10 +00002802{
Richard Henderson084d0492013-02-10 10:30:44 -08002803 int i;
bellard106ec872006-06-27 21:08:10 +00002804
Riku Voipio1d8b5122014-04-23 10:26:05 +03002805 __put_user(exception_resume_pc(regs), &sc->sc_pc);
Kwok Cheung Yeung1239b472013-05-17 14:51:21 -07002806 regs->hflags &= ~MIPS_HFLAG_BMASK;
bellard106ec872006-06-27 21:08:10 +00002807
Richard Henderson084d0492013-02-10 10:30:44 -08002808 __put_user(0, &sc->sc_regs[0]);
2809 for (i = 1; i < 32; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002810 __put_user(regs->active_tc.gpr[i], &sc->sc_regs[i]);
Richard Henderson084d0492013-02-10 10:30:44 -08002811 }
bellard106ec872006-06-27 21:08:10 +00002812
Riku Voipio1d8b5122014-04-23 10:26:05 +03002813 __put_user(regs->active_tc.HI[0], &sc->sc_mdhi);
2814 __put_user(regs->active_tc.LO[0], &sc->sc_mdlo);
bellard106ec872006-06-27 21:08:10 +00002815
Richard Henderson084d0492013-02-10 10:30:44 -08002816 /* Rather than checking for dsp existence, always copy. The storage
2817 would just be garbage otherwise. */
Riku Voipio1d8b5122014-04-23 10:26:05 +03002818 __put_user(regs->active_tc.HI[1], &sc->sc_hi1);
2819 __put_user(regs->active_tc.HI[2], &sc->sc_hi2);
2820 __put_user(regs->active_tc.HI[3], &sc->sc_hi3);
2821 __put_user(regs->active_tc.LO[1], &sc->sc_lo1);
2822 __put_user(regs->active_tc.LO[2], &sc->sc_lo2);
2823 __put_user(regs->active_tc.LO[3], &sc->sc_lo3);
Richard Henderson084d0492013-02-10 10:30:44 -08002824 {
2825 uint32_t dsp = cpu_rddsp(0x3ff, regs);
Riku Voipio1d8b5122014-04-23 10:26:05 +03002826 __put_user(dsp, &sc->sc_dsp);
bellard106ec872006-06-27 21:08:10 +00002827 }
Richard Henderson084d0492013-02-10 10:30:44 -08002828
Riku Voipio1d8b5122014-04-23 10:26:05 +03002829 __put_user(1, &sc->sc_used_math);
Richard Henderson084d0492013-02-10 10:30:44 -08002830
2831 for (i = 0; i < 32; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002832 __put_user(regs->active_fpu.fpr[i].d, &sc->sc_fpregs[i]);
bellard106ec872006-06-27 21:08:10 +00002833 }
bellard106ec872006-06-27 21:08:10 +00002834}
2835
Riku Voipio016d2e12014-04-23 11:19:48 +03002836static inline void
Andreas Färber05390242012-02-25 03:37:53 +01002837restore_sigcontext(CPUMIPSState *regs, struct target_sigcontext *sc)
bellard106ec872006-06-27 21:08:10 +00002838{
Richard Henderson084d0492013-02-10 10:30:44 -08002839 int i;
bellard106ec872006-06-27 21:08:10 +00002840
Riku Voipio1d8b5122014-04-23 10:26:05 +03002841 __get_user(regs->CP0_EPC, &sc->sc_pc);
bellard106ec872006-06-27 21:08:10 +00002842
Riku Voipio1d8b5122014-04-23 10:26:05 +03002843 __get_user(regs->active_tc.HI[0], &sc->sc_mdhi);
2844 __get_user(regs->active_tc.LO[0], &sc->sc_mdlo);
bellard106ec872006-06-27 21:08:10 +00002845
Richard Henderson084d0492013-02-10 10:30:44 -08002846 for (i = 1; i < 32; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002847 __get_user(regs->active_tc.gpr[i], &sc->sc_regs[i]);
bellard106ec872006-06-27 21:08:10 +00002848 }
2849
Riku Voipio1d8b5122014-04-23 10:26:05 +03002850 __get_user(regs->active_tc.HI[1], &sc->sc_hi1);
2851 __get_user(regs->active_tc.HI[2], &sc->sc_hi2);
2852 __get_user(regs->active_tc.HI[3], &sc->sc_hi3);
2853 __get_user(regs->active_tc.LO[1], &sc->sc_lo1);
2854 __get_user(regs->active_tc.LO[2], &sc->sc_lo2);
2855 __get_user(regs->active_tc.LO[3], &sc->sc_lo3);
Richard Henderson084d0492013-02-10 10:30:44 -08002856 {
2857 uint32_t dsp;
Riku Voipio1d8b5122014-04-23 10:26:05 +03002858 __get_user(dsp, &sc->sc_dsp);
Richard Henderson084d0492013-02-10 10:30:44 -08002859 cpu_wrdsp(dsp, 0x3ff, regs);
2860 }
2861
2862 for (i = 0; i < 32; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002863 __get_user(regs->active_fpu.fpr[i].d, &sc->sc_fpregs[i]);
Richard Henderson084d0492013-02-10 10:30:44 -08002864 }
bellard106ec872006-06-27 21:08:10 +00002865}
Richard Hendersonff970902013-02-10 10:30:42 -08002866
bellard106ec872006-06-27 21:08:10 +00002867/*
2868 * Determine which stack to use..
2869 */
bellard579a97f2007-11-11 14:26:47 +00002870static inline abi_ulong
Andreas Färber05390242012-02-25 03:37:53 +01002871get_sigframe(struct target_sigaction *ka, CPUMIPSState *regs, size_t frame_size)
bellard106ec872006-06-27 21:08:10 +00002872{
2873 unsigned long sp;
2874
2875 /* Default to using normal stack */
thsb5dc7732008-06-27 10:02:35 +00002876 sp = regs->active_tc.gpr[29];
bellard106ec872006-06-27 21:08:10 +00002877
2878 /*
Stefan Weil93148aa2012-02-26 18:46:12 +01002879 * FPU emulator may have its own trampoline active just
bellard106ec872006-06-27 21:08:10 +00002880 * above the user stack, 16-bytes before the next lowest
2881 * 16 byte boundary. Try to avoid trashing it.
2882 */
2883 sp -= 32;
2884
bellard106ec872006-06-27 21:08:10 +00002885 /* This is the X/Open sanctioned signal stack switching. */
pbrook624f7972008-05-31 16:11:38 +00002886 if ((ka->sa_flags & TARGET_SA_ONSTACK) && (sas_ss_flags (sp) == 0)) {
thsa04e1342007-09-27 13:57:58 +00002887 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
2888 }
bellard106ec872006-06-27 21:08:10 +00002889
bellard579a97f2007-11-11 14:26:47 +00002890 return (sp - frame_size) & ~7;
bellard106ec872006-06-27 21:08:10 +00002891}
2892
Kwok Cheung Yeungea3164a2013-05-17 14:51:20 -07002893static void mips_set_hflags_isa_mode_from_pc(CPUMIPSState *env)
2894{
2895 if (env->insn_flags & (ASE_MIPS16 | ASE_MICROMIPS)) {
2896 env->hflags &= ~MIPS_HFLAG_M16;
2897 env->hflags |= (env->active_tc.PC & 1) << MIPS_HFLAG_M16_SHIFT;
2898 env->active_tc.PC &= ~(target_ulong) 1;
2899 }
2900}
2901
Richard Hendersonff970902013-02-10 10:30:42 -08002902# if defined(TARGET_ABI_MIPSO32)
bellard579a97f2007-11-11 14:26:47 +00002903/* compare linux/arch/mips/kernel/signal.c:setup_frame() */
pbrook624f7972008-05-31 16:11:38 +00002904static void setup_frame(int sig, struct target_sigaction * ka,
Andreas Färber05390242012-02-25 03:37:53 +01002905 target_sigset_t *set, CPUMIPSState *regs)
bellard106ec872006-06-27 21:08:10 +00002906{
2907 struct sigframe *frame;
bellard579a97f2007-11-11 14:26:47 +00002908 abi_ulong frame_addr;
bellard106ec872006-06-27 21:08:10 +00002909 int i;
2910
bellard579a97f2007-11-11 14:26:47 +00002911 frame_addr = get_sigframe(ka, regs, sizeof(*frame));
2912 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
bellard106ec872006-06-27 21:08:10 +00002913 goto give_sigsegv;
2914
2915 install_sigtramp(frame->sf_code, TARGET_NR_sigreturn);
2916
Riku Voipio41ecc722014-04-23 11:01:00 +03002917 setup_sigcontext(regs, &frame->sf_sc);
bellard106ec872006-06-27 21:08:10 +00002918
2919 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
Riku Voipio0188fad2014-04-23 13:34:15 +03002920 __put_user(set->sig[i], &frame->sf_mask.sig[i]);
bellard106ec872006-06-27 21:08:10 +00002921 }
2922
2923 /*
2924 * Arguments to signal handler:
2925 *
2926 * a0 = signal number
2927 * a1 = 0 (should be cause)
2928 * a2 = pointer to struct sigcontext
2929 *
2930 * $25 and PC point to the signal handler, $29 points to the
2931 * struct sigframe.
2932 */
thsb5dc7732008-06-27 10:02:35 +00002933 regs->active_tc.gpr[ 4] = sig;
2934 regs->active_tc.gpr[ 5] = 0;
2935 regs->active_tc.gpr[ 6] = frame_addr + offsetof(struct sigframe, sf_sc);
2936 regs->active_tc.gpr[29] = frame_addr;
2937 regs->active_tc.gpr[31] = frame_addr + offsetof(struct sigframe, sf_code);
bellard106ec872006-06-27 21:08:10 +00002938 /* The original kernel code sets CP0_EPC to the handler
2939 * since it returns to userland using eret
2940 * we cannot do this here, and we must set PC directly */
thsb5dc7732008-06-27 10:02:35 +00002941 regs->active_tc.PC = regs->active_tc.gpr[25] = ka->_sa_handler;
Kwok Cheung Yeungea3164a2013-05-17 14:51:20 -07002942 mips_set_hflags_isa_mode_from_pc(regs);
bellard579a97f2007-11-11 14:26:47 +00002943 unlock_user_struct(frame, frame_addr, 1);
bellard106ec872006-06-27 21:08:10 +00002944 return;
2945
2946give_sigsegv:
2947 force_sig(TARGET_SIGSEGV/*, current*/);
bellard106ec872006-06-27 21:08:10 +00002948}
2949
Andreas Färber05390242012-02-25 03:37:53 +01002950long do_sigreturn(CPUMIPSState *regs)
bellard106ec872006-06-27 21:08:10 +00002951{
ths388bb212007-05-13 13:58:00 +00002952 struct sigframe *frame;
bellard579a97f2007-11-11 14:26:47 +00002953 abi_ulong frame_addr;
ths388bb212007-05-13 13:58:00 +00002954 sigset_t blocked;
Anthony Liguoric227f092009-10-01 16:12:16 -05002955 target_sigset_t target_set;
ths388bb212007-05-13 13:58:00 +00002956 int i;
bellard106ec872006-06-27 21:08:10 +00002957
2958#if defined(DEBUG_SIGNAL)
ths388bb212007-05-13 13:58:00 +00002959 fprintf(stderr, "do_sigreturn\n");
bellard106ec872006-06-27 21:08:10 +00002960#endif
thsb5dc7732008-06-27 10:02:35 +00002961 frame_addr = regs->active_tc.gpr[29];
bellard579a97f2007-11-11 14:26:47 +00002962 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
bellard106ec872006-06-27 21:08:10 +00002963 goto badframe;
2964
ths388bb212007-05-13 13:58:00 +00002965 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
Riku Voipiof5f601a2014-04-23 13:00:17 +03002966 __get_user(target_set.sig[i], &frame->sf_mask.sig[i]);
ths388bb212007-05-13 13:58:00 +00002967 }
bellard106ec872006-06-27 21:08:10 +00002968
ths388bb212007-05-13 13:58:00 +00002969 target_to_host_sigset_internal(&blocked, &target_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00002970 do_sigprocmask(SIG_SETMASK, &blocked, NULL);
bellard106ec872006-06-27 21:08:10 +00002971
Riku Voipio016d2e12014-04-23 11:19:48 +03002972 restore_sigcontext(regs, &frame->sf_sc);
bellard106ec872006-06-27 21:08:10 +00002973
2974#if 0
ths388bb212007-05-13 13:58:00 +00002975 /*
2976 * Don't let your children do this ...
2977 */
2978 __asm__ __volatile__(
bellard106ec872006-06-27 21:08:10 +00002979 "move\t$29, %0\n\t"
2980 "j\tsyscall_exit"
2981 :/* no outputs */
2982 :"r" (&regs));
ths388bb212007-05-13 13:58:00 +00002983 /* Unreached */
bellard106ec872006-06-27 21:08:10 +00002984#endif
ths3b46e622007-09-17 08:09:54 +00002985
thsb5dc7732008-06-27 10:02:35 +00002986 regs->active_tc.PC = regs->CP0_EPC;
Kwok Cheung Yeungea3164a2013-05-17 14:51:20 -07002987 mips_set_hflags_isa_mode_from_pc(regs);
ths388bb212007-05-13 13:58:00 +00002988 /* I am not sure this is right, but it seems to work
bellard106ec872006-06-27 21:08:10 +00002989 * maybe a problem with nested signals ? */
2990 regs->CP0_EPC = 0;
pbrook0b1bcb02009-04-21 01:41:10 +00002991 return -TARGET_QEMU_ESIGRETURN;
bellard106ec872006-06-27 21:08:10 +00002992
2993badframe:
ths388bb212007-05-13 13:58:00 +00002994 force_sig(TARGET_SIGSEGV/*, current*/);
2995 return 0;
bellard106ec872006-06-27 21:08:10 +00002996}
Richard Hendersonff970902013-02-10 10:30:42 -08002997# endif /* O32 */
bellard106ec872006-06-27 21:08:10 +00002998
pbrook624f7972008-05-31 16:11:38 +00002999static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05003000 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01003001 target_sigset_t *set, CPUMIPSState *env)
bellard106ec872006-06-27 21:08:10 +00003002{
pbrook0b1bcb02009-04-21 01:41:10 +00003003 struct target_rt_sigframe *frame;
3004 abi_ulong frame_addr;
3005 int i;
3006
3007 frame_addr = get_sigframe(ka, env, sizeof(*frame));
3008 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
3009 goto give_sigsegv;
3010
3011 install_sigtramp(frame->rs_code, TARGET_NR_rt_sigreturn);
3012
3013 copy_siginfo_to_user(&frame->rs_info, info);
3014
Aurelien Jarno60e99242010-03-29 02:12:51 +02003015 __put_user(0, &frame->rs_uc.tuc_flags);
3016 __put_user(0, &frame->rs_uc.tuc_link);
3017 __put_user(target_sigaltstack_used.ss_sp, &frame->rs_uc.tuc_stack.ss_sp);
3018 __put_user(target_sigaltstack_used.ss_size, &frame->rs_uc.tuc_stack.ss_size);
pbrook0b1bcb02009-04-21 01:41:10 +00003019 __put_user(sas_ss_flags(get_sp_from_cpustate(env)),
Aurelien Jarno60e99242010-03-29 02:12:51 +02003020 &frame->rs_uc.tuc_stack.ss_flags);
pbrook0b1bcb02009-04-21 01:41:10 +00003021
Aurelien Jarno60e99242010-03-29 02:12:51 +02003022 setup_sigcontext(env, &frame->rs_uc.tuc_mcontext);
pbrook0b1bcb02009-04-21 01:41:10 +00003023
3024 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
Aurelien Jarno60e99242010-03-29 02:12:51 +02003025 __put_user(set->sig[i], &frame->rs_uc.tuc_sigmask.sig[i]);
pbrook0b1bcb02009-04-21 01:41:10 +00003026 }
3027
3028 /*
3029 * Arguments to signal handler:
3030 *
3031 * a0 = signal number
Richard W.M. Jones02d2bd52012-07-05 03:32:44 +00003032 * a1 = pointer to siginfo_t
pbrook0b1bcb02009-04-21 01:41:10 +00003033 * a2 = pointer to struct ucontext
3034 *
3035 * $25 and PC point to the signal handler, $29 points to the
3036 * struct sigframe.
3037 */
3038 env->active_tc.gpr[ 4] = sig;
3039 env->active_tc.gpr[ 5] = frame_addr
3040 + offsetof(struct target_rt_sigframe, rs_info);
3041 env->active_tc.gpr[ 6] = frame_addr
3042 + offsetof(struct target_rt_sigframe, rs_uc);
3043 env->active_tc.gpr[29] = frame_addr;
3044 env->active_tc.gpr[31] = frame_addr
3045 + offsetof(struct target_rt_sigframe, rs_code);
3046 /* The original kernel code sets CP0_EPC to the handler
3047 * since it returns to userland using eret
3048 * we cannot do this here, and we must set PC directly */
3049 env->active_tc.PC = env->active_tc.gpr[25] = ka->_sa_handler;
Kwok Cheung Yeungea3164a2013-05-17 14:51:20 -07003050 mips_set_hflags_isa_mode_from_pc(env);
pbrook0b1bcb02009-04-21 01:41:10 +00003051 unlock_user_struct(frame, frame_addr, 1);
3052 return;
3053
3054give_sigsegv:
3055 unlock_user_struct(frame, frame_addr, 1);
3056 force_sig(TARGET_SIGSEGV/*, current*/);
bellard106ec872006-06-27 21:08:10 +00003057}
3058
Andreas Färber05390242012-02-25 03:37:53 +01003059long do_rt_sigreturn(CPUMIPSState *env)
bellard106ec872006-06-27 21:08:10 +00003060{
pbrook0b1bcb02009-04-21 01:41:10 +00003061 struct target_rt_sigframe *frame;
3062 abi_ulong frame_addr;
3063 sigset_t blocked;
3064
3065#if defined(DEBUG_SIGNAL)
3066 fprintf(stderr, "do_rt_sigreturn\n");
3067#endif
3068 frame_addr = env->active_tc.gpr[29];
3069 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
3070 goto badframe;
3071
Aurelien Jarno60e99242010-03-29 02:12:51 +02003072 target_to_host_sigset(&blocked, &frame->rs_uc.tuc_sigmask);
Alex Barcelo1c275922014-03-14 14:36:55 +00003073 do_sigprocmask(SIG_SETMASK, &blocked, NULL);
pbrook0b1bcb02009-04-21 01:41:10 +00003074
Riku Voipio016d2e12014-04-23 11:19:48 +03003075 restore_sigcontext(env, &frame->rs_uc.tuc_mcontext);
pbrook0b1bcb02009-04-21 01:41:10 +00003076
3077 if (do_sigaltstack(frame_addr +
Aurelien Jarno60e99242010-03-29 02:12:51 +02003078 offsetof(struct target_rt_sigframe, rs_uc.tuc_stack),
pbrook0b1bcb02009-04-21 01:41:10 +00003079 0, get_sp_from_cpustate(env)) == -EFAULT)
3080 goto badframe;
3081
3082 env->active_tc.PC = env->CP0_EPC;
Kwok Cheung Yeungea3164a2013-05-17 14:51:20 -07003083 mips_set_hflags_isa_mode_from_pc(env);
pbrook0b1bcb02009-04-21 01:41:10 +00003084 /* I am not sure this is right, but it seems to work
3085 * maybe a problem with nested signals ? */
3086 env->CP0_EPC = 0;
3087 return -TARGET_QEMU_ESIGRETURN;
3088
3089badframe:
3090 force_sig(TARGET_SIGSEGV/*, current*/);
3091 return 0;
bellard106ec872006-06-27 21:08:10 +00003092}
bellard6d5e2162004-09-30 22:04:13 +00003093
thsc3b5bc82007-12-02 06:31:25 +00003094#elif defined(TARGET_SH4)
3095
3096/*
3097 * code and data structures from linux kernel:
3098 * include/asm-sh/sigcontext.h
3099 * arch/sh/kernel/signal.c
3100 */
3101
3102struct target_sigcontext {
3103 target_ulong oldmask;
3104
3105 /* CPU registers */
3106 target_ulong sc_gregs[16];
3107 target_ulong sc_pc;
3108 target_ulong sc_pr;
3109 target_ulong sc_sr;
3110 target_ulong sc_gbr;
3111 target_ulong sc_mach;
3112 target_ulong sc_macl;
3113
3114 /* FPU registers */
3115 target_ulong sc_fpregs[16];
3116 target_ulong sc_xfpregs[16];
3117 unsigned int sc_fpscr;
3118 unsigned int sc_fpul;
3119 unsigned int sc_ownedfp;
3120};
3121
3122struct target_sigframe
3123{
3124 struct target_sigcontext sc;
3125 target_ulong extramask[TARGET_NSIG_WORDS-1];
3126 uint16_t retcode[3];
3127};
3128
3129
3130struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02003131 target_ulong tuc_flags;
3132 struct target_ucontext *tuc_link;
3133 target_stack_t tuc_stack;
3134 struct target_sigcontext tuc_mcontext;
3135 target_sigset_t tuc_sigmask; /* mask last for extensibility */
thsc3b5bc82007-12-02 06:31:25 +00003136};
3137
3138struct target_rt_sigframe
3139{
3140 struct target_siginfo info;
3141 struct target_ucontext uc;
3142 uint16_t retcode[3];
3143};
3144
3145
3146#define MOVW(n) (0x9300|((n)-2)) /* Move mem word at PC+n to R3 */
3147#define TRAP_NOARG 0xc310 /* Syscall w/no args (NR in R3) SH3/4 */
3148
pbrook624f7972008-05-31 16:11:38 +00003149static abi_ulong get_sigframe(struct target_sigaction *ka,
thsc3b5bc82007-12-02 06:31:25 +00003150 unsigned long sp, size_t frame_size)
3151{
pbrook624f7972008-05-31 16:11:38 +00003152 if ((ka->sa_flags & TARGET_SA_ONSTACK) && (sas_ss_flags(sp) == 0)) {
thsc3b5bc82007-12-02 06:31:25 +00003153 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
3154 }
3155
3156 return (sp - frame_size) & -8ul;
3157}
3158
Riku Voipio41ecc722014-04-23 11:01:00 +03003159static void setup_sigcontext(struct target_sigcontext *sc,
Andreas Färber05390242012-02-25 03:37:53 +01003160 CPUSH4State *regs, unsigned long mask)
thsc3b5bc82007-12-02 06:31:25 +00003161{
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003162 int i;
thsc3b5bc82007-12-02 06:31:25 +00003163
Riku Voipio1d8b5122014-04-23 10:26:05 +03003164#define COPY(x) __put_user(regs->x, &sc->sc_##x)
thsc3b5bc82007-12-02 06:31:25 +00003165 COPY(gregs[0]); COPY(gregs[1]);
3166 COPY(gregs[2]); COPY(gregs[3]);
3167 COPY(gregs[4]); COPY(gregs[5]);
3168 COPY(gregs[6]); COPY(gregs[7]);
3169 COPY(gregs[8]); COPY(gregs[9]);
3170 COPY(gregs[10]); COPY(gregs[11]);
3171 COPY(gregs[12]); COPY(gregs[13]);
3172 COPY(gregs[14]); COPY(gregs[15]);
3173 COPY(gbr); COPY(mach);
3174 COPY(macl); COPY(pr);
3175 COPY(sr); COPY(pc);
3176#undef COPY
3177
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003178 for (i=0; i<16; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03003179 __put_user(regs->fregs[i], &sc->sc_fpregs[i]);
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003180 }
Riku Voipio1d8b5122014-04-23 10:26:05 +03003181 __put_user(regs->fpscr, &sc->sc_fpscr);
3182 __put_user(regs->fpul, &sc->sc_fpul);
thsc3b5bc82007-12-02 06:31:25 +00003183
3184 /* non-iBCS2 extensions.. */
Riku Voipio1d8b5122014-04-23 10:26:05 +03003185 __put_user(mask, &sc->oldmask);
thsc3b5bc82007-12-02 06:31:25 +00003186}
3187
Riku Voipio016d2e12014-04-23 11:19:48 +03003188static void restore_sigcontext(CPUSH4State *regs, struct target_sigcontext *sc,
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003189 target_ulong *r0_p)
thsc3b5bc82007-12-02 06:31:25 +00003190{
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003191 int i;
thsc3b5bc82007-12-02 06:31:25 +00003192
Riku Voipio1d8b5122014-04-23 10:26:05 +03003193#define COPY(x) __get_user(regs->x, &sc->sc_##x)
thsc3b5bc82007-12-02 06:31:25 +00003194 COPY(gregs[1]);
3195 COPY(gregs[2]); COPY(gregs[3]);
3196 COPY(gregs[4]); COPY(gregs[5]);
3197 COPY(gregs[6]); COPY(gregs[7]);
3198 COPY(gregs[8]); COPY(gregs[9]);
3199 COPY(gregs[10]); COPY(gregs[11]);
3200 COPY(gregs[12]); COPY(gregs[13]);
3201 COPY(gregs[14]); COPY(gregs[15]);
3202 COPY(gbr); COPY(mach);
3203 COPY(macl); COPY(pr);
3204 COPY(sr); COPY(pc);
3205#undef COPY
3206
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003207 for (i=0; i<16; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03003208 __get_user(regs->fregs[i], &sc->sc_fpregs[i]);
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003209 }
Riku Voipio1d8b5122014-04-23 10:26:05 +03003210 __get_user(regs->fpscr, &sc->sc_fpscr);
3211 __get_user(regs->fpul, &sc->sc_fpul);
thsc3b5bc82007-12-02 06:31:25 +00003212
3213 regs->tra = -1; /* disable syscall checks */
Riku Voipio1d8b5122014-04-23 10:26:05 +03003214 __get_user(*r0_p, &sc->sc_gregs[0]);
thsc3b5bc82007-12-02 06:31:25 +00003215}
3216
pbrook624f7972008-05-31 16:11:38 +00003217static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01003218 target_sigset_t *set, CPUSH4State *regs)
thsc3b5bc82007-12-02 06:31:25 +00003219{
3220 struct target_sigframe *frame;
3221 abi_ulong frame_addr;
3222 int i;
3223 int err = 0;
thsc3b5bc82007-12-02 06:31:25 +00003224
3225 frame_addr = get_sigframe(ka, regs->gregs[15], sizeof(*frame));
3226 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
3227 goto give_sigsegv;
3228
Riku Voipio41ecc722014-04-23 11:01:00 +03003229 setup_sigcontext(&frame->sc, regs, set->sig[0]);
thsc3b5bc82007-12-02 06:31:25 +00003230
3231 for (i = 0; i < TARGET_NSIG_WORDS - 1; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03003232 __put_user(set->sig[i + 1], &frame->extramask[i]);
thsc3b5bc82007-12-02 06:31:25 +00003233 }
3234
3235 /* Set up to return from userspace. If provided, use a stub
3236 already in userspace. */
pbrook624f7972008-05-31 16:11:38 +00003237 if (ka->sa_flags & TARGET_SA_RESTORER) {
3238 regs->pr = (unsigned long) ka->sa_restorer;
thsc3b5bc82007-12-02 06:31:25 +00003239 } else {
3240 /* Generate return code (system call to sigreturn) */
Riku Voipio1d8b5122014-04-23 10:26:05 +03003241 __put_user(MOVW(2), &frame->retcode[0]);
3242 __put_user(TRAP_NOARG, &frame->retcode[1]);
3243 __put_user((TARGET_NR_sigreturn), &frame->retcode[2]);
thsc3b5bc82007-12-02 06:31:25 +00003244 regs->pr = (unsigned long) frame->retcode;
3245 }
3246
3247 if (err)
3248 goto give_sigsegv;
3249
3250 /* Set up registers for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003251 regs->gregs[15] = frame_addr;
Peter Maydellb6e2c932015-01-08 12:19:43 +00003252 regs->gregs[4] = sig; /* Arg for signal handler */
thsc3b5bc82007-12-02 06:31:25 +00003253 regs->gregs[5] = 0;
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003254 regs->gregs[6] = frame_addr += offsetof(typeof(*frame), sc);
pbrook624f7972008-05-31 16:11:38 +00003255 regs->pc = (unsigned long) ka->_sa_handler;
thsc3b5bc82007-12-02 06:31:25 +00003256
3257 unlock_user_struct(frame, frame_addr, 1);
3258 return;
3259
3260give_sigsegv:
3261 unlock_user_struct(frame, frame_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02003262 force_sig(TARGET_SIGSEGV);
thsc3b5bc82007-12-02 06:31:25 +00003263}
3264
pbrook624f7972008-05-31 16:11:38 +00003265static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05003266 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01003267 target_sigset_t *set, CPUSH4State *regs)
thsc3b5bc82007-12-02 06:31:25 +00003268{
3269 struct target_rt_sigframe *frame;
3270 abi_ulong frame_addr;
3271 int i;
3272 int err = 0;
thsc3b5bc82007-12-02 06:31:25 +00003273
3274 frame_addr = get_sigframe(ka, regs->gregs[15], sizeof(*frame));
3275 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
3276 goto give_sigsegv;
3277
Riku Voipiob0fd8d12014-04-23 10:46:13 +03003278 copy_siginfo_to_user(&frame->info, info);
thsc3b5bc82007-12-02 06:31:25 +00003279
3280 /* Create the ucontext. */
Riku Voipio1d8b5122014-04-23 10:26:05 +03003281 __put_user(0, &frame->uc.tuc_flags);
3282 __put_user(0, (unsigned long *)&frame->uc.tuc_link);
3283 __put_user((unsigned long)target_sigaltstack_used.ss_sp,
3284 &frame->uc.tuc_stack.ss_sp);
3285 __put_user(sas_ss_flags(regs->gregs[15]),
3286 &frame->uc.tuc_stack.ss_flags);
3287 __put_user(target_sigaltstack_used.ss_size,
3288 &frame->uc.tuc_stack.ss_size);
3289 setup_sigcontext(&frame->uc.tuc_mcontext,
thsc3b5bc82007-12-02 06:31:25 +00003290 regs, set->sig[0]);
3291 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03003292 __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
thsc3b5bc82007-12-02 06:31:25 +00003293 }
3294
3295 /* Set up to return from userspace. If provided, use a stub
3296 already in userspace. */
pbrook624f7972008-05-31 16:11:38 +00003297 if (ka->sa_flags & TARGET_SA_RESTORER) {
3298 regs->pr = (unsigned long) ka->sa_restorer;
thsc3b5bc82007-12-02 06:31:25 +00003299 } else {
3300 /* Generate return code (system call to sigreturn) */
Riku Voipio1d8b5122014-04-23 10:26:05 +03003301 __put_user(MOVW(2), &frame->retcode[0]);
3302 __put_user(TRAP_NOARG, &frame->retcode[1]);
3303 __put_user((TARGET_NR_rt_sigreturn), &frame->retcode[2]);
thsc3b5bc82007-12-02 06:31:25 +00003304 regs->pr = (unsigned long) frame->retcode;
3305 }
3306
3307 if (err)
3308 goto give_sigsegv;
3309
3310 /* Set up registers for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003311 regs->gregs[15] = frame_addr;
Peter Maydellb6e2c932015-01-08 12:19:43 +00003312 regs->gregs[4] = sig; /* Arg for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003313 regs->gregs[5] = frame_addr + offsetof(typeof(*frame), info);
3314 regs->gregs[6] = frame_addr + offsetof(typeof(*frame), uc);
pbrook624f7972008-05-31 16:11:38 +00003315 regs->pc = (unsigned long) ka->_sa_handler;
thsc3b5bc82007-12-02 06:31:25 +00003316
3317 unlock_user_struct(frame, frame_addr, 1);
3318 return;
3319
3320give_sigsegv:
3321 unlock_user_struct(frame, frame_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02003322 force_sig(TARGET_SIGSEGV);
thsc3b5bc82007-12-02 06:31:25 +00003323}
3324
Andreas Färber05390242012-02-25 03:37:53 +01003325long do_sigreturn(CPUSH4State *regs)
thsc3b5bc82007-12-02 06:31:25 +00003326{
3327 struct target_sigframe *frame;
3328 abi_ulong frame_addr;
3329 sigset_t blocked;
Anthony Liguoric227f092009-10-01 16:12:16 -05003330 target_sigset_t target_set;
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003331 target_ulong r0;
thsc3b5bc82007-12-02 06:31:25 +00003332 int i;
3333 int err = 0;
3334
3335#if defined(DEBUG_SIGNAL)
3336 fprintf(stderr, "do_sigreturn\n");
3337#endif
3338 frame_addr = regs->gregs[15];
3339 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
3340 goto badframe;
3341
Riku Voipio1d8b5122014-04-23 10:26:05 +03003342 __get_user(target_set.sig[0], &frame->sc.oldmask);
thsc3b5bc82007-12-02 06:31:25 +00003343 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03003344 __get_user(target_set.sig[i], &frame->extramask[i - 1]);
thsc3b5bc82007-12-02 06:31:25 +00003345 }
3346
3347 if (err)
3348 goto badframe;
3349
3350 target_to_host_sigset_internal(&blocked, &target_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00003351 do_sigprocmask(SIG_SETMASK, &blocked, NULL);
thsc3b5bc82007-12-02 06:31:25 +00003352
Riku Voipio016d2e12014-04-23 11:19:48 +03003353 restore_sigcontext(regs, &frame->sc, &r0);
thsc3b5bc82007-12-02 06:31:25 +00003354
3355 unlock_user_struct(frame, frame_addr, 0);
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003356 return r0;
thsc3b5bc82007-12-02 06:31:25 +00003357
3358badframe:
3359 unlock_user_struct(frame, frame_addr, 0);
3360 force_sig(TARGET_SIGSEGV);
3361 return 0;
3362}
3363
Andreas Färber05390242012-02-25 03:37:53 +01003364long do_rt_sigreturn(CPUSH4State *regs)
thsc3b5bc82007-12-02 06:31:25 +00003365{
3366 struct target_rt_sigframe *frame;
3367 abi_ulong frame_addr;
3368 sigset_t blocked;
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003369 target_ulong r0;
thsc3b5bc82007-12-02 06:31:25 +00003370
3371#if defined(DEBUG_SIGNAL)
3372 fprintf(stderr, "do_rt_sigreturn\n");
3373#endif
3374 frame_addr = regs->gregs[15];
3375 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
3376 goto badframe;
3377
Aurelien Jarno60e99242010-03-29 02:12:51 +02003378 target_to_host_sigset(&blocked, &frame->uc.tuc_sigmask);
Alex Barcelo1c275922014-03-14 14:36:55 +00003379 do_sigprocmask(SIG_SETMASK, &blocked, NULL);
thsc3b5bc82007-12-02 06:31:25 +00003380
Riku Voipio016d2e12014-04-23 11:19:48 +03003381 restore_sigcontext(regs, &frame->uc.tuc_mcontext, &r0);
thsc3b5bc82007-12-02 06:31:25 +00003382
3383 if (do_sigaltstack(frame_addr +
Aurelien Jarno60e99242010-03-29 02:12:51 +02003384 offsetof(struct target_rt_sigframe, uc.tuc_stack),
thsc3b5bc82007-12-02 06:31:25 +00003385 0, get_sp_from_cpustate(regs)) == -EFAULT)
3386 goto badframe;
3387
3388 unlock_user_struct(frame, frame_addr, 0);
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003389 return r0;
thsc3b5bc82007-12-02 06:31:25 +00003390
3391badframe:
3392 unlock_user_struct(frame, frame_addr, 0);
3393 force_sig(TARGET_SIGSEGV);
3394 return 0;
3395}
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003396#elif defined(TARGET_MICROBLAZE)
3397
3398struct target_sigcontext {
3399 struct target_pt_regs regs; /* needs to be first */
3400 uint32_t oldmask;
3401};
3402
Edgar E. Iglesiasb2178702010-07-23 09:30:37 +02003403struct target_stack_t {
3404 abi_ulong ss_sp;
3405 int ss_flags;
3406 unsigned int ss_size;
3407};
3408
3409struct target_ucontext {
Richard Hendersonf711df62010-11-22 14:57:52 -08003410 abi_ulong tuc_flags;
3411 abi_ulong tuc_link;
3412 struct target_stack_t tuc_stack;
3413 struct target_sigcontext tuc_mcontext;
3414 uint32_t tuc_extramask[TARGET_NSIG_WORDS - 1];
Edgar E. Iglesiasb2178702010-07-23 09:30:37 +02003415};
3416
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003417/* Signal frames. */
3418struct target_signal_frame {
Edgar E. Iglesiasb2178702010-07-23 09:30:37 +02003419 struct target_ucontext uc;
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003420 uint32_t extramask[TARGET_NSIG_WORDS - 1];
3421 uint32_t tramp[2];
3422};
3423
3424struct rt_signal_frame {
Richard W.M. Jones02d2bd52012-07-05 03:32:44 +00003425 siginfo_t info;
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003426 struct ucontext uc;
3427 uint32_t tramp[2];
3428};
3429
Andreas Färber05390242012-02-25 03:37:53 +01003430static void setup_sigcontext(struct target_sigcontext *sc, CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003431{
3432 __put_user(env->regs[0], &sc->regs.r0);
3433 __put_user(env->regs[1], &sc->regs.r1);
3434 __put_user(env->regs[2], &sc->regs.r2);
3435 __put_user(env->regs[3], &sc->regs.r3);
3436 __put_user(env->regs[4], &sc->regs.r4);
3437 __put_user(env->regs[5], &sc->regs.r5);
3438 __put_user(env->regs[6], &sc->regs.r6);
3439 __put_user(env->regs[7], &sc->regs.r7);
3440 __put_user(env->regs[8], &sc->regs.r8);
3441 __put_user(env->regs[9], &sc->regs.r9);
3442 __put_user(env->regs[10], &sc->regs.r10);
3443 __put_user(env->regs[11], &sc->regs.r11);
3444 __put_user(env->regs[12], &sc->regs.r12);
3445 __put_user(env->regs[13], &sc->regs.r13);
3446 __put_user(env->regs[14], &sc->regs.r14);
3447 __put_user(env->regs[15], &sc->regs.r15);
3448 __put_user(env->regs[16], &sc->regs.r16);
3449 __put_user(env->regs[17], &sc->regs.r17);
3450 __put_user(env->regs[18], &sc->regs.r18);
3451 __put_user(env->regs[19], &sc->regs.r19);
3452 __put_user(env->regs[20], &sc->regs.r20);
3453 __put_user(env->regs[21], &sc->regs.r21);
3454 __put_user(env->regs[22], &sc->regs.r22);
3455 __put_user(env->regs[23], &sc->regs.r23);
3456 __put_user(env->regs[24], &sc->regs.r24);
3457 __put_user(env->regs[25], &sc->regs.r25);
3458 __put_user(env->regs[26], &sc->regs.r26);
3459 __put_user(env->regs[27], &sc->regs.r27);
3460 __put_user(env->regs[28], &sc->regs.r28);
3461 __put_user(env->regs[29], &sc->regs.r29);
3462 __put_user(env->regs[30], &sc->regs.r30);
3463 __put_user(env->regs[31], &sc->regs.r31);
3464 __put_user(env->sregs[SR_PC], &sc->regs.pc);
3465}
3466
Andreas Färber05390242012-02-25 03:37:53 +01003467static void restore_sigcontext(struct target_sigcontext *sc, CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003468{
3469 __get_user(env->regs[0], &sc->regs.r0);
3470 __get_user(env->regs[1], &sc->regs.r1);
3471 __get_user(env->regs[2], &sc->regs.r2);
3472 __get_user(env->regs[3], &sc->regs.r3);
3473 __get_user(env->regs[4], &sc->regs.r4);
3474 __get_user(env->regs[5], &sc->regs.r5);
3475 __get_user(env->regs[6], &sc->regs.r6);
3476 __get_user(env->regs[7], &sc->regs.r7);
3477 __get_user(env->regs[8], &sc->regs.r8);
3478 __get_user(env->regs[9], &sc->regs.r9);
3479 __get_user(env->regs[10], &sc->regs.r10);
3480 __get_user(env->regs[11], &sc->regs.r11);
3481 __get_user(env->regs[12], &sc->regs.r12);
3482 __get_user(env->regs[13], &sc->regs.r13);
3483 __get_user(env->regs[14], &sc->regs.r14);
3484 __get_user(env->regs[15], &sc->regs.r15);
3485 __get_user(env->regs[16], &sc->regs.r16);
3486 __get_user(env->regs[17], &sc->regs.r17);
3487 __get_user(env->regs[18], &sc->regs.r18);
3488 __get_user(env->regs[19], &sc->regs.r19);
3489 __get_user(env->regs[20], &sc->regs.r20);
3490 __get_user(env->regs[21], &sc->regs.r21);
3491 __get_user(env->regs[22], &sc->regs.r22);
3492 __get_user(env->regs[23], &sc->regs.r23);
3493 __get_user(env->regs[24], &sc->regs.r24);
3494 __get_user(env->regs[25], &sc->regs.r25);
3495 __get_user(env->regs[26], &sc->regs.r26);
3496 __get_user(env->regs[27], &sc->regs.r27);
3497 __get_user(env->regs[28], &sc->regs.r28);
3498 __get_user(env->regs[29], &sc->regs.r29);
3499 __get_user(env->regs[30], &sc->regs.r30);
3500 __get_user(env->regs[31], &sc->regs.r31);
3501 __get_user(env->sregs[SR_PC], &sc->regs.pc);
3502}
3503
3504static abi_ulong get_sigframe(struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01003505 CPUMBState *env, int frame_size)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003506{
3507 abi_ulong sp = env->regs[1];
3508
Riku Voipiob545f632014-07-15 17:01:55 +03003509 if ((ka->sa_flags & TARGET_SA_ONSTACK) != 0 && !on_sig_stack(sp)) {
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003510 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
Riku Voipiob545f632014-07-15 17:01:55 +03003511 }
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003512
3513 return ((sp - frame_size) & -8UL);
3514}
3515
3516static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01003517 target_sigset_t *set, CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003518{
3519 struct target_signal_frame *frame;
3520 abi_ulong frame_addr;
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003521 int i;
3522
3523 frame_addr = get_sigframe(ka, env, sizeof *frame);
3524 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
3525 goto badframe;
3526
3527 /* Save the mask. */
Riku Voipio1d8b5122014-04-23 10:26:05 +03003528 __put_user(set->sig[0], &frame->uc.tuc_mcontext.oldmask);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003529
3530 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
Riku Voipio0188fad2014-04-23 13:34:15 +03003531 __put_user(set->sig[i], &frame->extramask[i - 1]);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003532 }
3533
Richard Hendersonf711df62010-11-22 14:57:52 -08003534 setup_sigcontext(&frame->uc.tuc_mcontext, env);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003535
3536 /* Set up to return from userspace. If provided, use a stub
3537 already in userspace. */
3538 /* minus 8 is offset to cater for "rtsd r15,8" offset */
3539 if (ka->sa_flags & TARGET_SA_RESTORER) {
3540 env->regs[15] = ((unsigned long)ka->sa_restorer)-8;
3541 } else {
3542 uint32_t t;
3543 /* Note, these encodings are _big endian_! */
3544 /* addi r12, r0, __NR_sigreturn */
3545 t = 0x31800000UL | TARGET_NR_sigreturn;
Riku Voipio1d8b5122014-04-23 10:26:05 +03003546 __put_user(t, frame->tramp + 0);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003547 /* brki r14, 0x8 */
3548 t = 0xb9cc0008UL;
Riku Voipio1d8b5122014-04-23 10:26:05 +03003549 __put_user(t, frame->tramp + 1);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003550
3551 /* Return from sighandler will jump to the tramp.
3552 Negative 8 offset because return is rtsd r15, 8 */
3553 env->regs[15] = ((unsigned long)frame->tramp) - 8;
3554 }
3555
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003556 /* Set up registers for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003557 env->regs[1] = frame_addr;
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003558 /* Signal handler args: */
3559 env->regs[5] = sig; /* Arg 0: signum */
Edgar E. Iglesias187b4e02010-07-15 15:32:51 +02003560 env->regs[6] = 0;
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003561 /* arg 1: sigcontext */
3562 env->regs[7] = frame_addr += offsetof(typeof(*frame), uc);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003563
3564 /* Offset of 4 to handle microblaze rtid r14, 0 */
3565 env->sregs[SR_PC] = (unsigned long)ka->_sa_handler;
3566
3567 unlock_user_struct(frame, frame_addr, 1);
3568 return;
3569 badframe:
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003570 force_sig(TARGET_SIGSEGV);
3571}
3572
3573static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05003574 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01003575 target_sigset_t *set, CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003576{
3577 fprintf(stderr, "Microblaze setup_rt_frame: not implemented\n");
3578}
3579
Andreas Färber05390242012-02-25 03:37:53 +01003580long do_sigreturn(CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003581{
3582 struct target_signal_frame *frame;
3583 abi_ulong frame_addr;
Anthony Liguoric227f092009-10-01 16:12:16 -05003584 target_sigset_t target_set;
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003585 sigset_t set;
3586 int i;
3587
3588 frame_addr = env->regs[R_SP];
3589 /* Make sure the guest isn't playing games. */
3590 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 1))
3591 goto badframe;
3592
3593 /* Restore blocked signals */
Riku Voipiof5f601a2014-04-23 13:00:17 +03003594 __get_user(target_set.sig[0], &frame->uc.tuc_mcontext.oldmask);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003595 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
Riku Voipiof5f601a2014-04-23 13:00:17 +03003596 __get_user(target_set.sig[i], &frame->extramask[i - 1]);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003597 }
3598 target_to_host_sigset_internal(&set, &target_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00003599 do_sigprocmask(SIG_SETMASK, &set, NULL);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003600
Richard Hendersonf711df62010-11-22 14:57:52 -08003601 restore_sigcontext(&frame->uc.tuc_mcontext, env);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003602 /* We got here through a sigreturn syscall, our path back is via an
3603 rtb insn so setup r14 for that. */
3604 env->regs[14] = env->sregs[SR_PC];
3605
3606 unlock_user_struct(frame, frame_addr, 0);
3607 return env->regs[10];
3608 badframe:
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003609 force_sig(TARGET_SIGSEGV);
3610}
3611
Andreas Färber05390242012-02-25 03:37:53 +01003612long do_rt_sigreturn(CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003613{
3614 fprintf(stderr, "Microblaze do_rt_sigreturn: not implemented\n");
3615 return -TARGET_ENOSYS;
3616}
3617
edgar_iglb6d3abd2008-02-28 11:29:27 +00003618#elif defined(TARGET_CRIS)
3619
3620struct target_sigcontext {
3621 struct target_pt_regs regs; /* needs to be first */
3622 uint32_t oldmask;
3623 uint32_t usp; /* usp before stacking this gunk on it */
3624};
3625
3626/* Signal frames. */
3627struct target_signal_frame {
3628 struct target_sigcontext sc;
3629 uint32_t extramask[TARGET_NSIG_WORDS - 1];
Stefan Weil8cfc1142014-02-01 09:41:09 +01003630 uint16_t retcode[4]; /* Trampoline code. */
edgar_iglb6d3abd2008-02-28 11:29:27 +00003631};
3632
3633struct rt_signal_frame {
Richard W.M. Jones02d2bd52012-07-05 03:32:44 +00003634 siginfo_t *pinfo;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003635 void *puc;
Richard W.M. Jones02d2bd52012-07-05 03:32:44 +00003636 siginfo_t info;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003637 struct ucontext uc;
Stefan Weil8cfc1142014-02-01 09:41:09 +01003638 uint16_t retcode[4]; /* Trampoline code. */
edgar_iglb6d3abd2008-02-28 11:29:27 +00003639};
3640
Andreas Färber05390242012-02-25 03:37:53 +01003641static void setup_sigcontext(struct target_sigcontext *sc, CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003642{
edgar_igl9664d922008-03-03 22:23:53 +00003643 __put_user(env->regs[0], &sc->regs.r0);
3644 __put_user(env->regs[1], &sc->regs.r1);
3645 __put_user(env->regs[2], &sc->regs.r2);
3646 __put_user(env->regs[3], &sc->regs.r3);
3647 __put_user(env->regs[4], &sc->regs.r4);
3648 __put_user(env->regs[5], &sc->regs.r5);
3649 __put_user(env->regs[6], &sc->regs.r6);
3650 __put_user(env->regs[7], &sc->regs.r7);
3651 __put_user(env->regs[8], &sc->regs.r8);
3652 __put_user(env->regs[9], &sc->regs.r9);
3653 __put_user(env->regs[10], &sc->regs.r10);
3654 __put_user(env->regs[11], &sc->regs.r11);
3655 __put_user(env->regs[12], &sc->regs.r12);
3656 __put_user(env->regs[13], &sc->regs.r13);
3657 __put_user(env->regs[14], &sc->usp);
3658 __put_user(env->regs[15], &sc->regs.acr);
3659 __put_user(env->pregs[PR_MOF], &sc->regs.mof);
3660 __put_user(env->pregs[PR_SRP], &sc->regs.srp);
3661 __put_user(env->pc, &sc->regs.erp);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003662}
edgar_igl9664d922008-03-03 22:23:53 +00003663
Andreas Färber05390242012-02-25 03:37:53 +01003664static void restore_sigcontext(struct target_sigcontext *sc, CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003665{
edgar_igl9664d922008-03-03 22:23:53 +00003666 __get_user(env->regs[0], &sc->regs.r0);
3667 __get_user(env->regs[1], &sc->regs.r1);
3668 __get_user(env->regs[2], &sc->regs.r2);
3669 __get_user(env->regs[3], &sc->regs.r3);
3670 __get_user(env->regs[4], &sc->regs.r4);
3671 __get_user(env->regs[5], &sc->regs.r5);
3672 __get_user(env->regs[6], &sc->regs.r6);
3673 __get_user(env->regs[7], &sc->regs.r7);
3674 __get_user(env->regs[8], &sc->regs.r8);
3675 __get_user(env->regs[9], &sc->regs.r9);
3676 __get_user(env->regs[10], &sc->regs.r10);
3677 __get_user(env->regs[11], &sc->regs.r11);
3678 __get_user(env->regs[12], &sc->regs.r12);
3679 __get_user(env->regs[13], &sc->regs.r13);
3680 __get_user(env->regs[14], &sc->usp);
3681 __get_user(env->regs[15], &sc->regs.acr);
3682 __get_user(env->pregs[PR_MOF], &sc->regs.mof);
3683 __get_user(env->pregs[PR_SRP], &sc->regs.srp);
3684 __get_user(env->pc, &sc->regs.erp);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003685}
3686
Andreas Färber05390242012-02-25 03:37:53 +01003687static abi_ulong get_sigframe(CPUCRISState *env, int framesize)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003688{
edgar_igl9664d922008-03-03 22:23:53 +00003689 abi_ulong sp;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003690 /* Align the stack downwards to 4. */
edgar_igl9664d922008-03-03 22:23:53 +00003691 sp = (env->regs[R_SP] & ~3);
3692 return sp - framesize;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003693}
3694
pbrook624f7972008-05-31 16:11:38 +00003695static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01003696 target_sigset_t *set, CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003697{
3698 struct target_signal_frame *frame;
edgar_igl9664d922008-03-03 22:23:53 +00003699 abi_ulong frame_addr;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003700 int i;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003701
edgar_igl9664d922008-03-03 22:23:53 +00003702 frame_addr = get_sigframe(env, sizeof *frame);
3703 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
edgar_iglb6d3abd2008-02-28 11:29:27 +00003704 goto badframe;
3705
3706 /*
3707 * The CRIS signal return trampoline. A real linux/CRIS kernel doesn't
3708 * use this trampoline anymore but it sets it up for GDB.
3709 * In QEMU, using the trampoline simplifies things a bit so we use it.
3710 *
3711 * This is movu.w __NR_sigreturn, r9; break 13;
3712 */
Riku Voipio1d8b5122014-04-23 10:26:05 +03003713 __put_user(0x9c5f, frame->retcode+0);
3714 __put_user(TARGET_NR_sigreturn,
3715 frame->retcode + 1);
3716 __put_user(0xe93d, frame->retcode + 2);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003717
3718 /* Save the mask. */
Riku Voipio1d8b5122014-04-23 10:26:05 +03003719 __put_user(set->sig[0], &frame->sc.oldmask);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003720
Riku Voipio0188fad2014-04-23 13:34:15 +03003721 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
3722 __put_user(set->sig[i], &frame->extramask[i - 1]);
3723 }
edgar_iglb6d3abd2008-02-28 11:29:27 +00003724
3725 setup_sigcontext(&frame->sc, env);
3726
3727 /* Move the stack and setup the arguments for the handler. */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003728 env->regs[R_SP] = frame_addr;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003729 env->regs[10] = sig;
pbrook624f7972008-05-31 16:11:38 +00003730 env->pc = (unsigned long) ka->_sa_handler;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003731 /* Link SRP so the guest returns through the trampoline. */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003732 env->pregs[PR_SRP] = frame_addr + offsetof(typeof(*frame), retcode);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003733
edgar_igl9664d922008-03-03 22:23:53 +00003734 unlock_user_struct(frame, frame_addr, 1);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003735 return;
3736 badframe:
edgar_iglb6d3abd2008-02-28 11:29:27 +00003737 force_sig(TARGET_SIGSEGV);
3738}
3739
pbrook624f7972008-05-31 16:11:38 +00003740static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05003741 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01003742 target_sigset_t *set, CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003743{
3744 fprintf(stderr, "CRIS setup_rt_frame: not implemented\n");
3745}
3746
Andreas Färber05390242012-02-25 03:37:53 +01003747long do_sigreturn(CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003748{
3749 struct target_signal_frame *frame;
edgar_igl9664d922008-03-03 22:23:53 +00003750 abi_ulong frame_addr;
Anthony Liguoric227f092009-10-01 16:12:16 -05003751 target_sigset_t target_set;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003752 sigset_t set;
3753 int i;
3754
edgar_igl9664d922008-03-03 22:23:53 +00003755 frame_addr = env->regs[R_SP];
edgar_iglb6d3abd2008-02-28 11:29:27 +00003756 /* Make sure the guest isn't playing games. */
edgar_igl9664d922008-03-03 22:23:53 +00003757 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 1))
edgar_iglb6d3abd2008-02-28 11:29:27 +00003758 goto badframe;
3759
3760 /* Restore blocked signals */
Riku Voipiof5f601a2014-04-23 13:00:17 +03003761 __get_user(target_set.sig[0], &frame->sc.oldmask);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003762 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
Riku Voipiof5f601a2014-04-23 13:00:17 +03003763 __get_user(target_set.sig[i], &frame->extramask[i - 1]);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003764 }
3765 target_to_host_sigset_internal(&set, &target_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00003766 do_sigprocmask(SIG_SETMASK, &set, NULL);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003767
3768 restore_sigcontext(&frame->sc, env);
edgar_igl9664d922008-03-03 22:23:53 +00003769 unlock_user_struct(frame, frame_addr, 0);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003770 return env->regs[10];
3771 badframe:
edgar_iglb6d3abd2008-02-28 11:29:27 +00003772 force_sig(TARGET_SIGSEGV);
3773}
3774
Andreas Färber05390242012-02-25 03:37:53 +01003775long do_rt_sigreturn(CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003776{
3777 fprintf(stderr, "CRIS do_rt_sigreturn: not implemented\n");
3778 return -TARGET_ENOSYS;
3779}
thsc3b5bc82007-12-02 06:31:25 +00003780
Jia Liud9627832012-07-20 15:50:52 +08003781#elif defined(TARGET_OPENRISC)
3782
3783struct target_sigcontext {
3784 struct target_pt_regs regs;
3785 abi_ulong oldmask;
3786 abi_ulong usp;
3787};
3788
3789struct target_ucontext {
3790 abi_ulong tuc_flags;
3791 abi_ulong tuc_link;
3792 target_stack_t tuc_stack;
3793 struct target_sigcontext tuc_mcontext;
3794 target_sigset_t tuc_sigmask; /* mask last for extensibility */
3795};
3796
3797struct target_rt_sigframe {
3798 abi_ulong pinfo;
3799 uint64_t puc;
3800 struct target_siginfo info;
3801 struct target_sigcontext sc;
3802 struct target_ucontext uc;
3803 unsigned char retcode[16]; /* trampoline code */
3804};
3805
3806/* This is the asm-generic/ucontext.h version */
3807#if 0
3808static int restore_sigcontext(CPUOpenRISCState *regs,
3809 struct target_sigcontext *sc)
3810{
3811 unsigned int err = 0;
3812 unsigned long old_usp;
3813
3814 /* Alwys make any pending restarted system call return -EINTR */
3815 current_thread_info()->restart_block.fn = do_no_restart_syscall;
3816
3817 /* restore the regs from &sc->regs (same as sc, since regs is first)
3818 * (sc is already checked for VERIFY_READ since the sigframe was
3819 * checked in sys_sigreturn previously)
3820 */
3821
3822 if (copy_from_user(regs, &sc, sizeof(struct target_pt_regs))) {
3823 goto badframe;
3824 }
3825
3826 /* make sure the U-flag is set so user-mode cannot fool us */
3827
3828 regs->sr &= ~SR_SM;
3829
3830 /* restore the old USP as it was before we stacked the sc etc.
3831 * (we cannot just pop the sigcontext since we aligned the sp and
3832 * stuff after pushing it)
3833 */
3834
Riku Voipio1d8b5122014-04-23 10:26:05 +03003835 __get_user(old_usp, &sc->usp);
Jia Liud9627832012-07-20 15:50:52 +08003836 phx_signal("old_usp 0x%lx", old_usp);
3837
3838 __PHX__ REALLY /* ??? */
3839 wrusp(old_usp);
3840 regs->gpr[1] = old_usp;
3841
3842 /* TODO: the other ports use regs->orig_XX to disable syscall checks
3843 * after this completes, but we don't use that mechanism. maybe we can
3844 * use it now ?
3845 */
3846
3847 return err;
3848
3849badframe:
3850 return 1;
3851}
3852#endif
3853
3854/* Set up a signal frame. */
3855
Riku Voipio41ecc722014-04-23 11:01:00 +03003856static void setup_sigcontext(struct target_sigcontext *sc,
Jia Liud9627832012-07-20 15:50:52 +08003857 CPUOpenRISCState *regs,
3858 unsigned long mask)
3859{
Jia Liud9627832012-07-20 15:50:52 +08003860 unsigned long usp = regs->gpr[1];
3861
3862 /* copy the regs. they are first in sc so we can use sc directly */
3863
Riku Voipio1d8b5122014-04-23 10:26:05 +03003864 /*copy_to_user(&sc, regs, sizeof(struct target_pt_regs));*/
Jia Liud9627832012-07-20 15:50:52 +08003865
3866 /* Set the frametype to CRIS_FRAME_NORMAL for the execution of
3867 the signal handler. The frametype will be restored to its previous
3868 value in restore_sigcontext. */
3869 /*regs->frametype = CRIS_FRAME_NORMAL;*/
3870
3871 /* then some other stuff */
Riku Voipio1d8b5122014-04-23 10:26:05 +03003872 __put_user(mask, &sc->oldmask);
Riku Voipio41ecc722014-04-23 11:01:00 +03003873 __put_user(usp, &sc->usp);
Jia Liud9627832012-07-20 15:50:52 +08003874}
3875
3876static inline unsigned long align_sigframe(unsigned long sp)
3877{
3878 unsigned long i;
3879 i = sp & ~3UL;
3880 return i;
3881}
3882
3883static inline abi_ulong get_sigframe(struct target_sigaction *ka,
3884 CPUOpenRISCState *regs,
3885 size_t frame_size)
3886{
3887 unsigned long sp = regs->gpr[1];
3888 int onsigstack = on_sig_stack(sp);
3889
3890 /* redzone */
3891 /* This is the X/Open sanctioned signal stack switching. */
Riku Voipiob545f632014-07-15 17:01:55 +03003892 if ((ka->sa_flags & TARGET_SA_ONSTACK) != 0 && !onsigstack) {
Jia Liud9627832012-07-20 15:50:52 +08003893 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
3894 }
3895
3896 sp = align_sigframe(sp - frame_size);
3897
3898 /*
3899 * If we are on the alternate signal stack and would overflow it, don't.
3900 * Return an always-bogus address instead so we will die with SIGSEGV.
3901 */
3902
3903 if (onsigstack && !likely(on_sig_stack(sp))) {
3904 return -1L;
3905 }
3906
3907 return sp;
3908}
3909
3910static void setup_frame(int sig, struct target_sigaction *ka,
3911 target_sigset_t *set, CPUOpenRISCState *env)
3912{
3913 qemu_log("Not implement.\n");
3914}
3915
3916static void setup_rt_frame(int sig, struct target_sigaction *ka,
3917 target_siginfo_t *info,
3918 target_sigset_t *set, CPUOpenRISCState *env)
3919{
3920 int err = 0;
3921 abi_ulong frame_addr;
3922 unsigned long return_ip;
3923 struct target_rt_sigframe *frame;
3924 abi_ulong info_addr, uc_addr;
3925
Jia Liud9627832012-07-20 15:50:52 +08003926 frame_addr = get_sigframe(ka, env, sizeof(*frame));
3927 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
3928 goto give_sigsegv;
3929 }
3930
3931 info_addr = frame_addr + offsetof(struct target_rt_sigframe, info);
Riku Voipio1d8b5122014-04-23 10:26:05 +03003932 __put_user(info_addr, &frame->pinfo);
Jia Liud9627832012-07-20 15:50:52 +08003933 uc_addr = frame_addr + offsetof(struct target_rt_sigframe, uc);
Riku Voipio1d8b5122014-04-23 10:26:05 +03003934 __put_user(uc_addr, &frame->puc);
Jia Liud9627832012-07-20 15:50:52 +08003935
3936 if (ka->sa_flags & SA_SIGINFO) {
Riku Voipiob0fd8d12014-04-23 10:46:13 +03003937 copy_siginfo_to_user(&frame->info, info);
Jia Liud9627832012-07-20 15:50:52 +08003938 }
3939
3940 /*err |= __clear_user(&frame->uc, offsetof(struct ucontext, uc_mcontext));*/
Riku Voipio1d8b5122014-04-23 10:26:05 +03003941 __put_user(0, &frame->uc.tuc_flags);
3942 __put_user(0, &frame->uc.tuc_link);
3943 __put_user(target_sigaltstack_used.ss_sp,
3944 &frame->uc.tuc_stack.ss_sp);
3945 __put_user(sas_ss_flags(env->gpr[1]), &frame->uc.tuc_stack.ss_flags);
3946 __put_user(target_sigaltstack_used.ss_size,
3947 &frame->uc.tuc_stack.ss_size);
Riku Voipio41ecc722014-04-23 11:01:00 +03003948 setup_sigcontext(&frame->sc, env, set->sig[0]);
Jia Liud9627832012-07-20 15:50:52 +08003949
3950 /*err |= copy_to_user(frame->uc.tuc_sigmask, set, sizeof(*set));*/
3951
Jia Liud9627832012-07-20 15:50:52 +08003952 /* trampoline - the desired return ip is the retcode itself */
3953 return_ip = (unsigned long)&frame->retcode;
3954 /* This is l.ori r11,r0,__NR_sigreturn, l.sys 1 */
Riku Voipio1d8b5122014-04-23 10:26:05 +03003955 __put_user(0xa960, (short *)(frame->retcode + 0));
3956 __put_user(TARGET_NR_rt_sigreturn, (short *)(frame->retcode + 2));
3957 __put_user(0x20000001, (unsigned long *)(frame->retcode + 4));
3958 __put_user(0x15000000, (unsigned long *)(frame->retcode + 8));
Jia Liud9627832012-07-20 15:50:52 +08003959
3960 if (err) {
3961 goto give_sigsegv;
3962 }
3963
3964 /* TODO what is the current->exec_domain stuff and invmap ? */
3965
3966 /* Set up registers for signal handler */
3967 env->pc = (unsigned long)ka->_sa_handler; /* what we enter NOW */
3968 env->gpr[9] = (unsigned long)return_ip; /* what we enter LATER */
3969 env->gpr[3] = (unsigned long)sig; /* arg 1: signo */
3970 env->gpr[4] = (unsigned long)&frame->info; /* arg 2: (siginfo_t*) */
3971 env->gpr[5] = (unsigned long)&frame->uc; /* arg 3: ucontext */
3972
3973 /* actually move the usp to reflect the stacked frame */
3974 env->gpr[1] = (unsigned long)frame;
3975
3976 return;
3977
3978give_sigsegv:
3979 unlock_user_struct(frame, frame_addr, 1);
3980 if (sig == TARGET_SIGSEGV) {
3981 ka->_sa_handler = TARGET_SIG_DFL;
3982 }
3983 force_sig(TARGET_SIGSEGV);
3984}
3985
3986long do_sigreturn(CPUOpenRISCState *env)
3987{
3988
3989 qemu_log("do_sigreturn: not implemented\n");
3990 return -TARGET_ENOSYS;
3991}
3992
3993long do_rt_sigreturn(CPUOpenRISCState *env)
3994{
3995 qemu_log("do_rt_sigreturn: not implemented\n");
3996 return -TARGET_ENOSYS;
3997}
3998/* TARGET_OPENRISC */
3999
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004000#elif defined(TARGET_S390X)
4001
4002#define __NUM_GPRS 16
4003#define __NUM_FPRS 16
4004#define __NUM_ACRS 16
4005
4006#define S390_SYSCALL_SIZE 2
4007#define __SIGNAL_FRAMESIZE 160 /* FIXME: 31-bit mode -> 96 */
4008
4009#define _SIGCONTEXT_NSIG 64
4010#define _SIGCONTEXT_NSIG_BPW 64 /* FIXME: 31-bit mode -> 32 */
4011#define _SIGCONTEXT_NSIG_WORDS (_SIGCONTEXT_NSIG / _SIGCONTEXT_NSIG_BPW)
4012#define _SIGMASK_COPY_SIZE (sizeof(unsigned long)*_SIGCONTEXT_NSIG_WORDS)
4013#define PSW_ADDR_AMODE 0x0000000000000000UL /* 0x80000000UL for 31-bit */
4014#define S390_SYSCALL_OPCODE ((uint16_t)0x0a00)
4015
4016typedef struct {
4017 target_psw_t psw;
4018 target_ulong gprs[__NUM_GPRS];
4019 unsigned int acrs[__NUM_ACRS];
4020} target_s390_regs_common;
4021
4022typedef struct {
4023 unsigned int fpc;
4024 double fprs[__NUM_FPRS];
4025} target_s390_fp_regs;
4026
4027typedef struct {
4028 target_s390_regs_common regs;
4029 target_s390_fp_regs fpregs;
4030} target_sigregs;
4031
4032struct target_sigcontext {
4033 target_ulong oldmask[_SIGCONTEXT_NSIG_WORDS];
4034 target_sigregs *sregs;
4035};
4036
4037typedef struct {
4038 uint8_t callee_used_stack[__SIGNAL_FRAMESIZE];
4039 struct target_sigcontext sc;
4040 target_sigregs sregs;
4041 int signo;
4042 uint8_t retcode[S390_SYSCALL_SIZE];
4043} sigframe;
4044
4045struct target_ucontext {
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004046 target_ulong tuc_flags;
4047 struct target_ucontext *tuc_link;
4048 target_stack_t tuc_stack;
4049 target_sigregs tuc_mcontext;
4050 target_sigset_t tuc_sigmask; /* mask last for extensibility */
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004051};
4052
4053typedef struct {
4054 uint8_t callee_used_stack[__SIGNAL_FRAMESIZE];
4055 uint8_t retcode[S390_SYSCALL_SIZE];
4056 struct target_siginfo info;
4057 struct target_ucontext uc;
4058} rt_sigframe;
4059
4060static inline abi_ulong
Andreas Färber05390242012-02-25 03:37:53 +01004061get_sigframe(struct target_sigaction *ka, CPUS390XState *env, size_t frame_size)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004062{
4063 abi_ulong sp;
4064
4065 /* Default to using normal stack */
4066 sp = env->regs[15];
4067
4068 /* This is the X/Open sanctioned signal stack switching. */
4069 if (ka->sa_flags & TARGET_SA_ONSTACK) {
4070 if (!sas_ss_flags(sp)) {
4071 sp = target_sigaltstack_used.ss_sp +
4072 target_sigaltstack_used.ss_size;
4073 }
4074 }
4075
4076 /* This is the legacy signal stack switching. */
4077 else if (/* FIXME !user_mode(regs) */ 0 &&
4078 !(ka->sa_flags & TARGET_SA_RESTORER) &&
4079 ka->sa_restorer) {
4080 sp = (abi_ulong) ka->sa_restorer;
4081 }
4082
4083 return (sp - frame_size) & -8ul;
4084}
4085
Andreas Färber05390242012-02-25 03:37:53 +01004086static void save_sigregs(CPUS390XState *env, target_sigregs *sregs)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004087{
4088 int i;
4089 //save_access_regs(current->thread.acrs); FIXME
4090
4091 /* Copy a 'clean' PSW mask to the user to avoid leaking
4092 information about whether PER is currently on. */
4093 __put_user(env->psw.mask, &sregs->regs.psw.mask);
4094 __put_user(env->psw.addr, &sregs->regs.psw.addr);
4095 for (i = 0; i < 16; i++) {
4096 __put_user(env->regs[i], &sregs->regs.gprs[i]);
4097 }
4098 for (i = 0; i < 16; i++) {
4099 __put_user(env->aregs[i], &sregs->regs.acrs[i]);
4100 }
4101 /*
4102 * We have to store the fp registers to current->thread.fp_regs
4103 * to merge them with the emulated registers.
4104 */
4105 //save_fp_regs(&current->thread.fp_regs); FIXME
4106 for (i = 0; i < 16; i++) {
4107 __put_user(env->fregs[i].ll, &sregs->fpregs.fprs[i]);
4108 }
4109}
4110
4111static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01004112 target_sigset_t *set, CPUS390XState *env)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004113{
4114 sigframe *frame;
4115 abi_ulong frame_addr;
4116
4117 frame_addr = get_sigframe(ka, env, sizeof(*frame));
4118 qemu_log("%s: frame_addr 0x%llx\n", __FUNCTION__,
4119 (unsigned long long)frame_addr);
4120 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
4121 goto give_sigsegv;
4122 }
4123
4124 qemu_log("%s: 1\n", __FUNCTION__);
Riku Voipio0188fad2014-04-23 13:34:15 +03004125 __put_user(set->sig[0], &frame->sc.oldmask[0]);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004126
4127 save_sigregs(env, &frame->sregs);
4128
4129 __put_user((abi_ulong)(unsigned long)&frame->sregs,
4130 (abi_ulong *)&frame->sc.sregs);
4131
4132 /* Set up to return from userspace. If provided, use a stub
4133 already in userspace. */
4134 if (ka->sa_flags & TARGET_SA_RESTORER) {
4135 env->regs[14] = (unsigned long)
4136 ka->sa_restorer | PSW_ADDR_AMODE;
4137 } else {
4138 env->regs[14] = (unsigned long)
4139 frame->retcode | PSW_ADDR_AMODE;
Riku Voipio0188fad2014-04-23 13:34:15 +03004140 __put_user(S390_SYSCALL_OPCODE | TARGET_NR_sigreturn,
4141 (uint16_t *)(frame->retcode));
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004142 }
4143
4144 /* Set up backchain. */
Riku Voipio0188fad2014-04-23 13:34:15 +03004145 __put_user(env->regs[15], (abi_ulong *) frame);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004146
4147 /* Set up registers for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02004148 env->regs[15] = frame_addr;
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004149 env->psw.addr = (target_ulong) ka->_sa_handler | PSW_ADDR_AMODE;
4150
4151 env->regs[2] = sig; //map_signal(sig);
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02004152 env->regs[3] = frame_addr += offsetof(typeof(*frame), sc);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004153
4154 /* We forgot to include these in the sigcontext.
4155 To avoid breaking binary compatibility, they are passed as args. */
4156 env->regs[4] = 0; // FIXME: no clue... current->thread.trap_no;
4157 env->regs[5] = 0; // FIXME: no clue... current->thread.prot_addr;
4158
4159 /* Place signal number on stack to allow backtrace from handler. */
Riku Voipio0188fad2014-04-23 13:34:15 +03004160 __put_user(env->regs[2], (int *) &frame->signo);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004161 unlock_user_struct(frame, frame_addr, 1);
4162 return;
4163
4164give_sigsegv:
4165 qemu_log("%s: give_sigsegv\n", __FUNCTION__);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004166 force_sig(TARGET_SIGSEGV);
4167}
4168
4169static void setup_rt_frame(int sig, struct target_sigaction *ka,
4170 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01004171 target_sigset_t *set, CPUS390XState *env)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004172{
4173 int i;
4174 rt_sigframe *frame;
4175 abi_ulong frame_addr;
4176
4177 frame_addr = get_sigframe(ka, env, sizeof *frame);
4178 qemu_log("%s: frame_addr 0x%llx\n", __FUNCTION__,
4179 (unsigned long long)frame_addr);
4180 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
4181 goto give_sigsegv;
4182 }
4183
4184 qemu_log("%s: 1\n", __FUNCTION__);
Riku Voipiob0fd8d12014-04-23 10:46:13 +03004185 copy_siginfo_to_user(&frame->info, info);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004186
4187 /* Create the ucontext. */
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004188 __put_user(0, &frame->uc.tuc_flags);
4189 __put_user((abi_ulong)0, (abi_ulong *)&frame->uc.tuc_link);
4190 __put_user(target_sigaltstack_used.ss_sp, &frame->uc.tuc_stack.ss_sp);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004191 __put_user(sas_ss_flags(get_sp_from_cpustate(env)),
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004192 &frame->uc.tuc_stack.ss_flags);
4193 __put_user(target_sigaltstack_used.ss_size, &frame->uc.tuc_stack.ss_size);
4194 save_sigregs(env, &frame->uc.tuc_mcontext);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004195 for (i = 0; i < TARGET_NSIG_WORDS; i++) {
4196 __put_user((abi_ulong)set->sig[i],
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004197 (abi_ulong *)&frame->uc.tuc_sigmask.sig[i]);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004198 }
4199
4200 /* Set up to return from userspace. If provided, use a stub
4201 already in userspace. */
4202 if (ka->sa_flags & TARGET_SA_RESTORER) {
4203 env->regs[14] = (unsigned long) ka->sa_restorer | PSW_ADDR_AMODE;
4204 } else {
4205 env->regs[14] = (unsigned long) frame->retcode | PSW_ADDR_AMODE;
Riku Voipio0188fad2014-04-23 13:34:15 +03004206 __put_user(S390_SYSCALL_OPCODE | TARGET_NR_rt_sigreturn,
4207 (uint16_t *)(frame->retcode));
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004208 }
4209
4210 /* Set up backchain. */
Riku Voipio0188fad2014-04-23 13:34:15 +03004211 __put_user(env->regs[15], (abi_ulong *) frame);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004212
4213 /* Set up registers for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02004214 env->regs[15] = frame_addr;
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004215 env->psw.addr = (target_ulong) ka->_sa_handler | PSW_ADDR_AMODE;
4216
4217 env->regs[2] = sig; //map_signal(sig);
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02004218 env->regs[3] = frame_addr + offsetof(typeof(*frame), info);
4219 env->regs[4] = frame_addr + offsetof(typeof(*frame), uc);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004220 return;
4221
4222give_sigsegv:
4223 qemu_log("%s: give_sigsegv\n", __FUNCTION__);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004224 force_sig(TARGET_SIGSEGV);
4225}
4226
4227static int
Andreas Färber05390242012-02-25 03:37:53 +01004228restore_sigregs(CPUS390XState *env, target_sigregs *sc)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004229{
4230 int err = 0;
4231 int i;
4232
4233 for (i = 0; i < 16; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03004234 __get_user(env->regs[i], &sc->regs.gprs[i]);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004235 }
4236
Riku Voipio1d8b5122014-04-23 10:26:05 +03004237 __get_user(env->psw.mask, &sc->regs.psw.mask);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004238 qemu_log("%s: sc->regs.psw.addr 0x%llx env->psw.addr 0x%llx\n",
4239 __FUNCTION__, (unsigned long long)sc->regs.psw.addr,
4240 (unsigned long long)env->psw.addr);
Riku Voipio1d8b5122014-04-23 10:26:05 +03004241 __get_user(env->psw.addr, &sc->regs.psw.addr);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004242 /* FIXME: 31-bit -> | PSW_ADDR_AMODE */
4243
4244 for (i = 0; i < 16; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03004245 __get_user(env->aregs[i], &sc->regs.acrs[i]);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004246 }
4247 for (i = 0; i < 16; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03004248 __get_user(env->fregs[i].ll, &sc->fpregs.fprs[i]);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004249 }
4250
4251 return err;
4252}
4253
Andreas Färber05390242012-02-25 03:37:53 +01004254long do_sigreturn(CPUS390XState *env)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004255{
4256 sigframe *frame;
4257 abi_ulong frame_addr = env->regs[15];
4258 qemu_log("%s: frame_addr 0x%llx\n", __FUNCTION__,
4259 (unsigned long long)frame_addr);
4260 target_sigset_t target_set;
4261 sigset_t set;
4262
4263 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
4264 goto badframe;
4265 }
Riku Voipiof5f601a2014-04-23 13:00:17 +03004266 __get_user(target_set.sig[0], &frame->sc.oldmask[0]);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004267
4268 target_to_host_sigset_internal(&set, &target_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00004269 do_sigprocmask(SIG_SETMASK, &set, NULL); /* ~_BLOCKABLE? */
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004270
4271 if (restore_sigregs(env, &frame->sregs)) {
4272 goto badframe;
4273 }
4274
4275 unlock_user_struct(frame, frame_addr, 0);
4276 return env->regs[2];
4277
4278badframe:
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004279 force_sig(TARGET_SIGSEGV);
4280 return 0;
4281}
4282
Andreas Färber05390242012-02-25 03:37:53 +01004283long do_rt_sigreturn(CPUS390XState *env)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004284{
4285 rt_sigframe *frame;
4286 abi_ulong frame_addr = env->regs[15];
4287 qemu_log("%s: frame_addr 0x%llx\n", __FUNCTION__,
4288 (unsigned long long)frame_addr);
4289 sigset_t set;
4290
4291 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
4292 goto badframe;
4293 }
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004294 target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004295
Alex Barcelo1c275922014-03-14 14:36:55 +00004296 do_sigprocmask(SIG_SETMASK, &set, NULL); /* ~_BLOCKABLE? */
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004297
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004298 if (restore_sigregs(env, &frame->uc.tuc_mcontext)) {
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004299 goto badframe;
4300 }
4301
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004302 if (do_sigaltstack(frame_addr + offsetof(rt_sigframe, uc.tuc_stack), 0,
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004303 get_sp_from_cpustate(env)) == -EFAULT) {
4304 goto badframe;
4305 }
4306 unlock_user_struct(frame, frame_addr, 0);
4307 return env->regs[2];
4308
4309badframe:
4310 unlock_user_struct(frame, frame_addr, 0);
4311 force_sig(TARGET_SIGSEGV);
4312 return 0;
4313}
4314
Tom Musta61e75fe2014-06-30 08:13:38 -05004315#elif defined(TARGET_PPC)
Nathan Froydbcd49332009-05-12 19:13:18 -07004316
4317/* Size of dummy stack frame allocated when calling signal handler.
4318 See arch/powerpc/include/asm/ptrace.h. */
4319#if defined(TARGET_PPC64)
4320#define SIGNAL_FRAMESIZE 128
4321#else
4322#define SIGNAL_FRAMESIZE 64
4323#endif
4324
Tom Musta61e75fe2014-06-30 08:13:38 -05004325/* See arch/powerpc/include/asm/ucontext.h. Only used for 32-bit PPC;
4326 on 64-bit PPC, sigcontext and mcontext are one and the same. */
4327struct target_mcontext {
4328 target_ulong mc_gregs[48];
4329 /* Includes fpscr. */
4330 uint64_t mc_fregs[33];
4331 target_ulong mc_pad[2];
4332 /* We need to handle Altivec and SPE at the same time, which no
4333 kernel needs to do. Fortunately, the kernel defines this bit to
4334 be Altivec-register-large all the time, rather than trying to
4335 twiddle it based on the specific platform. */
4336 union {
4337 /* SPE vector registers. One extra for SPEFSCR. */
4338 uint32_t spe[33];
4339 /* Altivec vector registers. The packing of VSCR and VRSAVE
4340 varies depending on whether we're PPC64 or not: PPC64 splits
4341 them apart; PPC32 stuffs them together. */
4342#if defined(TARGET_PPC64)
4343#define QEMU_NVRREG 34
4344#else
4345#define QEMU_NVRREG 33
4346#endif
4347 ppc_avr_t altivec[QEMU_NVRREG];
4348#undef QEMU_NVRREG
4349 } mc_vregs __attribute__((__aligned__(16)));
4350};
4351
Nathan Froydbcd49332009-05-12 19:13:18 -07004352/* See arch/powerpc/include/asm/sigcontext.h. */
4353struct target_sigcontext {
4354 target_ulong _unused[4];
4355 int32_t signal;
4356#if defined(TARGET_PPC64)
4357 int32_t pad0;
4358#endif
4359 target_ulong handler;
4360 target_ulong oldmask;
4361 target_ulong regs; /* struct pt_regs __user * */
Tom Musta61e75fe2014-06-30 08:13:38 -05004362#if defined(TARGET_PPC64)
4363 struct target_mcontext mcontext;
4364#endif
Nathan Froydbcd49332009-05-12 19:13:18 -07004365};
4366
4367/* Indices for target_mcontext.mc_gregs, below.
4368 See arch/powerpc/include/asm/ptrace.h for details. */
4369enum {
4370 TARGET_PT_R0 = 0,
4371 TARGET_PT_R1 = 1,
4372 TARGET_PT_R2 = 2,
4373 TARGET_PT_R3 = 3,
4374 TARGET_PT_R4 = 4,
4375 TARGET_PT_R5 = 5,
4376 TARGET_PT_R6 = 6,
4377 TARGET_PT_R7 = 7,
4378 TARGET_PT_R8 = 8,
4379 TARGET_PT_R9 = 9,
4380 TARGET_PT_R10 = 10,
4381 TARGET_PT_R11 = 11,
4382 TARGET_PT_R12 = 12,
4383 TARGET_PT_R13 = 13,
4384 TARGET_PT_R14 = 14,
4385 TARGET_PT_R15 = 15,
4386 TARGET_PT_R16 = 16,
4387 TARGET_PT_R17 = 17,
4388 TARGET_PT_R18 = 18,
4389 TARGET_PT_R19 = 19,
4390 TARGET_PT_R20 = 20,
4391 TARGET_PT_R21 = 21,
4392 TARGET_PT_R22 = 22,
4393 TARGET_PT_R23 = 23,
4394 TARGET_PT_R24 = 24,
4395 TARGET_PT_R25 = 25,
4396 TARGET_PT_R26 = 26,
4397 TARGET_PT_R27 = 27,
4398 TARGET_PT_R28 = 28,
4399 TARGET_PT_R29 = 29,
4400 TARGET_PT_R30 = 30,
4401 TARGET_PT_R31 = 31,
4402 TARGET_PT_NIP = 32,
4403 TARGET_PT_MSR = 33,
4404 TARGET_PT_ORIG_R3 = 34,
4405 TARGET_PT_CTR = 35,
4406 TARGET_PT_LNK = 36,
4407 TARGET_PT_XER = 37,
4408 TARGET_PT_CCR = 38,
4409 /* Yes, there are two registers with #39. One is 64-bit only. */
4410 TARGET_PT_MQ = 39,
4411 TARGET_PT_SOFTE = 39,
4412 TARGET_PT_TRAP = 40,
4413 TARGET_PT_DAR = 41,
4414 TARGET_PT_DSISR = 42,
4415 TARGET_PT_RESULT = 43,
4416 TARGET_PT_REGS_COUNT = 44
4417};
4418
Nathan Froydbcd49332009-05-12 19:13:18 -07004419
4420struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02004421 target_ulong tuc_flags;
4422 target_ulong tuc_link; /* struct ucontext __user * */
4423 struct target_sigaltstack tuc_stack;
Nathan Froydbcd49332009-05-12 19:13:18 -07004424#if !defined(TARGET_PPC64)
Aurelien Jarno60e99242010-03-29 02:12:51 +02004425 int32_t tuc_pad[7];
4426 target_ulong tuc_regs; /* struct mcontext __user *
Nathan Froydbcd49332009-05-12 19:13:18 -07004427 points to uc_mcontext field */
4428#endif
Aurelien Jarno60e99242010-03-29 02:12:51 +02004429 target_sigset_t tuc_sigmask;
Nathan Froydbcd49332009-05-12 19:13:18 -07004430#if defined(TARGET_PPC64)
Anthony Liguoric227f092009-10-01 16:12:16 -05004431 target_sigset_t unused[15]; /* Allow for uc_sigmask growth */
Tom Musta61e75fe2014-06-30 08:13:38 -05004432 struct target_sigcontext tuc_sigcontext;
Nathan Froydbcd49332009-05-12 19:13:18 -07004433#else
Aurelien Jarno60e99242010-03-29 02:12:51 +02004434 int32_t tuc_maskext[30];
4435 int32_t tuc_pad2[3];
4436 struct target_mcontext tuc_mcontext;
Nathan Froydbcd49332009-05-12 19:13:18 -07004437#endif
4438};
4439
4440/* See arch/powerpc/kernel/signal_32.c. */
4441struct target_sigframe {
4442 struct target_sigcontext sctx;
4443 struct target_mcontext mctx;
4444 int32_t abigap[56];
4445};
4446
Tom Musta61e75fe2014-06-30 08:13:38 -05004447#if defined(TARGET_PPC64)
4448
4449#define TARGET_TRAMP_SIZE 6
4450
4451struct target_rt_sigframe {
4452 /* sys_rt_sigreturn requires the ucontext be the first field */
4453 struct target_ucontext uc;
4454 target_ulong _unused[2];
4455 uint32_t trampoline[TARGET_TRAMP_SIZE];
4456 target_ulong pinfo; /* struct siginfo __user * */
4457 target_ulong puc; /* void __user * */
4458 struct target_siginfo info;
4459 /* 64 bit ABI allows for 288 bytes below sp before decrementing it. */
4460 char abigap[288];
4461} __attribute__((aligned(16)));
4462
4463#else
4464
Nathan Froydbcd49332009-05-12 19:13:18 -07004465struct target_rt_sigframe {
4466 struct target_siginfo info;
4467 struct target_ucontext uc;
4468 int32_t abigap[56];
4469};
4470
Tom Musta61e75fe2014-06-30 08:13:38 -05004471#endif
4472
Tom Musta8d6ab332014-06-30 08:13:39 -05004473#if defined(TARGET_PPC64)
4474
4475struct target_func_ptr {
4476 target_ulong entry;
4477 target_ulong toc;
4478};
4479
4480#endif
4481
Nathan Froydbcd49332009-05-12 19:13:18 -07004482/* We use the mc_pad field for the signal return trampoline. */
4483#define tramp mc_pad
4484
4485/* See arch/powerpc/kernel/signal.c. */
4486static target_ulong get_sigframe(struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01004487 CPUPPCState *env,
Nathan Froydbcd49332009-05-12 19:13:18 -07004488 int frame_size)
4489{
4490 target_ulong oldsp, newsp;
4491
4492 oldsp = env->gpr[1];
4493
4494 if ((ka->sa_flags & TARGET_SA_ONSTACK) &&
Alex Barcelo32a20032012-02-09 23:55:46 +00004495 (sas_ss_flags(oldsp) == 0)) {
Nathan Froydbcd49332009-05-12 19:13:18 -07004496 oldsp = (target_sigaltstack_used.ss_sp
4497 + target_sigaltstack_used.ss_size);
4498 }
4499
4500 newsp = (oldsp - frame_size) & ~0xFUL;
4501
4502 return newsp;
4503}
4504
Tom Musta76781082014-06-30 08:13:37 -05004505static void save_user_regs(CPUPPCState *env, struct target_mcontext *frame)
Nathan Froydbcd49332009-05-12 19:13:18 -07004506{
4507 target_ulong msr = env->msr;
4508 int i;
4509 target_ulong ccr = 0;
4510
4511 /* In general, the kernel attempts to be intelligent about what it
4512 needs to save for Altivec/FP/SPE registers. We don't care that
4513 much, so we just go ahead and save everything. */
4514
4515 /* Save general registers. */
4516 for (i = 0; i < ARRAY_SIZE(env->gpr); i++) {
Riku Voipioc650c002014-04-23 13:53:45 +03004517 __put_user(env->gpr[i], &frame->mc_gregs[i]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004518 }
Riku Voipioc650c002014-04-23 13:53:45 +03004519 __put_user(env->nip, &frame->mc_gregs[TARGET_PT_NIP]);
4520 __put_user(env->ctr, &frame->mc_gregs[TARGET_PT_CTR]);
4521 __put_user(env->lr, &frame->mc_gregs[TARGET_PT_LNK]);
4522 __put_user(env->xer, &frame->mc_gregs[TARGET_PT_XER]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004523
4524 for (i = 0; i < ARRAY_SIZE(env->crf); i++) {
4525 ccr |= env->crf[i] << (32 - ((i + 1) * 4));
4526 }
Riku Voipioc650c002014-04-23 13:53:45 +03004527 __put_user(ccr, &frame->mc_gregs[TARGET_PT_CCR]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004528
4529 /* Save Altivec registers if necessary. */
4530 if (env->insns_flags & PPC_ALTIVEC) {
4531 for (i = 0; i < ARRAY_SIZE(env->avr); i++) {
Anthony Liguoric227f092009-10-01 16:12:16 -05004532 ppc_avr_t *avr = &env->avr[i];
4533 ppc_avr_t *vreg = &frame->mc_vregs.altivec[i];
Nathan Froydbcd49332009-05-12 19:13:18 -07004534
Riku Voipioc650c002014-04-23 13:53:45 +03004535 __put_user(avr->u64[0], &vreg->u64[0]);
4536 __put_user(avr->u64[1], &vreg->u64[1]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004537 }
4538 /* Set MSR_VR in the saved MSR value to indicate that
4539 frame->mc_vregs contains valid data. */
4540 msr |= MSR_VR;
Riku Voipioc650c002014-04-23 13:53:45 +03004541 __put_user((uint32_t)env->spr[SPR_VRSAVE],
4542 &frame->mc_vregs.altivec[32].u32[3]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004543 }
4544
4545 /* Save floating point registers. */
4546 if (env->insns_flags & PPC_FLOAT) {
4547 for (i = 0; i < ARRAY_SIZE(env->fpr); i++) {
Riku Voipioc650c002014-04-23 13:53:45 +03004548 __put_user(env->fpr[i], &frame->mc_fregs[i]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004549 }
Riku Voipioc650c002014-04-23 13:53:45 +03004550 __put_user((uint64_t) env->fpscr, &frame->mc_fregs[32]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004551 }
4552
4553 /* Save SPE registers. The kernel only saves the high half. */
4554 if (env->insns_flags & PPC_SPE) {
4555#if defined(TARGET_PPC64)
4556 for (i = 0; i < ARRAY_SIZE(env->gpr); i++) {
Riku Voipioc650c002014-04-23 13:53:45 +03004557 __put_user(env->gpr[i] >> 32, &frame->mc_vregs.spe[i]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004558 }
4559#else
4560 for (i = 0; i < ARRAY_SIZE(env->gprh); i++) {
Riku Voipioc650c002014-04-23 13:53:45 +03004561 __put_user(env->gprh[i], &frame->mc_vregs.spe[i]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004562 }
4563#endif
4564 /* Set MSR_SPE in the saved MSR value to indicate that
4565 frame->mc_vregs contains valid data. */
4566 msr |= MSR_SPE;
Riku Voipioc650c002014-04-23 13:53:45 +03004567 __put_user(env->spe_fscr, &frame->mc_vregs.spe[32]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004568 }
4569
4570 /* Store MSR. */
Riku Voipioc650c002014-04-23 13:53:45 +03004571 __put_user(msr, &frame->mc_gregs[TARGET_PT_MSR]);
Tom Musta76781082014-06-30 08:13:37 -05004572}
Nathan Froydbcd49332009-05-12 19:13:18 -07004573
Tom Musta76781082014-06-30 08:13:37 -05004574static void encode_trampoline(int sigret, uint32_t *tramp)
4575{
Nathan Froydbcd49332009-05-12 19:13:18 -07004576 /* Set up the sigreturn trampoline: li r0,sigret; sc. */
4577 if (sigret) {
Tom Musta76781082014-06-30 08:13:37 -05004578 __put_user(0x38000000 | sigret, &tramp[0]);
4579 __put_user(0x44000002, &tramp[1]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004580 }
Nathan Froydbcd49332009-05-12 19:13:18 -07004581}
4582
Riku Voipioc650c002014-04-23 13:53:45 +03004583static void restore_user_regs(CPUPPCState *env,
4584 struct target_mcontext *frame, int sig)
Nathan Froydbcd49332009-05-12 19:13:18 -07004585{
4586 target_ulong save_r2 = 0;
4587 target_ulong msr;
4588 target_ulong ccr;
4589
4590 int i;
4591
4592 if (!sig) {
4593 save_r2 = env->gpr[2];
4594 }
4595
4596 /* Restore general registers. */
4597 for (i = 0; i < ARRAY_SIZE(env->gpr); i++) {
Riku Voipioc650c002014-04-23 13:53:45 +03004598 __get_user(env->gpr[i], &frame->mc_gregs[i]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004599 }
Riku Voipioc650c002014-04-23 13:53:45 +03004600 __get_user(env->nip, &frame->mc_gregs[TARGET_PT_NIP]);
4601 __get_user(env->ctr, &frame->mc_gregs[TARGET_PT_CTR]);
4602 __get_user(env->lr, &frame->mc_gregs[TARGET_PT_LNK]);
4603 __get_user(env->xer, &frame->mc_gregs[TARGET_PT_XER]);
4604 __get_user(ccr, &frame->mc_gregs[TARGET_PT_CCR]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004605
4606 for (i = 0; i < ARRAY_SIZE(env->crf); i++) {
4607 env->crf[i] = (ccr >> (32 - ((i + 1) * 4))) & 0xf;
4608 }
4609
4610 if (!sig) {
4611 env->gpr[2] = save_r2;
4612 }
4613 /* Restore MSR. */
Riku Voipioc650c002014-04-23 13:53:45 +03004614 __get_user(msr, &frame->mc_gregs[TARGET_PT_MSR]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004615
4616 /* If doing signal return, restore the previous little-endian mode. */
4617 if (sig)
4618 env->msr = (env->msr & ~MSR_LE) | (msr & MSR_LE);
4619
4620 /* Restore Altivec registers if necessary. */
4621 if (env->insns_flags & PPC_ALTIVEC) {
4622 for (i = 0; i < ARRAY_SIZE(env->avr); i++) {
Anthony Liguoric227f092009-10-01 16:12:16 -05004623 ppc_avr_t *avr = &env->avr[i];
4624 ppc_avr_t *vreg = &frame->mc_vregs.altivec[i];
Nathan Froydbcd49332009-05-12 19:13:18 -07004625
Riku Voipioc650c002014-04-23 13:53:45 +03004626 __get_user(avr->u64[0], &vreg->u64[0]);
4627 __get_user(avr->u64[1], &vreg->u64[1]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004628 }
4629 /* Set MSR_VEC in the saved MSR value to indicate that
4630 frame->mc_vregs contains valid data. */
Riku Voipioc650c002014-04-23 13:53:45 +03004631 __get_user(env->spr[SPR_VRSAVE],
4632 (target_ulong *)(&frame->mc_vregs.altivec[32].u32[3]));
Nathan Froydbcd49332009-05-12 19:13:18 -07004633 }
4634
4635 /* Restore floating point registers. */
4636 if (env->insns_flags & PPC_FLOAT) {
4637 uint64_t fpscr;
4638 for (i = 0; i < ARRAY_SIZE(env->fpr); i++) {
Riku Voipioc650c002014-04-23 13:53:45 +03004639 __get_user(env->fpr[i], &frame->mc_fregs[i]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004640 }
Riku Voipioc650c002014-04-23 13:53:45 +03004641 __get_user(fpscr, &frame->mc_fregs[32]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004642 env->fpscr = (uint32_t) fpscr;
4643 }
4644
4645 /* Save SPE registers. The kernel only saves the high half. */
4646 if (env->insns_flags & PPC_SPE) {
4647#if defined(TARGET_PPC64)
4648 for (i = 0; i < ARRAY_SIZE(env->gpr); i++) {
4649 uint32_t hi;
4650
Riku Voipioc650c002014-04-23 13:53:45 +03004651 __get_user(hi, &frame->mc_vregs.spe[i]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004652 env->gpr[i] = ((uint64_t)hi << 32) | ((uint32_t) env->gpr[i]);
4653 }
4654#else
4655 for (i = 0; i < ARRAY_SIZE(env->gprh); i++) {
Riku Voipioc650c002014-04-23 13:53:45 +03004656 __get_user(env->gprh[i], &frame->mc_vregs.spe[i]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004657 }
4658#endif
Riku Voipioc650c002014-04-23 13:53:45 +03004659 __get_user(env->spe_fscr, &frame->mc_vregs.spe[32]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004660 }
Nathan Froydbcd49332009-05-12 19:13:18 -07004661}
4662
4663static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01004664 target_sigset_t *set, CPUPPCState *env)
Nathan Froydbcd49332009-05-12 19:13:18 -07004665{
4666 struct target_sigframe *frame;
4667 struct target_sigcontext *sc;
4668 target_ulong frame_addr, newsp;
4669 int err = 0;
Tom Musta14585582014-06-30 08:13:42 -05004670#if defined(TARGET_PPC64)
4671 struct image_info *image = ((TaskState *)thread_cpu->opaque)->info;
4672#endif
Nathan Froydbcd49332009-05-12 19:13:18 -07004673
4674 frame_addr = get_sigframe(ka, env, sizeof(*frame));
4675 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 1))
4676 goto sigsegv;
4677 sc = &frame->sctx;
4678
Riku Voipio1d8b5122014-04-23 10:26:05 +03004679 __put_user(ka->_sa_handler, &sc->handler);
4680 __put_user(set->sig[0], &sc->oldmask);
Tom Musta61e75fe2014-06-30 08:13:38 -05004681#if TARGET_ABI_BITS == 64
Riku Voipio1d8b5122014-04-23 10:26:05 +03004682 __put_user(set->sig[0] >> 32, &sc->_unused[3]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004683#else
Riku Voipio1d8b5122014-04-23 10:26:05 +03004684 __put_user(set->sig[1], &sc->_unused[3]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004685#endif
Riku Voipio1d8b5122014-04-23 10:26:05 +03004686 __put_user(h2g(&frame->mctx), &sc->regs);
4687 __put_user(sig, &sc->signal);
Nathan Froydbcd49332009-05-12 19:13:18 -07004688
4689 /* Save user regs. */
Tom Musta76781082014-06-30 08:13:37 -05004690 save_user_regs(env, &frame->mctx);
4691
4692 /* Construct the trampoline code on the stack. */
4693 encode_trampoline(TARGET_NR_sigreturn, (uint32_t *)&frame->mctx.tramp);
Nathan Froydbcd49332009-05-12 19:13:18 -07004694
4695 /* The kernel checks for the presence of a VDSO here. We don't
4696 emulate a vdso, so use a sigreturn system call. */
4697 env->lr = (target_ulong) h2g(frame->mctx.tramp);
4698
4699 /* Turn off all fp exceptions. */
4700 env->fpscr = 0;
4701
4702 /* Create a stack frame for the caller of the handler. */
4703 newsp = frame_addr - SIGNAL_FRAMESIZE;
Samuel Seaybeb526b2013-01-02 10:53:46 +00004704 err |= put_user(env->gpr[1], newsp, target_ulong);
Nathan Froydbcd49332009-05-12 19:13:18 -07004705
4706 if (err)
4707 goto sigsegv;
4708
4709 /* Set up registers for signal handler. */
4710 env->gpr[1] = newsp;
Peter Maydellb6e2c932015-01-08 12:19:43 +00004711 env->gpr[3] = sig;
Samuel Seay61993a62013-01-04 14:35:48 +00004712 env->gpr[4] = frame_addr + offsetof(struct target_sigframe, sctx);
Tom Musta8d6ab332014-06-30 08:13:39 -05004713
4714#if defined(TARGET_PPC64)
Tom Musta14585582014-06-30 08:13:42 -05004715 if (get_ppc64_abi(image) < 2) {
4716 /* ELFv1 PPC64 function pointers are pointers to OPD entries. */
4717 struct target_func_ptr *handler =
4718 (struct target_func_ptr *)g2h(ka->_sa_handler);
4719 env->nip = tswapl(handler->entry);
4720 env->gpr[2] = tswapl(handler->toc);
4721 } else {
4722 /* ELFv2 PPC64 function pointers are entry points, but R12
4723 * must also be set */
4724 env->nip = tswapl((target_ulong) ka->_sa_handler);
4725 env->gpr[12] = env->nip;
4726 }
Tom Musta8d6ab332014-06-30 08:13:39 -05004727#else
Nathan Froydbcd49332009-05-12 19:13:18 -07004728 env->nip = (target_ulong) ka->_sa_handler;
Tom Musta8d6ab332014-06-30 08:13:39 -05004729#endif
4730
Nathan Froydbcd49332009-05-12 19:13:18 -07004731 /* Signal handlers are entered in big-endian mode. */
4732 env->msr &= ~MSR_LE;
4733
4734 unlock_user_struct(frame, frame_addr, 1);
4735 return;
4736
4737sigsegv:
4738 unlock_user_struct(frame, frame_addr, 1);
Blue Swirleeacee42012-06-03 16:35:32 +00004739 qemu_log("segfaulting from setup_frame\n");
Riku Voipio66393fb2009-12-04 15:16:32 +02004740 force_sig(TARGET_SIGSEGV);
Nathan Froydbcd49332009-05-12 19:13:18 -07004741}
4742
4743static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05004744 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01004745 target_sigset_t *set, CPUPPCState *env)
Nathan Froydbcd49332009-05-12 19:13:18 -07004746{
4747 struct target_rt_sigframe *rt_sf;
Tom Musta61e75fe2014-06-30 08:13:38 -05004748 uint32_t *trampptr = 0;
4749 struct target_mcontext *mctx = 0;
Nathan Froydbcd49332009-05-12 19:13:18 -07004750 target_ulong rt_sf_addr, newsp = 0;
4751 int i, err = 0;
Tom Musta14585582014-06-30 08:13:42 -05004752#if defined(TARGET_PPC64)
4753 struct image_info *image = ((TaskState *)thread_cpu->opaque)->info;
4754#endif
Nathan Froydbcd49332009-05-12 19:13:18 -07004755
4756 rt_sf_addr = get_sigframe(ka, env, sizeof(*rt_sf));
4757 if (!lock_user_struct(VERIFY_WRITE, rt_sf, rt_sf_addr, 1))
4758 goto sigsegv;
4759
Riku Voipiob0fd8d12014-04-23 10:46:13 +03004760 copy_siginfo_to_user(&rt_sf->info, info);
Nathan Froydbcd49332009-05-12 19:13:18 -07004761
Riku Voipio1d8b5122014-04-23 10:26:05 +03004762 __put_user(0, &rt_sf->uc.tuc_flags);
4763 __put_user(0, &rt_sf->uc.tuc_link);
4764 __put_user((target_ulong)target_sigaltstack_used.ss_sp,
4765 &rt_sf->uc.tuc_stack.ss_sp);
4766 __put_user(sas_ss_flags(env->gpr[1]),
4767 &rt_sf->uc.tuc_stack.ss_flags);
4768 __put_user(target_sigaltstack_used.ss_size,
4769 &rt_sf->uc.tuc_stack.ss_size);
Tom Musta61e75fe2014-06-30 08:13:38 -05004770#if !defined(TARGET_PPC64)
Riku Voipio1d8b5122014-04-23 10:26:05 +03004771 __put_user(h2g (&rt_sf->uc.tuc_mcontext),
4772 &rt_sf->uc.tuc_regs);
Tom Musta61e75fe2014-06-30 08:13:38 -05004773#endif
Nathan Froydbcd49332009-05-12 19:13:18 -07004774 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03004775 __put_user(set->sig[i], &rt_sf->uc.tuc_sigmask.sig[i]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004776 }
4777
Tom Musta61e75fe2014-06-30 08:13:38 -05004778#if defined(TARGET_PPC64)
4779 mctx = &rt_sf->uc.tuc_sigcontext.mcontext;
4780 trampptr = &rt_sf->trampoline[0];
4781#else
4782 mctx = &rt_sf->uc.tuc_mcontext;
4783 trampptr = (uint32_t *)&rt_sf->uc.tuc_mcontext.tramp;
4784#endif
4785
4786 save_user_regs(env, mctx);
4787 encode_trampoline(TARGET_NR_rt_sigreturn, trampptr);
Nathan Froydbcd49332009-05-12 19:13:18 -07004788
4789 /* The kernel checks for the presence of a VDSO here. We don't
4790 emulate a vdso, so use a sigreturn system call. */
Tom Musta61e75fe2014-06-30 08:13:38 -05004791 env->lr = (target_ulong) h2g(trampptr);
Nathan Froydbcd49332009-05-12 19:13:18 -07004792
4793 /* Turn off all fp exceptions. */
4794 env->fpscr = 0;
4795
4796 /* Create a stack frame for the caller of the handler. */
4797 newsp = rt_sf_addr - (SIGNAL_FRAMESIZE + 16);
Tom Mustafbdc2002014-06-30 08:13:36 -05004798 err |= put_user(env->gpr[1], newsp, target_ulong);
Nathan Froydbcd49332009-05-12 19:13:18 -07004799
4800 if (err)
4801 goto sigsegv;
4802
4803 /* Set up registers for signal handler. */
4804 env->gpr[1] = newsp;
Peter Maydellb6e2c932015-01-08 12:19:43 +00004805 env->gpr[3] = (target_ulong) sig;
Nathan Froydbcd49332009-05-12 19:13:18 -07004806 env->gpr[4] = (target_ulong) h2g(&rt_sf->info);
4807 env->gpr[5] = (target_ulong) h2g(&rt_sf->uc);
4808 env->gpr[6] = (target_ulong) h2g(rt_sf);
Tom Musta8d6ab332014-06-30 08:13:39 -05004809
4810#if defined(TARGET_PPC64)
Tom Musta14585582014-06-30 08:13:42 -05004811 if (get_ppc64_abi(image) < 2) {
4812 /* ELFv1 PPC64 function pointers are pointers to OPD entries. */
4813 struct target_func_ptr *handler =
4814 (struct target_func_ptr *)g2h(ka->_sa_handler);
4815 env->nip = tswapl(handler->entry);
4816 env->gpr[2] = tswapl(handler->toc);
4817 } else {
4818 /* ELFv2 PPC64 function pointers are entry points, but R12
4819 * must also be set */
4820 env->nip = tswapl((target_ulong) ka->_sa_handler);
4821 env->gpr[12] = env->nip;
4822 }
Tom Musta8d6ab332014-06-30 08:13:39 -05004823#else
Nathan Froydbcd49332009-05-12 19:13:18 -07004824 env->nip = (target_ulong) ka->_sa_handler;
Tom Musta8d6ab332014-06-30 08:13:39 -05004825#endif
4826
Nathan Froydbcd49332009-05-12 19:13:18 -07004827 /* Signal handlers are entered in big-endian mode. */
4828 env->msr &= ~MSR_LE;
4829
4830 unlock_user_struct(rt_sf, rt_sf_addr, 1);
4831 return;
4832
4833sigsegv:
4834 unlock_user_struct(rt_sf, rt_sf_addr, 1);
Blue Swirleeacee42012-06-03 16:35:32 +00004835 qemu_log("segfaulting from setup_rt_frame\n");
Riku Voipio66393fb2009-12-04 15:16:32 +02004836 force_sig(TARGET_SIGSEGV);
Nathan Froydbcd49332009-05-12 19:13:18 -07004837
4838}
4839
Andreas Färber05390242012-02-25 03:37:53 +01004840long do_sigreturn(CPUPPCState *env)
Nathan Froydbcd49332009-05-12 19:13:18 -07004841{
4842 struct target_sigcontext *sc = NULL;
4843 struct target_mcontext *sr = NULL;
Peter Maydellb04636f2013-07-29 12:00:31 +01004844 target_ulong sr_addr = 0, sc_addr;
Nathan Froydbcd49332009-05-12 19:13:18 -07004845 sigset_t blocked;
Anthony Liguoric227f092009-10-01 16:12:16 -05004846 target_sigset_t set;
Nathan Froydbcd49332009-05-12 19:13:18 -07004847
4848 sc_addr = env->gpr[1] + SIGNAL_FRAMESIZE;
4849 if (!lock_user_struct(VERIFY_READ, sc, sc_addr, 1))
4850 goto sigsegv;
4851
4852#if defined(TARGET_PPC64)
Tom Musta61e75fe2014-06-30 08:13:38 -05004853 set.sig[0] = sc->oldmask + ((uint64_t)(sc->_unused[3]) << 32);
Nathan Froydbcd49332009-05-12 19:13:18 -07004854#else
Riku Voipiof5f601a2014-04-23 13:00:17 +03004855 __get_user(set.sig[0], &sc->oldmask);
4856 __get_user(set.sig[1], &sc->_unused[3]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004857#endif
4858 target_to_host_sigset_internal(&blocked, &set);
Alex Barcelo1c275922014-03-14 14:36:55 +00004859 do_sigprocmask(SIG_SETMASK, &blocked, NULL);
Nathan Froydbcd49332009-05-12 19:13:18 -07004860
Riku Voipiof5f601a2014-04-23 13:00:17 +03004861 __get_user(sr_addr, &sc->regs);
Nathan Froydbcd49332009-05-12 19:13:18 -07004862 if (!lock_user_struct(VERIFY_READ, sr, sr_addr, 1))
4863 goto sigsegv;
Riku Voipioc650c002014-04-23 13:53:45 +03004864 restore_user_regs(env, sr, 1);
Nathan Froydbcd49332009-05-12 19:13:18 -07004865
4866 unlock_user_struct(sr, sr_addr, 1);
4867 unlock_user_struct(sc, sc_addr, 1);
4868 return -TARGET_QEMU_ESIGRETURN;
4869
4870sigsegv:
4871 unlock_user_struct(sr, sr_addr, 1);
4872 unlock_user_struct(sc, sc_addr, 1);
Blue Swirleeacee42012-06-03 16:35:32 +00004873 qemu_log("segfaulting from do_sigreturn\n");
Riku Voipio66393fb2009-12-04 15:16:32 +02004874 force_sig(TARGET_SIGSEGV);
Nathan Froydbcd49332009-05-12 19:13:18 -07004875 return 0;
4876}
4877
4878/* See arch/powerpc/kernel/signal_32.c. */
Andreas Färber05390242012-02-25 03:37:53 +01004879static int do_setcontext(struct target_ucontext *ucp, CPUPPCState *env, int sig)
Nathan Froydbcd49332009-05-12 19:13:18 -07004880{
4881 struct target_mcontext *mcp;
4882 target_ulong mcp_addr;
4883 sigset_t blocked;
Anthony Liguoric227f092009-10-01 16:12:16 -05004884 target_sigset_t set;
Nathan Froydbcd49332009-05-12 19:13:18 -07004885
Aurelien Jarno60e99242010-03-29 02:12:51 +02004886 if (copy_from_user(&set, h2g(ucp) + offsetof(struct target_ucontext, tuc_sigmask),
Nathan Froydbcd49332009-05-12 19:13:18 -07004887 sizeof (set)))
4888 return 1;
4889
Tom Musta19774ec2014-06-30 08:13:40 -05004890#if defined(TARGET_PPC64)
4891 mcp_addr = h2g(ucp) +
4892 offsetof(struct target_ucontext, tuc_sigcontext.mcontext);
4893#else
Riku Voipio9e918dc2014-04-23 14:05:09 +03004894 __get_user(mcp_addr, &ucp->tuc_regs);
Tom Musta19774ec2014-06-30 08:13:40 -05004895#endif
Nathan Froydbcd49332009-05-12 19:13:18 -07004896
4897 if (!lock_user_struct(VERIFY_READ, mcp, mcp_addr, 1))
4898 return 1;
4899
4900 target_to_host_sigset_internal(&blocked, &set);
Alex Barcelo1c275922014-03-14 14:36:55 +00004901 do_sigprocmask(SIG_SETMASK, &blocked, NULL);
Riku Voipioc650c002014-04-23 13:53:45 +03004902 restore_user_regs(env, mcp, sig);
Nathan Froydbcd49332009-05-12 19:13:18 -07004903
4904 unlock_user_struct(mcp, mcp_addr, 1);
4905 return 0;
Nathan Froydbcd49332009-05-12 19:13:18 -07004906}
4907
Andreas Färber05390242012-02-25 03:37:53 +01004908long do_rt_sigreturn(CPUPPCState *env)
Nathan Froydbcd49332009-05-12 19:13:18 -07004909{
4910 struct target_rt_sigframe *rt_sf = NULL;
4911 target_ulong rt_sf_addr;
4912
4913 rt_sf_addr = env->gpr[1] + SIGNAL_FRAMESIZE + 16;
4914 if (!lock_user_struct(VERIFY_READ, rt_sf, rt_sf_addr, 1))
4915 goto sigsegv;
4916
4917 if (do_setcontext(&rt_sf->uc, env, 1))
4918 goto sigsegv;
4919
4920 do_sigaltstack(rt_sf_addr
Aurelien Jarno60e99242010-03-29 02:12:51 +02004921 + offsetof(struct target_rt_sigframe, uc.tuc_stack),
Nathan Froydbcd49332009-05-12 19:13:18 -07004922 0, env->gpr[1]);
4923
4924 unlock_user_struct(rt_sf, rt_sf_addr, 1);
4925 return -TARGET_QEMU_ESIGRETURN;
4926
4927sigsegv:
4928 unlock_user_struct(rt_sf, rt_sf_addr, 1);
Blue Swirleeacee42012-06-03 16:35:32 +00004929 qemu_log("segfaulting from do_rt_sigreturn\n");
Riku Voipio66393fb2009-12-04 15:16:32 +02004930 force_sig(TARGET_SIGSEGV);
Nathan Froydbcd49332009-05-12 19:13:18 -07004931 return 0;
4932}
4933
Laurent Vivier492a8742009-08-03 16:12:17 +02004934#elif defined(TARGET_M68K)
4935
4936struct target_sigcontext {
4937 abi_ulong sc_mask;
4938 abi_ulong sc_usp;
4939 abi_ulong sc_d0;
4940 abi_ulong sc_d1;
4941 abi_ulong sc_a0;
4942 abi_ulong sc_a1;
4943 unsigned short sc_sr;
4944 abi_ulong sc_pc;
4945};
4946
4947struct target_sigframe
4948{
4949 abi_ulong pretcode;
4950 int sig;
4951 int code;
4952 abi_ulong psc;
4953 char retcode[8];
4954 abi_ulong extramask[TARGET_NSIG_WORDS-1];
4955 struct target_sigcontext sc;
4956};
Laurent Vivier71811552009-08-03 16:12:18 +02004957
Anthony Liguoric227f092009-10-01 16:12:16 -05004958typedef int target_greg_t;
Laurent Vivier71811552009-08-03 16:12:18 +02004959#define TARGET_NGREG 18
Anthony Liguoric227f092009-10-01 16:12:16 -05004960typedef target_greg_t target_gregset_t[TARGET_NGREG];
Laurent Vivier71811552009-08-03 16:12:18 +02004961
4962typedef struct target_fpregset {
4963 int f_fpcntl[3];
4964 int f_fpregs[8*3];
Anthony Liguoric227f092009-10-01 16:12:16 -05004965} target_fpregset_t;
Laurent Vivier71811552009-08-03 16:12:18 +02004966
4967struct target_mcontext {
4968 int version;
Anthony Liguoric227f092009-10-01 16:12:16 -05004969 target_gregset_t gregs;
4970 target_fpregset_t fpregs;
Laurent Vivier71811552009-08-03 16:12:18 +02004971};
4972
4973#define TARGET_MCONTEXT_VERSION 2
4974
4975struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02004976 abi_ulong tuc_flags;
4977 abi_ulong tuc_link;
4978 target_stack_t tuc_stack;
4979 struct target_mcontext tuc_mcontext;
4980 abi_long tuc_filler[80];
4981 target_sigset_t tuc_sigmask;
Laurent Vivier71811552009-08-03 16:12:18 +02004982};
4983
4984struct target_rt_sigframe
4985{
4986 abi_ulong pretcode;
4987 int sig;
4988 abi_ulong pinfo;
4989 abi_ulong puc;
4990 char retcode[8];
4991 struct target_siginfo info;
4992 struct target_ucontext uc;
4993};
Laurent Vivier492a8742009-08-03 16:12:17 +02004994
Riku Voipio41ecc722014-04-23 11:01:00 +03004995static void setup_sigcontext(struct target_sigcontext *sc, CPUM68KState *env,
4996 abi_ulong mask)
Laurent Vivier492a8742009-08-03 16:12:17 +02004997{
Riku Voipio1d8b5122014-04-23 10:26:05 +03004998 __put_user(mask, &sc->sc_mask);
4999 __put_user(env->aregs[7], &sc->sc_usp);
5000 __put_user(env->dregs[0], &sc->sc_d0);
5001 __put_user(env->dregs[1], &sc->sc_d1);
5002 __put_user(env->aregs[0], &sc->sc_a0);
5003 __put_user(env->aregs[1], &sc->sc_a1);
5004 __put_user(env->sr, &sc->sc_sr);
5005 __put_user(env->pc, &sc->sc_pc);
Laurent Vivier492a8742009-08-03 16:12:17 +02005006}
5007
Riku Voipio016d2e12014-04-23 11:19:48 +03005008static void
Andreas Färber05390242012-02-25 03:37:53 +01005009restore_sigcontext(CPUM68KState *env, struct target_sigcontext *sc, int *pd0)
Laurent Vivier492a8742009-08-03 16:12:17 +02005010{
Laurent Vivier492a8742009-08-03 16:12:17 +02005011 int temp;
5012
Riku Voipio1d8b5122014-04-23 10:26:05 +03005013 __get_user(env->aregs[7], &sc->sc_usp);
5014 __get_user(env->dregs[1], &sc->sc_d1);
5015 __get_user(env->aregs[0], &sc->sc_a0);
5016 __get_user(env->aregs[1], &sc->sc_a1);
5017 __get_user(env->pc, &sc->sc_pc);
5018 __get_user(temp, &sc->sc_sr);
Laurent Vivier492a8742009-08-03 16:12:17 +02005019 env->sr = (env->sr & 0xff00) | (temp & 0xff);
5020
5021 *pd0 = tswapl(sc->sc_d0);
Laurent Vivier492a8742009-08-03 16:12:17 +02005022}
5023
5024/*
5025 * Determine which stack to use..
5026 */
5027static inline abi_ulong
Andreas Färber05390242012-02-25 03:37:53 +01005028get_sigframe(struct target_sigaction *ka, CPUM68KState *regs,
5029 size_t frame_size)
Laurent Vivier492a8742009-08-03 16:12:17 +02005030{
5031 unsigned long sp;
5032
5033 sp = regs->aregs[7];
5034
5035 /* This is the X/Open sanctioned signal stack switching. */
5036 if ((ka->sa_flags & TARGET_SA_ONSTACK) && (sas_ss_flags (sp) == 0)) {
5037 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
5038 }
5039
5040 return ((sp - frame_size) & -8UL);
5041}
5042
5043static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01005044 target_sigset_t *set, CPUM68KState *env)
Laurent Vivier492a8742009-08-03 16:12:17 +02005045{
5046 struct target_sigframe *frame;
5047 abi_ulong frame_addr;
5048 abi_ulong retcode_addr;
5049 abi_ulong sc_addr;
Laurent Vivier492a8742009-08-03 16:12:17 +02005050 int i;
5051
5052 frame_addr = get_sigframe(ka, env, sizeof *frame);
5053 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
5054 goto give_sigsegv;
5055
Riku Voipio1d8b5122014-04-23 10:26:05 +03005056 __put_user(sig, &frame->sig);
Laurent Vivier492a8742009-08-03 16:12:17 +02005057
5058 sc_addr = frame_addr + offsetof(struct target_sigframe, sc);
Riku Voipio1d8b5122014-04-23 10:26:05 +03005059 __put_user(sc_addr, &frame->psc);
Laurent Vivier492a8742009-08-03 16:12:17 +02005060
Riku Voipio41ecc722014-04-23 11:01:00 +03005061 setup_sigcontext(&frame->sc, env, set->sig[0]);
Laurent Vivier492a8742009-08-03 16:12:17 +02005062
5063 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
Riku Voipio0188fad2014-04-23 13:34:15 +03005064 __put_user(set->sig[i], &frame->extramask[i - 1]);
Laurent Vivier492a8742009-08-03 16:12:17 +02005065 }
5066
5067 /* Set up to return from userspace. */
5068
5069 retcode_addr = frame_addr + offsetof(struct target_sigframe, retcode);
Riku Voipio1d8b5122014-04-23 10:26:05 +03005070 __put_user(retcode_addr, &frame->pretcode);
Laurent Vivier492a8742009-08-03 16:12:17 +02005071
5072 /* moveq #,d0; trap #0 */
5073
Riku Voipio1d8b5122014-04-23 10:26:05 +03005074 __put_user(0x70004e40 + (TARGET_NR_sigreturn << 16),
Laurent Vivier492a8742009-08-03 16:12:17 +02005075 (long *)(frame->retcode));
5076
Laurent Vivier492a8742009-08-03 16:12:17 +02005077 /* Set up to return from userspace */
5078
5079 env->aregs[7] = frame_addr;
5080 env->pc = ka->_sa_handler;
5081
5082 unlock_user_struct(frame, frame_addr, 1);
5083 return;
5084
5085give_sigsegv:
Riku Voipio66393fb2009-12-04 15:16:32 +02005086 force_sig(TARGET_SIGSEGV);
Laurent Vivier492a8742009-08-03 16:12:17 +02005087}
5088
Laurent Vivier71811552009-08-03 16:12:18 +02005089static inline int target_rt_setup_ucontext(struct target_ucontext *uc,
Andreas Färber05390242012-02-25 03:37:53 +01005090 CPUM68KState *env)
Laurent Vivier71811552009-08-03 16:12:18 +02005091{
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 __put_user(TARGET_MCONTEXT_VERSION, &uc->tuc_mcontext.version);
5095 __put_user(env->dregs[0], &gregs[0]);
5096 __put_user(env->dregs[1], &gregs[1]);
5097 __put_user(env->dregs[2], &gregs[2]);
5098 __put_user(env->dregs[3], &gregs[3]);
5099 __put_user(env->dregs[4], &gregs[4]);
5100 __put_user(env->dregs[5], &gregs[5]);
5101 __put_user(env->dregs[6], &gregs[6]);
5102 __put_user(env->dregs[7], &gregs[7]);
5103 __put_user(env->aregs[0], &gregs[8]);
5104 __put_user(env->aregs[1], &gregs[9]);
5105 __put_user(env->aregs[2], &gregs[10]);
5106 __put_user(env->aregs[3], &gregs[11]);
5107 __put_user(env->aregs[4], &gregs[12]);
5108 __put_user(env->aregs[5], &gregs[13]);
5109 __put_user(env->aregs[6], &gregs[14]);
5110 __put_user(env->aregs[7], &gregs[15]);
5111 __put_user(env->pc, &gregs[16]);
5112 __put_user(env->sr, &gregs[17]);
Laurent Vivier71811552009-08-03 16:12:18 +02005113
Riku Voipio1d8b5122014-04-23 10:26:05 +03005114 return 0;
Laurent Vivier71811552009-08-03 16:12:18 +02005115}
5116
Andreas Färber05390242012-02-25 03:37:53 +01005117static inline int target_rt_restore_ucontext(CPUM68KState *env,
Laurent Vivier71811552009-08-03 16:12:18 +02005118 struct target_ucontext *uc,
5119 int *pd0)
5120{
5121 int temp;
Aurelien Jarno60e99242010-03-29 02:12:51 +02005122 target_greg_t *gregs = uc->tuc_mcontext.gregs;
Laurent Vivier71811552009-08-03 16:12:18 +02005123
Riku Voipio1d8b5122014-04-23 10:26:05 +03005124 __get_user(temp, &uc->tuc_mcontext.version);
Laurent Vivier71811552009-08-03 16:12:18 +02005125 if (temp != TARGET_MCONTEXT_VERSION)
5126 goto badframe;
5127
5128 /* restore passed registers */
Riku Voipio1d8b5122014-04-23 10:26:05 +03005129 __get_user(env->dregs[0], &gregs[0]);
5130 __get_user(env->dregs[1], &gregs[1]);
5131 __get_user(env->dregs[2], &gregs[2]);
5132 __get_user(env->dregs[3], &gregs[3]);
5133 __get_user(env->dregs[4], &gregs[4]);
5134 __get_user(env->dregs[5], &gregs[5]);
5135 __get_user(env->dregs[6], &gregs[6]);
5136 __get_user(env->dregs[7], &gregs[7]);
5137 __get_user(env->aregs[0], &gregs[8]);
5138 __get_user(env->aregs[1], &gregs[9]);
5139 __get_user(env->aregs[2], &gregs[10]);
5140 __get_user(env->aregs[3], &gregs[11]);
5141 __get_user(env->aregs[4], &gregs[12]);
5142 __get_user(env->aregs[5], &gregs[13]);
5143 __get_user(env->aregs[6], &gregs[14]);
5144 __get_user(env->aregs[7], &gregs[15]);
5145 __get_user(env->pc, &gregs[16]);
5146 __get_user(temp, &gregs[17]);
Laurent Vivier71811552009-08-03 16:12:18 +02005147 env->sr = (env->sr & 0xff00) | (temp & 0xff);
5148
5149 *pd0 = env->dregs[0];
Riku Voipio1d8b5122014-04-23 10:26:05 +03005150 return 0;
Laurent Vivier71811552009-08-03 16:12:18 +02005151
5152badframe:
5153 return 1;
5154}
5155
Laurent Vivier492a8742009-08-03 16:12:17 +02005156static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05005157 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01005158 target_sigset_t *set, CPUM68KState *env)
Laurent Vivier492a8742009-08-03 16:12:17 +02005159{
Laurent Vivier71811552009-08-03 16:12:18 +02005160 struct target_rt_sigframe *frame;
5161 abi_ulong frame_addr;
5162 abi_ulong retcode_addr;
5163 abi_ulong info_addr;
5164 abi_ulong uc_addr;
5165 int err = 0;
5166 int i;
5167
5168 frame_addr = get_sigframe(ka, env, sizeof *frame);
5169 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
5170 goto give_sigsegv;
5171
Riku Voipio1d8b5122014-04-23 10:26:05 +03005172 __put_user(sig, &frame->sig);
Laurent Vivier71811552009-08-03 16:12:18 +02005173
5174 info_addr = frame_addr + offsetof(struct target_rt_sigframe, info);
Riku Voipio1d8b5122014-04-23 10:26:05 +03005175 __put_user(info_addr, &frame->pinfo);
Laurent Vivier71811552009-08-03 16:12:18 +02005176
5177 uc_addr = frame_addr + offsetof(struct target_rt_sigframe, uc);
Riku Voipio1d8b5122014-04-23 10:26:05 +03005178 __put_user(uc_addr, &frame->puc);
Laurent Vivier71811552009-08-03 16:12:18 +02005179
Riku Voipiob0fd8d12014-04-23 10:46:13 +03005180 copy_siginfo_to_user(&frame->info, info);
Laurent Vivier71811552009-08-03 16:12:18 +02005181
5182 /* Create the ucontext */
5183
Riku Voipio1d8b5122014-04-23 10:26:05 +03005184 __put_user(0, &frame->uc.tuc_flags);
5185 __put_user(0, &frame->uc.tuc_link);
5186 __put_user(target_sigaltstack_used.ss_sp,
5187 &frame->uc.tuc_stack.ss_sp);
5188 __put_user(sas_ss_flags(env->aregs[7]),
5189 &frame->uc.tuc_stack.ss_flags);
5190 __put_user(target_sigaltstack_used.ss_size,
5191 &frame->uc.tuc_stack.ss_size);
Laurent Vivier71811552009-08-03 16:12:18 +02005192 err |= target_rt_setup_ucontext(&frame->uc, env);
5193
5194 if (err)
5195 goto give_sigsegv;
5196
5197 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
Riku Voipio0188fad2014-04-23 13:34:15 +03005198 __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
Laurent Vivier71811552009-08-03 16:12:18 +02005199 }
5200
5201 /* Set up to return from userspace. */
5202
5203 retcode_addr = frame_addr + offsetof(struct target_sigframe, retcode);
Riku Voipio1d8b5122014-04-23 10:26:05 +03005204 __put_user(retcode_addr, &frame->pretcode);
Laurent Vivier71811552009-08-03 16:12:18 +02005205
5206 /* moveq #,d0; notb d0; trap #0 */
5207
Riku Voipio1d8b5122014-04-23 10:26:05 +03005208 __put_user(0x70004600 + ((TARGET_NR_rt_sigreturn ^ 0xff) << 16),
5209 (long *)(frame->retcode + 0));
5210 __put_user(0x4e40, (short *)(frame->retcode + 4));
Laurent Vivier71811552009-08-03 16:12:18 +02005211
5212 if (err)
5213 goto give_sigsegv;
5214
5215 /* Set up to return from userspace */
5216
5217 env->aregs[7] = frame_addr;
5218 env->pc = ka->_sa_handler;
5219
5220 unlock_user_struct(frame, frame_addr, 1);
5221 return;
5222
5223give_sigsegv:
5224 unlock_user_struct(frame, frame_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02005225 force_sig(TARGET_SIGSEGV);
Laurent Vivier492a8742009-08-03 16:12:17 +02005226}
5227
Andreas Färber05390242012-02-25 03:37:53 +01005228long do_sigreturn(CPUM68KState *env)
Laurent Vivier492a8742009-08-03 16:12:17 +02005229{
5230 struct target_sigframe *frame;
5231 abi_ulong frame_addr = env->aregs[7] - 4;
Anthony Liguoric227f092009-10-01 16:12:16 -05005232 target_sigset_t target_set;
Laurent Vivier492a8742009-08-03 16:12:17 +02005233 sigset_t set;
5234 int d0, i;
5235
5236 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
5237 goto badframe;
5238
5239 /* set blocked signals */
5240
Riku Voipiof5f601a2014-04-23 13:00:17 +03005241 __get_user(target_set.sig[0], &frame->sc.sc_mask);
Laurent Vivier492a8742009-08-03 16:12:17 +02005242
5243 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
Riku Voipiof5f601a2014-04-23 13:00:17 +03005244 __get_user(target_set.sig[i], &frame->extramask[i - 1]);
Laurent Vivier492a8742009-08-03 16:12:17 +02005245 }
5246
5247 target_to_host_sigset_internal(&set, &target_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00005248 do_sigprocmask(SIG_SETMASK, &set, NULL);
Laurent Vivier492a8742009-08-03 16:12:17 +02005249
5250 /* restore registers */
5251
Riku Voipio016d2e12014-04-23 11:19:48 +03005252 restore_sigcontext(env, &frame->sc, &d0);
Laurent Vivier492a8742009-08-03 16:12:17 +02005253
5254 unlock_user_struct(frame, frame_addr, 0);
5255 return d0;
5256
5257badframe:
Laurent Vivier492a8742009-08-03 16:12:17 +02005258 force_sig(TARGET_SIGSEGV);
5259 return 0;
5260}
5261
Andreas Färber05390242012-02-25 03:37:53 +01005262long do_rt_sigreturn(CPUM68KState *env)
Laurent Vivier492a8742009-08-03 16:12:17 +02005263{
Laurent Vivier71811552009-08-03 16:12:18 +02005264 struct target_rt_sigframe *frame;
5265 abi_ulong frame_addr = env->aregs[7] - 4;
Anthony Liguoric227f092009-10-01 16:12:16 -05005266 target_sigset_t target_set;
Laurent Vivier71811552009-08-03 16:12:18 +02005267 sigset_t set;
5268 int d0;
5269
5270 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
5271 goto badframe;
5272
5273 target_to_host_sigset_internal(&set, &target_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00005274 do_sigprocmask(SIG_SETMASK, &set, NULL);
Laurent Vivier71811552009-08-03 16:12:18 +02005275
5276 /* restore registers */
5277
5278 if (target_rt_restore_ucontext(env, &frame->uc, &d0))
5279 goto badframe;
5280
5281 if (do_sigaltstack(frame_addr +
Aurelien Jarno60e99242010-03-29 02:12:51 +02005282 offsetof(struct target_rt_sigframe, uc.tuc_stack),
Laurent Vivier71811552009-08-03 16:12:18 +02005283 0, get_sp_from_cpustate(env)) == -EFAULT)
5284 goto badframe;
5285
5286 unlock_user_struct(frame, frame_addr, 0);
5287 return d0;
5288
5289badframe:
5290 unlock_user_struct(frame, frame_addr, 0);
5291 force_sig(TARGET_SIGSEGV);
5292 return 0;
Laurent Vivier492a8742009-08-03 16:12:17 +02005293}
5294
Richard Henderson6049f4f2009-12-27 18:30:03 -08005295#elif defined(TARGET_ALPHA)
5296
5297struct target_sigcontext {
5298 abi_long sc_onstack;
5299 abi_long sc_mask;
5300 abi_long sc_pc;
5301 abi_long sc_ps;
5302 abi_long sc_regs[32];
5303 abi_long sc_ownedfp;
5304 abi_long sc_fpregs[32];
5305 abi_ulong sc_fpcr;
5306 abi_ulong sc_fp_control;
5307 abi_ulong sc_reserved1;
5308 abi_ulong sc_reserved2;
5309 abi_ulong sc_ssize;
5310 abi_ulong sc_sbase;
5311 abi_ulong sc_traparg_a0;
5312 abi_ulong sc_traparg_a1;
5313 abi_ulong sc_traparg_a2;
5314 abi_ulong sc_fp_trap_pc;
5315 abi_ulong sc_fp_trigger_sum;
5316 abi_ulong sc_fp_trigger_inst;
5317};
5318
5319struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02005320 abi_ulong tuc_flags;
5321 abi_ulong tuc_link;
5322 abi_ulong tuc_osf_sigmask;
5323 target_stack_t tuc_stack;
5324 struct target_sigcontext tuc_mcontext;
5325 target_sigset_t tuc_sigmask;
Richard Henderson6049f4f2009-12-27 18:30:03 -08005326};
5327
5328struct target_sigframe {
5329 struct target_sigcontext sc;
5330 unsigned int retcode[3];
5331};
5332
5333struct target_rt_sigframe {
5334 target_siginfo_t info;
5335 struct target_ucontext uc;
5336 unsigned int retcode[3];
5337};
5338
5339#define INSN_MOV_R30_R16 0x47fe0410
5340#define INSN_LDI_R0 0x201f0000
5341#define INSN_CALLSYS 0x00000083
5342
Riku Voipio41ecc722014-04-23 11:01:00 +03005343static void setup_sigcontext(struct target_sigcontext *sc, CPUAlphaState *env,
Richard Henderson6049f4f2009-12-27 18:30:03 -08005344 abi_ulong frame_addr, target_sigset_t *set)
5345{
Riku Voipio41ecc722014-04-23 11:01:00 +03005346 int i;
Richard Henderson6049f4f2009-12-27 18:30:03 -08005347
Riku Voipio1d8b5122014-04-23 10:26:05 +03005348 __put_user(on_sig_stack(frame_addr), &sc->sc_onstack);
5349 __put_user(set->sig[0], &sc->sc_mask);
5350 __put_user(env->pc, &sc->sc_pc);
5351 __put_user(8, &sc->sc_ps);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005352
5353 for (i = 0; i < 31; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03005354 __put_user(env->ir[i], &sc->sc_regs[i]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005355 }
Riku Voipio1d8b5122014-04-23 10:26:05 +03005356 __put_user(0, &sc->sc_regs[31]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005357
5358 for (i = 0; i < 31; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03005359 __put_user(env->fir[i], &sc->sc_fpregs[i]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005360 }
Riku Voipio1d8b5122014-04-23 10:26:05 +03005361 __put_user(0, &sc->sc_fpregs[31]);
5362 __put_user(cpu_alpha_load_fpcr(env), &sc->sc_fpcr);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005363
Riku Voipio1d8b5122014-04-23 10:26:05 +03005364 __put_user(0, &sc->sc_traparg_a0); /* FIXME */
5365 __put_user(0, &sc->sc_traparg_a1); /* FIXME */
5366 __put_user(0, &sc->sc_traparg_a2); /* FIXME */
Richard Henderson6049f4f2009-12-27 18:30:03 -08005367}
5368
Riku Voipio016d2e12014-04-23 11:19:48 +03005369static void restore_sigcontext(CPUAlphaState *env,
Andreas Färber05390242012-02-25 03:37:53 +01005370 struct target_sigcontext *sc)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005371{
5372 uint64_t fpcr;
Riku Voipio016d2e12014-04-23 11:19:48 +03005373 int i;
Richard Henderson6049f4f2009-12-27 18:30:03 -08005374
Riku Voipio1d8b5122014-04-23 10:26:05 +03005375 __get_user(env->pc, &sc->sc_pc);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005376
5377 for (i = 0; i < 31; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03005378 __get_user(env->ir[i], &sc->sc_regs[i]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005379 }
5380 for (i = 0; i < 31; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03005381 __get_user(env->fir[i], &sc->sc_fpregs[i]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005382 }
5383
Riku Voipio1d8b5122014-04-23 10:26:05 +03005384 __get_user(fpcr, &sc->sc_fpcr);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005385 cpu_alpha_store_fpcr(env, fpcr);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005386}
5387
5388static inline abi_ulong get_sigframe(struct target_sigaction *sa,
Andreas Färber05390242012-02-25 03:37:53 +01005389 CPUAlphaState *env,
5390 unsigned long framesize)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005391{
5392 abi_ulong sp = env->ir[IR_SP];
5393
5394 /* This is the X/Open sanctioned signal stack switching. */
5395 if ((sa->sa_flags & TARGET_SA_ONSTACK) != 0 && !sas_ss_flags(sp)) {
5396 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
5397 }
5398 return (sp - framesize) & -32;
5399}
5400
5401static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01005402 target_sigset_t *set, CPUAlphaState *env)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005403{
5404 abi_ulong frame_addr, r26;
5405 struct target_sigframe *frame;
5406 int err = 0;
5407
5408 frame_addr = get_sigframe(ka, env, sizeof(*frame));
5409 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
5410 goto give_sigsegv;
5411 }
5412
Riku Voipio41ecc722014-04-23 11:01:00 +03005413 setup_sigcontext(&frame->sc, env, frame_addr, set);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005414
5415 if (ka->sa_restorer) {
5416 r26 = ka->sa_restorer;
5417 } else {
Riku Voipio1d8b5122014-04-23 10:26:05 +03005418 __put_user(INSN_MOV_R30_R16, &frame->retcode[0]);
5419 __put_user(INSN_LDI_R0 + TARGET_NR_sigreturn,
5420 &frame->retcode[1]);
5421 __put_user(INSN_CALLSYS, &frame->retcode[2]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005422 /* imb() */
5423 r26 = frame_addr;
5424 }
5425
5426 unlock_user_struct(frame, frame_addr, 1);
5427
5428 if (err) {
5429 give_sigsegv:
5430 if (sig == TARGET_SIGSEGV) {
5431 ka->_sa_handler = TARGET_SIG_DFL;
5432 }
5433 force_sig(TARGET_SIGSEGV);
5434 }
5435
5436 env->ir[IR_RA] = r26;
5437 env->ir[IR_PV] = env->pc = ka->_sa_handler;
5438 env->ir[IR_A0] = sig;
5439 env->ir[IR_A1] = 0;
5440 env->ir[IR_A2] = frame_addr + offsetof(struct target_sigframe, sc);
5441 env->ir[IR_SP] = frame_addr;
5442}
5443
5444static void setup_rt_frame(int sig, struct target_sigaction *ka,
5445 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01005446 target_sigset_t *set, CPUAlphaState *env)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005447{
5448 abi_ulong frame_addr, r26;
5449 struct target_rt_sigframe *frame;
5450 int i, err = 0;
5451
5452 frame_addr = get_sigframe(ka, env, sizeof(*frame));
5453 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
5454 goto give_sigsegv;
5455 }
5456
Riku Voipiob0fd8d12014-04-23 10:46:13 +03005457 copy_siginfo_to_user(&frame->info, info);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005458
Riku Voipio1d8b5122014-04-23 10:26:05 +03005459 __put_user(0, &frame->uc.tuc_flags);
5460 __put_user(0, &frame->uc.tuc_link);
5461 __put_user(set->sig[0], &frame->uc.tuc_osf_sigmask);
5462 __put_user(target_sigaltstack_used.ss_sp,
5463 &frame->uc.tuc_stack.ss_sp);
5464 __put_user(sas_ss_flags(env->ir[IR_SP]),
5465 &frame->uc.tuc_stack.ss_flags);
5466 __put_user(target_sigaltstack_used.ss_size,
5467 &frame->uc.tuc_stack.ss_size);
Riku Voipio41ecc722014-04-23 11:01:00 +03005468 setup_sigcontext(&frame->uc.tuc_mcontext, env, frame_addr, set);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005469 for (i = 0; i < TARGET_NSIG_WORDS; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03005470 __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005471 }
5472
5473 if (ka->sa_restorer) {
5474 r26 = ka->sa_restorer;
5475 } else {
Riku Voipio1d8b5122014-04-23 10:26:05 +03005476 __put_user(INSN_MOV_R30_R16, &frame->retcode[0]);
5477 __put_user(INSN_LDI_R0 + TARGET_NR_rt_sigreturn,
5478 &frame->retcode[1]);
5479 __put_user(INSN_CALLSYS, &frame->retcode[2]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005480 /* imb(); */
5481 r26 = frame_addr;
5482 }
5483
5484 if (err) {
5485 give_sigsegv:
5486 if (sig == TARGET_SIGSEGV) {
5487 ka->_sa_handler = TARGET_SIG_DFL;
5488 }
5489 force_sig(TARGET_SIGSEGV);
5490 }
5491
5492 env->ir[IR_RA] = r26;
5493 env->ir[IR_PV] = env->pc = ka->_sa_handler;
5494 env->ir[IR_A0] = sig;
5495 env->ir[IR_A1] = frame_addr + offsetof(struct target_rt_sigframe, info);
5496 env->ir[IR_A2] = frame_addr + offsetof(struct target_rt_sigframe, uc);
5497 env->ir[IR_SP] = frame_addr;
5498}
5499
Andreas Färber05390242012-02-25 03:37:53 +01005500long do_sigreturn(CPUAlphaState *env)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005501{
5502 struct target_sigcontext *sc;
5503 abi_ulong sc_addr = env->ir[IR_A0];
5504 target_sigset_t target_set;
5505 sigset_t set;
5506
5507 if (!lock_user_struct(VERIFY_READ, sc, sc_addr, 1)) {
5508 goto badframe;
5509 }
5510
5511 target_sigemptyset(&target_set);
Riku Voipiof5f601a2014-04-23 13:00:17 +03005512 __get_user(target_set.sig[0], &sc->sc_mask);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005513
5514 target_to_host_sigset_internal(&set, &target_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00005515 do_sigprocmask(SIG_SETMASK, &set, NULL);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005516
Riku Voipio016d2e12014-04-23 11:19:48 +03005517 restore_sigcontext(env, sc);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005518 unlock_user_struct(sc, sc_addr, 0);
5519 return env->ir[IR_V0];
5520
5521 badframe:
Richard Henderson6049f4f2009-12-27 18:30:03 -08005522 force_sig(TARGET_SIGSEGV);
5523}
5524
Andreas Färber05390242012-02-25 03:37:53 +01005525long do_rt_sigreturn(CPUAlphaState *env)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005526{
5527 abi_ulong frame_addr = env->ir[IR_A0];
5528 struct target_rt_sigframe *frame;
5529 sigset_t set;
5530
5531 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
5532 goto badframe;
5533 }
Aurelien Jarno60e99242010-03-29 02:12:51 +02005534 target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
Alex Barcelo1c275922014-03-14 14:36:55 +00005535 do_sigprocmask(SIG_SETMASK, &set, NULL);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005536
Riku Voipio016d2e12014-04-23 11:19:48 +03005537 restore_sigcontext(env, &frame->uc.tuc_mcontext);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005538 if (do_sigaltstack(frame_addr + offsetof(struct target_rt_sigframe,
Aurelien Jarno60e99242010-03-29 02:12:51 +02005539 uc.tuc_stack),
Richard Henderson6049f4f2009-12-27 18:30:03 -08005540 0, env->ir[IR_SP]) == -EFAULT) {
5541 goto badframe;
5542 }
5543
5544 unlock_user_struct(frame, frame_addr, 0);
5545 return env->ir[IR_V0];
5546
5547
5548 badframe:
5549 unlock_user_struct(frame, frame_addr, 0);
5550 force_sig(TARGET_SIGSEGV);
5551}
5552
bellardb346ff42003-06-15 20:05:50 +00005553#else
5554
pbrook624f7972008-05-31 16:11:38 +00005555static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber9349b4f2012-03-14 01:38:32 +01005556 target_sigset_t *set, CPUArchState *env)
bellardb346ff42003-06-15 20:05:50 +00005557{
5558 fprintf(stderr, "setup_frame: not implemented\n");
5559}
5560
pbrook624f7972008-05-31 16:11:38 +00005561static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05005562 target_siginfo_t *info,
Andreas Färber9349b4f2012-03-14 01:38:32 +01005563 target_sigset_t *set, CPUArchState *env)
bellardb346ff42003-06-15 20:05:50 +00005564{
5565 fprintf(stderr, "setup_rt_frame: not implemented\n");
5566}
5567
Andreas Färber9349b4f2012-03-14 01:38:32 +01005568long do_sigreturn(CPUArchState *env)
bellardb346ff42003-06-15 20:05:50 +00005569{
5570 fprintf(stderr, "do_sigreturn: not implemented\n");
bellardf8b0aa22007-11-11 23:03:42 +00005571 return -TARGET_ENOSYS;
bellardb346ff42003-06-15 20:05:50 +00005572}
5573
Andreas Färber9349b4f2012-03-14 01:38:32 +01005574long do_rt_sigreturn(CPUArchState *env)
bellardb346ff42003-06-15 20:05:50 +00005575{
5576 fprintf(stderr, "do_rt_sigreturn: not implemented\n");
bellardf8b0aa22007-11-11 23:03:42 +00005577 return -TARGET_ENOSYS;
bellardb346ff42003-06-15 20:05:50 +00005578}
5579
bellard66fb9762003-03-23 01:06:05 +00005580#endif
5581
Andreas Färber9349b4f2012-03-14 01:38:32 +01005582void process_pending_signals(CPUArchState *cpu_env)
bellard66fb9762003-03-23 01:06:05 +00005583{
Andreas Färberdb6b81d2013-06-27 19:49:31 +02005584 CPUState *cpu = ENV_GET_CPU(cpu_env);
bellard66fb9762003-03-23 01:06:05 +00005585 int sig;
blueswir1992f48a2007-10-14 16:27:31 +00005586 abi_ulong handler;
bellard9de5e442003-03-23 16:49:39 +00005587 sigset_t set, old_set;
Anthony Liguoric227f092009-10-01 16:12:16 -05005588 target_sigset_t target_old_set;
pbrook624f7972008-05-31 16:11:38 +00005589 struct emulated_sigtable *k;
5590 struct target_sigaction *sa;
bellard66fb9762003-03-23 01:06:05 +00005591 struct sigqueue *q;
Andreas Färber0429a972013-08-26 18:14:44 +02005592 TaskState *ts = cpu->opaque;
ths3b46e622007-09-17 08:09:54 +00005593
pbrook624f7972008-05-31 16:11:38 +00005594 if (!ts->signal_pending)
bellard31e31b82003-02-18 22:55:36 +00005595 return;
5596
pbrook624f7972008-05-31 16:11:38 +00005597 /* FIXME: This is not threadsafe. */
5598 k = ts->sigtab;
bellard66fb9762003-03-23 01:06:05 +00005599 for(sig = 1; sig <= TARGET_NSIG; sig++) {
5600 if (k->pending)
bellard31e31b82003-02-18 22:55:36 +00005601 goto handle_signal;
bellard66fb9762003-03-23 01:06:05 +00005602 k++;
bellard31e31b82003-02-18 22:55:36 +00005603 }
5604 /* if no signal is pending, just return */
pbrook624f7972008-05-31 16:11:38 +00005605 ts->signal_pending = 0;
bellard31e31b82003-02-18 22:55:36 +00005606 return;
bellard66fb9762003-03-23 01:06:05 +00005607
bellard31e31b82003-02-18 22:55:36 +00005608 handle_signal:
bellard66fb9762003-03-23 01:06:05 +00005609#ifdef DEBUG_SIGNAL
bellardbc8a22c2003-03-30 21:02:40 +00005610 fprintf(stderr, "qemu: process signal %d\n", sig);
bellard66fb9762003-03-23 01:06:05 +00005611#endif
5612 /* dequeue signal */
5613 q = k->first;
5614 k->first = q->next;
5615 if (!k->first)
5616 k->pending = 0;
ths3b46e622007-09-17 08:09:54 +00005617
Andreas Färberdb6b81d2013-06-27 19:49:31 +02005618 sig = gdb_handlesig(cpu, sig);
bellard1fddef42005-04-17 19:16:13 +00005619 if (!sig) {
aurel32ca587a82008-12-18 22:44:13 +00005620 sa = NULL;
5621 handler = TARGET_SIG_IGN;
5622 } else {
5623 sa = &sigact_table[sig - 1];
5624 handler = sa->_sa_handler;
bellard1fddef42005-04-17 19:16:13 +00005625 }
bellard66fb9762003-03-23 01:06:05 +00005626
Peter Maydella7ec0f92014-03-14 14:36:56 +00005627 if (ts->sigsegv_blocked && sig == TARGET_SIGSEGV) {
5628 /* Guest has blocked SIGSEGV but we got one anyway. Assume this
5629 * is a forced SIGSEGV (ie one the kernel handles via force_sig_info
5630 * because it got a real MMU fault), and treat as if default handler.
5631 */
5632 handler = TARGET_SIG_DFL;
5633 }
5634
bellard66fb9762003-03-23 01:06:05 +00005635 if (handler == TARGET_SIG_DFL) {
aurel32ca587a82008-12-18 22:44:13 +00005636 /* default handler : ignore some signal. The other are job control or fatal */
5637 if (sig == TARGET_SIGTSTP || sig == TARGET_SIGTTIN || sig == TARGET_SIGTTOU) {
5638 kill(getpid(),SIGSTOP);
5639 } else if (sig != TARGET_SIGCHLD &&
5640 sig != TARGET_SIGURG &&
5641 sig != TARGET_SIGWINCH &&
5642 sig != TARGET_SIGCONT) {
bellard66fb9762003-03-23 01:06:05 +00005643 force_sig(sig);
5644 }
5645 } else if (handler == TARGET_SIG_IGN) {
5646 /* ignore sig */
5647 } else if (handler == TARGET_SIG_ERR) {
5648 force_sig(sig);
5649 } else {
bellard9de5e442003-03-23 16:49:39 +00005650 /* compute the blocked signals during the handler execution */
pbrook624f7972008-05-31 16:11:38 +00005651 target_to_host_sigset(&set, &sa->sa_mask);
bellard9de5e442003-03-23 16:49:39 +00005652 /* SA_NODEFER indicates that the current signal should not be
5653 blocked during the handler */
pbrook624f7972008-05-31 16:11:38 +00005654 if (!(sa->sa_flags & TARGET_SA_NODEFER))
bellard9de5e442003-03-23 16:49:39 +00005655 sigaddset(&set, target_to_host_signal(sig));
ths3b46e622007-09-17 08:09:54 +00005656
bellard9de5e442003-03-23 16:49:39 +00005657 /* block signals in the handler using Linux */
Alex Barcelo1c275922014-03-14 14:36:55 +00005658 do_sigprocmask(SIG_BLOCK, &set, &old_set);
bellard9de5e442003-03-23 16:49:39 +00005659 /* save the previous blocked signal state to restore it at the
5660 end of the signal execution (see do_sigreturn) */
bellard92319442004-06-19 16:58:13 +00005661 host_to_target_sigset_internal(&target_old_set, &old_set);
bellard9de5e442003-03-23 16:49:39 +00005662
bellardbc8a22c2003-03-30 21:02:40 +00005663 /* if the CPU is in VM86 mode, we restore the 32 bit values */
j_mayer84409dd2007-04-06 08:56:50 +00005664#if defined(TARGET_I386) && !defined(TARGET_X86_64)
bellardbc8a22c2003-03-30 21:02:40 +00005665 {
5666 CPUX86State *env = cpu_env;
5667 if (env->eflags & VM_MASK)
5668 save_v86_state(env);
5669 }
5670#endif
bellard9de5e442003-03-23 16:49:39 +00005671 /* prepare the stack frame of the virtual CPU */
Richard Hendersonff970902013-02-10 10:30:42 -08005672#if defined(TARGET_ABI_MIPSN32) || defined(TARGET_ABI_MIPSN64)
5673 /* These targets do not have traditional signals. */
5674 setup_rt_frame(sig, sa, &q->info, &target_old_set, cpu_env);
5675#else
pbrook624f7972008-05-31 16:11:38 +00005676 if (sa->sa_flags & TARGET_SA_SIGINFO)
5677 setup_rt_frame(sig, sa, &q->info, &target_old_set, cpu_env);
bellard66fb9762003-03-23 01:06:05 +00005678 else
pbrook624f7972008-05-31 16:11:38 +00005679 setup_frame(sig, sa, &target_old_set, cpu_env);
Richard Hendersonff970902013-02-10 10:30:42 -08005680#endif
pbrook624f7972008-05-31 16:11:38 +00005681 if (sa->sa_flags & TARGET_SA_RESETHAND)
5682 sa->_sa_handler = TARGET_SIG_DFL;
bellard31e31b82003-02-18 22:55:36 +00005683 }
bellard66fb9762003-03-23 01:06:05 +00005684 if (q != &k->info)
pbrook624f7972008-05-31 16:11:38 +00005685 free_sigqueue(cpu_env, q);
bellard31e31b82003-02-18 22:55:36 +00005686}