blob: 5b43410eac8c02ca783192406204c024163d3217 [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;
thsa04e1342007-09-27 13:57:58 +0000620
ths0da46a62007-10-20 20:23:07 +0000621 ret = -TARGET_EFAULT;
Riku Voipio9eeb8302014-04-23 11:26:34 +0300622 if (!lock_user_struct(VERIFY_READ, uss, uss_addr, 1)) {
thsa04e1342007-09-27 13:57:58 +0000623 goto out;
Riku Voipio9eeb8302014-04-23 11:26:34 +0300624 }
625 __get_user(ss.ss_sp, &uss->ss_sp);
626 __get_user(ss.ss_size, &uss->ss_size);
627 __get_user(ss.ss_flags, &uss->ss_flags);
bellard579a97f2007-11-11 14:26:47 +0000628 unlock_user_struct(uss, uss_addr, 0);
thsa04e1342007-09-27 13:57:58 +0000629
ths0da46a62007-10-20 20:23:07 +0000630 ret = -TARGET_EPERM;
thsa04e1342007-09-27 13:57:58 +0000631 if (on_sig_stack(sp))
632 goto out;
633
ths0da46a62007-10-20 20:23:07 +0000634 ret = -TARGET_EINVAL;
thsa04e1342007-09-27 13:57:58 +0000635 if (ss.ss_flags != TARGET_SS_DISABLE
636 && ss.ss_flags != TARGET_SS_ONSTACK
637 && ss.ss_flags != 0)
638 goto out;
639
640 if (ss.ss_flags == TARGET_SS_DISABLE) {
641 ss.ss_size = 0;
642 ss.ss_sp = 0;
643 } else {
ths0da46a62007-10-20 20:23:07 +0000644 ret = -TARGET_ENOMEM;
thsa04e1342007-09-27 13:57:58 +0000645 if (ss.ss_size < MINSIGSTKSZ)
646 goto out;
647 }
648
649 target_sigaltstack_used.ss_sp = ss.ss_sp;
650 target_sigaltstack_used.ss_size = ss.ss_size;
651 }
652
bellard579a97f2007-11-11 14:26:47 +0000653 if (uoss_addr) {
ths0da46a62007-10-20 20:23:07 +0000654 ret = -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +0000655 if (copy_to_user(uoss_addr, &oss, sizeof(oss)))
thsa04e1342007-09-27 13:57:58 +0000656 goto out;
thsa04e1342007-09-27 13:57:58 +0000657 }
658
659 ret = 0;
660out:
661 return ret;
662}
663
ths0da46a62007-10-20 20:23:07 +0000664/* do_sigaction() return host values and errnos */
bellard66fb9762003-03-23 01:06:05 +0000665int do_sigaction(int sig, const struct target_sigaction *act,
666 struct target_sigaction *oact)
bellard31e31b82003-02-18 22:55:36 +0000667{
pbrook624f7972008-05-31 16:11:38 +0000668 struct target_sigaction *k;
bellard773b93e2004-01-04 17:15:59 +0000669 struct sigaction act1;
670 int host_sig;
ths0da46a62007-10-20 20:23:07 +0000671 int ret = 0;
bellard31e31b82003-02-18 22:55:36 +0000672
ths2a913eb2008-11-27 15:46:25 +0000673 if (sig < 1 || sig > TARGET_NSIG || sig == TARGET_SIGKILL || sig == TARGET_SIGSTOP)
bellard66fb9762003-03-23 01:06:05 +0000674 return -EINVAL;
675 k = &sigact_table[sig - 1];
bellard773b93e2004-01-04 17:15:59 +0000676#if defined(DEBUG_SIGNAL)
Blue Swirl0bf9e312009-07-20 17:19:25 +0000677 fprintf(stderr, "sigaction sig=%d act=0x%p, oact=0x%p\n",
678 sig, act, oact);
bellard66fb9762003-03-23 01:06:05 +0000679#endif
680 if (oact) {
Richard Hendersond2565872013-01-04 16:39:32 -0800681 __put_user(k->_sa_handler, &oact->_sa_handler);
682 __put_user(k->sa_flags, &oact->sa_flags);
ths388bb212007-05-13 13:58:00 +0000683#if !defined(TARGET_MIPS)
Richard Hendersond2565872013-01-04 16:39:32 -0800684 __put_user(k->sa_restorer, &oact->sa_restorer);
ths388bb212007-05-13 13:58:00 +0000685#endif
Richard Hendersond2565872013-01-04 16:39:32 -0800686 /* Not swapped. */
pbrook624f7972008-05-31 16:11:38 +0000687 oact->sa_mask = k->sa_mask;
bellard66fb9762003-03-23 01:06:05 +0000688 }
689 if (act) {
pbrook624f7972008-05-31 16:11:38 +0000690 /* FIXME: This is not threadsafe. */
Richard Hendersond2565872013-01-04 16:39:32 -0800691 __get_user(k->_sa_handler, &act->_sa_handler);
692 __get_user(k->sa_flags, &act->sa_flags);
ths388bb212007-05-13 13:58:00 +0000693#if !defined(TARGET_MIPS)
Richard Hendersond2565872013-01-04 16:39:32 -0800694 __get_user(k->sa_restorer, &act->sa_restorer);
ths388bb212007-05-13 13:58:00 +0000695#endif
Richard Hendersond2565872013-01-04 16:39:32 -0800696 /* To be swapped in target_to_host_sigset. */
pbrook624f7972008-05-31 16:11:38 +0000697 k->sa_mask = act->sa_mask;
bellard773b93e2004-01-04 17:15:59 +0000698
699 /* we update the host linux signal state */
700 host_sig = target_to_host_signal(sig);
701 if (host_sig != SIGSEGV && host_sig != SIGBUS) {
702 sigfillset(&act1.sa_mask);
703 act1.sa_flags = SA_SIGINFO;
pbrook624f7972008-05-31 16:11:38 +0000704 if (k->sa_flags & TARGET_SA_RESTART)
bellard773b93e2004-01-04 17:15:59 +0000705 act1.sa_flags |= SA_RESTART;
706 /* NOTE: it is important to update the host kernel signal
707 ignore state to avoid getting unexpected interrupted
708 syscalls */
pbrook624f7972008-05-31 16:11:38 +0000709 if (k->_sa_handler == TARGET_SIG_IGN) {
bellard773b93e2004-01-04 17:15:59 +0000710 act1.sa_sigaction = (void *)SIG_IGN;
pbrook624f7972008-05-31 16:11:38 +0000711 } else if (k->_sa_handler == TARGET_SIG_DFL) {
aurel32ca587a82008-12-18 22:44:13 +0000712 if (fatal_signal (sig))
713 act1.sa_sigaction = host_signal_handler;
714 else
715 act1.sa_sigaction = (void *)SIG_DFL;
bellard773b93e2004-01-04 17:15:59 +0000716 } else {
717 act1.sa_sigaction = host_signal_handler;
718 }
ths0da46a62007-10-20 20:23:07 +0000719 ret = sigaction(host_sig, &act1, NULL);
bellard773b93e2004-01-04 17:15:59 +0000720 }
bellard66fb9762003-03-23 01:06:05 +0000721 }
ths0da46a62007-10-20 20:23:07 +0000722 return ret;
bellard66fb9762003-03-23 01:06:05 +0000723}
bellard31e31b82003-02-18 22:55:36 +0000724
Riku Voipiob0fd8d12014-04-23 10:46:13 +0300725static inline void copy_siginfo_to_user(target_siginfo_t *tinfo,
Anthony Liguoric227f092009-10-01 16:12:16 -0500726 const target_siginfo_t *info)
bellard43fff232003-07-09 19:31:39 +0000727{
728 tswap_siginfo(tinfo, info);
bellard43fff232003-07-09 19:31:39 +0000729}
730
thsc3b5bc82007-12-02 06:31:25 +0000731static inline int current_exec_domain_sig(int sig)
732{
733 return /* current->exec_domain && current->exec_domain->signal_invmap
734 && sig < 32 ? current->exec_domain->signal_invmap[sig] : */ sig;
735}
736
bellard459a4012007-11-11 19:45:10 +0000737#if defined(TARGET_I386) && TARGET_ABI_BITS == 32
bellard66fb9762003-03-23 01:06:05 +0000738
739/* from the Linux kernel */
740
741struct target_fpreg {
742 uint16_t significand[4];
743 uint16_t exponent;
744};
745
746struct target_fpxreg {
747 uint16_t significand[4];
748 uint16_t exponent;
749 uint16_t padding[3];
750};
751
752struct target_xmmreg {
blueswir1992f48a2007-10-14 16:27:31 +0000753 abi_ulong element[4];
bellard66fb9762003-03-23 01:06:05 +0000754};
755
756struct target_fpstate {
757 /* Regular FPU environment */
blueswir1992f48a2007-10-14 16:27:31 +0000758 abi_ulong cw;
759 abi_ulong sw;
760 abi_ulong tag;
761 abi_ulong ipoff;
762 abi_ulong cssel;
763 abi_ulong dataoff;
764 abi_ulong datasel;
bellard66fb9762003-03-23 01:06:05 +0000765 struct target_fpreg _st[8];
766 uint16_t status;
767 uint16_t magic; /* 0xffff = regular FPU data only */
768
769 /* FXSR FPU environment */
blueswir1992f48a2007-10-14 16:27:31 +0000770 abi_ulong _fxsr_env[6]; /* FXSR FPU env is ignored */
771 abi_ulong mxcsr;
772 abi_ulong reserved;
bellard66fb9762003-03-23 01:06:05 +0000773 struct target_fpxreg _fxsr_st[8]; /* FXSR FPU reg data is ignored */
774 struct target_xmmreg _xmm[8];
blueswir1992f48a2007-10-14 16:27:31 +0000775 abi_ulong padding[56];
bellard66fb9762003-03-23 01:06:05 +0000776};
777
778#define X86_FXSR_MAGIC 0x0000
779
780struct target_sigcontext {
781 uint16_t gs, __gsh;
782 uint16_t fs, __fsh;
783 uint16_t es, __esh;
784 uint16_t ds, __dsh;
blueswir1992f48a2007-10-14 16:27:31 +0000785 abi_ulong edi;
786 abi_ulong esi;
787 abi_ulong ebp;
788 abi_ulong esp;
789 abi_ulong ebx;
790 abi_ulong edx;
791 abi_ulong ecx;
792 abi_ulong eax;
793 abi_ulong trapno;
794 abi_ulong err;
795 abi_ulong eip;
bellard66fb9762003-03-23 01:06:05 +0000796 uint16_t cs, __csh;
blueswir1992f48a2007-10-14 16:27:31 +0000797 abi_ulong eflags;
798 abi_ulong esp_at_signal;
bellard66fb9762003-03-23 01:06:05 +0000799 uint16_t ss, __ssh;
blueswir1992f48a2007-10-14 16:27:31 +0000800 abi_ulong fpstate; /* pointer */
801 abi_ulong oldmask;
802 abi_ulong cr2;
bellard66fb9762003-03-23 01:06:05 +0000803};
804
bellard66fb9762003-03-23 01:06:05 +0000805struct target_ucontext {
blueswir1992f48a2007-10-14 16:27:31 +0000806 abi_ulong tuc_flags;
807 abi_ulong tuc_link;
Anthony Liguoric227f092009-10-01 16:12:16 -0500808 target_stack_t tuc_stack;
bellardb8076a72005-04-07 22:20:31 +0000809 struct target_sigcontext tuc_mcontext;
Anthony Liguoric227f092009-10-01 16:12:16 -0500810 target_sigset_t tuc_sigmask; /* mask last for extensibility */
bellard66fb9762003-03-23 01:06:05 +0000811};
812
813struct sigframe
814{
blueswir1992f48a2007-10-14 16:27:31 +0000815 abi_ulong pretcode;
bellard66fb9762003-03-23 01:06:05 +0000816 int sig;
817 struct target_sigcontext sc;
818 struct target_fpstate fpstate;
blueswir1992f48a2007-10-14 16:27:31 +0000819 abi_ulong extramask[TARGET_NSIG_WORDS-1];
bellard66fb9762003-03-23 01:06:05 +0000820 char retcode[8];
821};
822
823struct rt_sigframe
824{
blueswir1992f48a2007-10-14 16:27:31 +0000825 abi_ulong pretcode;
bellard66fb9762003-03-23 01:06:05 +0000826 int sig;
blueswir1992f48a2007-10-14 16:27:31 +0000827 abi_ulong pinfo;
828 abi_ulong puc;
bellard66fb9762003-03-23 01:06:05 +0000829 struct target_siginfo info;
830 struct target_ucontext uc;
831 struct target_fpstate fpstate;
832 char retcode[8];
833};
834
835/*
836 * Set up a signal frame.
837 */
838
bellard66fb9762003-03-23 01:06:05 +0000839/* XXX: save x87 state */
Riku Voipio41ecc722014-04-23 11:01:00 +0300840static void setup_sigcontext(struct target_sigcontext *sc,
841 struct target_fpstate *fpstate, CPUX86State *env, abi_ulong mask,
842 abi_ulong fpstate_addr)
bellard66fb9762003-03-23 01:06:05 +0000843{
Andreas Färber27103422013-08-26 08:31:06 +0200844 CPUState *cs = CPU(x86_env_get_cpu(env));
Andreas Färber27103422013-08-26 08:31:06 +0200845 uint16_t magic;
bellard66fb9762003-03-23 01:06:05 +0000846
bellard579a97f2007-11-11 14:26:47 +0000847 /* already locked in setup_frame() */
Riku Voipio1d8b5122014-04-23 10:26:05 +0300848 __put_user(env->segs[R_GS].selector, (unsigned int *)&sc->gs);
849 __put_user(env->segs[R_FS].selector, (unsigned int *)&sc->fs);
850 __put_user(env->segs[R_ES].selector, (unsigned int *)&sc->es);
851 __put_user(env->segs[R_DS].selector, (unsigned int *)&sc->ds);
852 __put_user(env->regs[R_EDI], &sc->edi);
853 __put_user(env->regs[R_ESI], &sc->esi);
854 __put_user(env->regs[R_EBP], &sc->ebp);
855 __put_user(env->regs[R_ESP], &sc->esp);
856 __put_user(env->regs[R_EBX], &sc->ebx);
857 __put_user(env->regs[R_EDX], &sc->edx);
858 __put_user(env->regs[R_ECX], &sc->ecx);
859 __put_user(env->regs[R_EAX], &sc->eax);
860 __put_user(cs->exception_index, &sc->trapno);
861 __put_user(env->error_code, &sc->err);
862 __put_user(env->eip, &sc->eip);
863 __put_user(env->segs[R_CS].selector, (unsigned int *)&sc->cs);
864 __put_user(env->eflags, &sc->eflags);
865 __put_user(env->regs[R_ESP], &sc->esp_at_signal);
866 __put_user(env->segs[R_SS].selector, (unsigned int *)&sc->ss);
bellarded2dcdf2003-05-29 20:06:27 +0000867
bellard28be6232007-11-11 22:23:38 +0000868 cpu_x86_fsave(env, fpstate_addr, 1);
bellarded2dcdf2003-05-29 20:06:27 +0000869 fpstate->status = fpstate->sw;
bellard775b58d2007-11-11 16:22:17 +0000870 magic = 0xffff;
Riku Voipio1d8b5122014-04-23 10:26:05 +0300871 __put_user(magic, &fpstate->magic);
872 __put_user(fpstate_addr, &sc->fpstate);
bellarded2dcdf2003-05-29 20:06:27 +0000873
bellard66fb9762003-03-23 01:06:05 +0000874 /* non-iBCS2 extensions.. */
Riku Voipio1d8b5122014-04-23 10:26:05 +0300875 __put_user(mask, &sc->oldmask);
876 __put_user(env->cr[2], &sc->cr2);
bellard66fb9762003-03-23 01:06:05 +0000877}
878
879/*
880 * Determine which stack to use..
881 */
882
bellard579a97f2007-11-11 14:26:47 +0000883static inline abi_ulong
pbrook624f7972008-05-31 16:11:38 +0000884get_sigframe(struct target_sigaction *ka, CPUX86State *env, size_t frame_size)
bellard66fb9762003-03-23 01:06:05 +0000885{
886 unsigned long esp;
887
888 /* Default to using normal stack */
889 esp = env->regs[R_ESP];
bellard66fb9762003-03-23 01:06:05 +0000890 /* This is the X/Open sanctioned signal stack switching. */
pbrook624f7972008-05-31 16:11:38 +0000891 if (ka->sa_flags & TARGET_SA_ONSTACK) {
thsa04e1342007-09-27 13:57:58 +0000892 if (sas_ss_flags(esp) == 0)
893 esp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
894 }
bellard66fb9762003-03-23 01:06:05 +0000895
896 /* This is the legacy signal stack switching. */
ths5fafdf22007-09-16 21:08:06 +0000897 else
bellarda52c7572003-06-21 13:14:12 +0000898 if ((env->segs[R_SS].selector & 0xffff) != __USER_DS &&
pbrook624f7972008-05-31 16:11:38 +0000899 !(ka->sa_flags & TARGET_SA_RESTORER) &&
900 ka->sa_restorer) {
901 esp = (unsigned long) ka->sa_restorer;
bellarda52c7572003-06-21 13:14:12 +0000902 }
bellard579a97f2007-11-11 14:26:47 +0000903 return (esp - frame_size) & -8ul;
bellard66fb9762003-03-23 01:06:05 +0000904}
905
bellard579a97f2007-11-11 14:26:47 +0000906/* compare linux/arch/i386/kernel/signal.c:setup_frame() */
pbrook624f7972008-05-31 16:11:38 +0000907static void setup_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -0500908 target_sigset_t *set, CPUX86State *env)
bellard66fb9762003-03-23 01:06:05 +0000909{
bellard579a97f2007-11-11 14:26:47 +0000910 abi_ulong frame_addr;
bellard66fb9762003-03-23 01:06:05 +0000911 struct sigframe *frame;
Riku Voipio7df2fa32014-04-23 10:34:53 +0300912 int i;
bellard66fb9762003-03-23 01:06:05 +0000913
bellard579a97f2007-11-11 14:26:47 +0000914 frame_addr = get_sigframe(ka, env, sizeof(*frame));
bellard66fb9762003-03-23 01:06:05 +0000915
bellard579a97f2007-11-11 14:26:47 +0000916 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
bellard66fb9762003-03-23 01:06:05 +0000917 goto give_sigsegv;
bellard579a97f2007-11-11 14:26:47 +0000918
Riku Voipio1d8b5122014-04-23 10:26:05 +0300919 __put_user(current_exec_domain_sig(sig),
920 &frame->sig);
bellard66fb9762003-03-23 01:06:05 +0000921
bellard28be6232007-11-11 22:23:38 +0000922 setup_sigcontext(&frame->sc, &frame->fpstate, env, set->sig[0],
923 frame_addr + offsetof(struct sigframe, fpstate));
bellard66fb9762003-03-23 01:06:05 +0000924
Riku Voipio7df2fa32014-04-23 10:34:53 +0300925 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
926 __put_user(set->sig[i], &frame->extramask[i - 1]);
927 }
bellard66fb9762003-03-23 01:06:05 +0000928
929 /* Set up to return from userspace. If provided, use a stub
930 already in userspace. */
pbrook624f7972008-05-31 16:11:38 +0000931 if (ka->sa_flags & TARGET_SA_RESTORER) {
Riku Voipio1d8b5122014-04-23 10:26:05 +0300932 __put_user(ka->sa_restorer, &frame->pretcode);
bellard66fb9762003-03-23 01:06:05 +0000933 } else {
bellard775b58d2007-11-11 16:22:17 +0000934 uint16_t val16;
bellard28be6232007-11-11 22:23:38 +0000935 abi_ulong retcode_addr;
936 retcode_addr = frame_addr + offsetof(struct sigframe, retcode);
Riku Voipio1d8b5122014-04-23 10:26:05 +0300937 __put_user(retcode_addr, &frame->pretcode);
bellard66fb9762003-03-23 01:06:05 +0000938 /* This is popl %eax ; movl $,%eax ; int $0x80 */
bellard775b58d2007-11-11 16:22:17 +0000939 val16 = 0xb858;
Riku Voipio1d8b5122014-04-23 10:26:05 +0300940 __put_user(val16, (uint16_t *)(frame->retcode+0));
941 __put_user(TARGET_NR_sigreturn, (int *)(frame->retcode+2));
bellard775b58d2007-11-11 16:22:17 +0000942 val16 = 0x80cd;
Riku Voipio1d8b5122014-04-23 10:26:05 +0300943 __put_user(val16, (uint16_t *)(frame->retcode+6));
bellard66fb9762003-03-23 01:06:05 +0000944 }
945
bellard66fb9762003-03-23 01:06:05 +0000946
947 /* Set up registers for signal handler */
bellard28be6232007-11-11 22:23:38 +0000948 env->regs[R_ESP] = frame_addr;
pbrook624f7972008-05-31 16:11:38 +0000949 env->eip = ka->_sa_handler;
bellard66fb9762003-03-23 01:06:05 +0000950
951 cpu_x86_load_seg(env, R_DS, __USER_DS);
952 cpu_x86_load_seg(env, R_ES, __USER_DS);
953 cpu_x86_load_seg(env, R_SS, __USER_DS);
954 cpu_x86_load_seg(env, R_CS, __USER_CS);
955 env->eflags &= ~TF_MASK;
956
bellard579a97f2007-11-11 14:26:47 +0000957 unlock_user_struct(frame, frame_addr, 1);
958
bellard66fb9762003-03-23 01:06:05 +0000959 return;
960
961give_sigsegv:
962 if (sig == TARGET_SIGSEGV)
pbrook624f7972008-05-31 16:11:38 +0000963 ka->_sa_handler = TARGET_SIG_DFL;
bellard66fb9762003-03-23 01:06:05 +0000964 force_sig(TARGET_SIGSEGV /* , current */);
965}
966
bellard579a97f2007-11-11 14:26:47 +0000967/* compare linux/arch/i386/kernel/signal.c:setup_rt_frame() */
pbrook624f7972008-05-31 16:11:38 +0000968static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -0500969 target_siginfo_t *info,
970 target_sigset_t *set, CPUX86State *env)
bellard66fb9762003-03-23 01:06:05 +0000971{
bellard28be6232007-11-11 22:23:38 +0000972 abi_ulong frame_addr, addr;
bellard66fb9762003-03-23 01:06:05 +0000973 struct rt_sigframe *frame;
bellard92319442004-06-19 16:58:13 +0000974 int i, err = 0;
bellard66fb9762003-03-23 01:06:05 +0000975
bellard579a97f2007-11-11 14:26:47 +0000976 frame_addr = get_sigframe(ka, env, sizeof(*frame));
bellard66fb9762003-03-23 01:06:05 +0000977
bellard579a97f2007-11-11 14:26:47 +0000978 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
bellard66fb9762003-03-23 01:06:05 +0000979 goto give_sigsegv;
bellard66fb9762003-03-23 01:06:05 +0000980
Riku Voipio1d8b5122014-04-23 10:26:05 +0300981 __put_user(current_exec_domain_sig(sig), &frame->sig);
bellard28be6232007-11-11 22:23:38 +0000982 addr = frame_addr + offsetof(struct rt_sigframe, info);
Riku Voipio1d8b5122014-04-23 10:26:05 +0300983 __put_user(addr, &frame->pinfo);
bellard28be6232007-11-11 22:23:38 +0000984 addr = frame_addr + offsetof(struct rt_sigframe, uc);
Riku Voipio1d8b5122014-04-23 10:26:05 +0300985 __put_user(addr, &frame->puc);
Riku Voipiob0fd8d12014-04-23 10:46:13 +0300986 copy_siginfo_to_user(&frame->info, info);
bellard66fb9762003-03-23 01:06:05 +0000987
988 /* Create the ucontext. */
Riku Voipio1d8b5122014-04-23 10:26:05 +0300989 __put_user(0, &frame->uc.tuc_flags);
990 __put_user(0, &frame->uc.tuc_link);
991 __put_user(target_sigaltstack_used.ss_sp, &frame->uc.tuc_stack.ss_sp);
992 __put_user(sas_ss_flags(get_sp_from_cpustate(env)),
993 &frame->uc.tuc_stack.ss_flags);
994 __put_user(target_sigaltstack_used.ss_size,
995 &frame->uc.tuc_stack.ss_size);
Riku Voipio41ecc722014-04-23 11:01:00 +0300996 setup_sigcontext(&frame->uc.tuc_mcontext, &frame->fpstate, env,
997 set->sig[0], frame_addr + offsetof(struct rt_sigframe, fpstate));
998
bellard92319442004-06-19 16:58:13 +0000999 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
bellardb8076a72005-04-07 22:20:31 +00001000 if (__put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]))
bellard92319442004-06-19 16:58:13 +00001001 goto give_sigsegv;
1002 }
bellard66fb9762003-03-23 01:06:05 +00001003
1004 /* Set up to return from userspace. If provided, use a stub
1005 already in userspace. */
pbrook624f7972008-05-31 16:11:38 +00001006 if (ka->sa_flags & TARGET_SA_RESTORER) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03001007 __put_user(ka->sa_restorer, &frame->pretcode);
bellard66fb9762003-03-23 01:06:05 +00001008 } else {
bellard775b58d2007-11-11 16:22:17 +00001009 uint16_t val16;
bellard28be6232007-11-11 22:23:38 +00001010 addr = frame_addr + offsetof(struct rt_sigframe, retcode);
Riku Voipio1d8b5122014-04-23 10:26:05 +03001011 __put_user(addr, &frame->pretcode);
bellard66fb9762003-03-23 01:06:05 +00001012 /* This is movl $,%eax ; int $0x80 */
Riku Voipio1d8b5122014-04-23 10:26:05 +03001013 __put_user(0xb8, (char *)(frame->retcode+0));
1014 __put_user(TARGET_NR_rt_sigreturn, (int *)(frame->retcode+1));
bellard775b58d2007-11-11 16:22:17 +00001015 val16 = 0x80cd;
Riku Voipio1d8b5122014-04-23 10:26:05 +03001016 __put_user(val16, (uint16_t *)(frame->retcode+5));
bellard66fb9762003-03-23 01:06:05 +00001017 }
1018
1019 if (err)
1020 goto give_sigsegv;
1021
1022 /* Set up registers for signal handler */
bellard28be6232007-11-11 22:23:38 +00001023 env->regs[R_ESP] = frame_addr;
pbrook624f7972008-05-31 16:11:38 +00001024 env->eip = ka->_sa_handler;
bellard66fb9762003-03-23 01:06:05 +00001025
1026 cpu_x86_load_seg(env, R_DS, __USER_DS);
1027 cpu_x86_load_seg(env, R_ES, __USER_DS);
1028 cpu_x86_load_seg(env, R_SS, __USER_DS);
1029 cpu_x86_load_seg(env, R_CS, __USER_CS);
1030 env->eflags &= ~TF_MASK;
1031
bellard579a97f2007-11-11 14:26:47 +00001032 unlock_user_struct(frame, frame_addr, 1);
1033
bellard66fb9762003-03-23 01:06:05 +00001034 return;
1035
1036give_sigsegv:
bellard579a97f2007-11-11 14:26:47 +00001037 unlock_user_struct(frame, frame_addr, 1);
bellard66fb9762003-03-23 01:06:05 +00001038 if (sig == TARGET_SIGSEGV)
pbrook624f7972008-05-31 16:11:38 +00001039 ka->_sa_handler = TARGET_SIG_DFL;
bellard66fb9762003-03-23 01:06:05 +00001040 force_sig(TARGET_SIGSEGV /* , current */);
1041}
1042
1043static int
1044restore_sigcontext(CPUX86State *env, struct target_sigcontext *sc, int *peax)
1045{
1046 unsigned int err = 0;
bellard28be6232007-11-11 22:23:38 +00001047 abi_ulong fpstate_addr;
1048 unsigned int tmpflags;
bellard66fb9762003-03-23 01:06:05 +00001049
bellard28be6232007-11-11 22:23:38 +00001050 cpu_x86_load_seg(env, R_GS, tswap16(sc->gs));
1051 cpu_x86_load_seg(env, R_FS, tswap16(sc->fs));
1052 cpu_x86_load_seg(env, R_ES, tswap16(sc->es));
1053 cpu_x86_load_seg(env, R_DS, tswap16(sc->ds));
bellard66fb9762003-03-23 01:06:05 +00001054
bellard28be6232007-11-11 22:23:38 +00001055 env->regs[R_EDI] = tswapl(sc->edi);
1056 env->regs[R_ESI] = tswapl(sc->esi);
1057 env->regs[R_EBP] = tswapl(sc->ebp);
1058 env->regs[R_ESP] = tswapl(sc->esp);
1059 env->regs[R_EBX] = tswapl(sc->ebx);
1060 env->regs[R_EDX] = tswapl(sc->edx);
1061 env->regs[R_ECX] = tswapl(sc->ecx);
1062 env->eip = tswapl(sc->eip);
bellard66fb9762003-03-23 01:06:05 +00001063
Mike McCormack9a826d72011-06-01 15:14:37 +09001064 cpu_x86_load_seg(env, R_CS, lduw_p(&sc->cs) | 3);
1065 cpu_x86_load_seg(env, R_SS, lduw_p(&sc->ss) | 3);
ths5fafdf22007-09-16 21:08:06 +00001066
bellard28be6232007-11-11 22:23:38 +00001067 tmpflags = tswapl(sc->eflags);
1068 env->eflags = (env->eflags & ~0x40DD5) | (tmpflags & 0x40DD5);
1069 // regs->orig_eax = -1; /* disable syscall checks */
1070
1071 fpstate_addr = tswapl(sc->fpstate);
1072 if (fpstate_addr != 0) {
1073 if (!access_ok(VERIFY_READ, fpstate_addr,
1074 sizeof(struct target_fpstate)))
1075 goto badframe;
1076 cpu_x86_frstor(env, fpstate_addr, 1);
bellard66fb9762003-03-23 01:06:05 +00001077 }
1078
bellard28be6232007-11-11 22:23:38 +00001079 *peax = tswapl(sc->eax);
bellard66fb9762003-03-23 01:06:05 +00001080 return err;
bellard66fb9762003-03-23 01:06:05 +00001081badframe:
1082 return 1;
bellard66fb9762003-03-23 01:06:05 +00001083}
1084
1085long do_sigreturn(CPUX86State *env)
1086{
bellard579a97f2007-11-11 14:26:47 +00001087 struct sigframe *frame;
1088 abi_ulong frame_addr = env->regs[R_ESP] - 8;
Anthony Liguoric227f092009-10-01 16:12:16 -05001089 target_sigset_t target_set;
bellard66fb9762003-03-23 01:06:05 +00001090 sigset_t set;
1091 int eax, i;
1092
bellard447db212003-05-10 15:10:36 +00001093#if defined(DEBUG_SIGNAL)
1094 fprintf(stderr, "do_sigreturn\n");
1095#endif
bellard579a97f2007-11-11 14:26:47 +00001096 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
1097 goto badframe;
bellard66fb9762003-03-23 01:06:05 +00001098 /* set blocked signals */
Riku Voipiof5f601a2014-04-23 13:00:17 +03001099 __get_user(target_set.sig[0], &frame->sc.oldmask);
bellard92319442004-06-19 16:58:13 +00001100 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
Riku Voipiof5f601a2014-04-23 13:00:17 +03001101 __get_user(target_set.sig[i], &frame->extramask[i - 1]);
bellard92319442004-06-19 16:58:13 +00001102 }
bellard66fb9762003-03-23 01:06:05 +00001103
bellard92319442004-06-19 16:58:13 +00001104 target_to_host_sigset_internal(&set, &target_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00001105 do_sigprocmask(SIG_SETMASK, &set, NULL);
ths3b46e622007-09-17 08:09:54 +00001106
bellard66fb9762003-03-23 01:06:05 +00001107 /* restore registers */
1108 if (restore_sigcontext(env, &frame->sc, &eax))
1109 goto badframe;
bellard579a97f2007-11-11 14:26:47 +00001110 unlock_user_struct(frame, frame_addr, 0);
bellard66fb9762003-03-23 01:06:05 +00001111 return eax;
1112
1113badframe:
bellard579a97f2007-11-11 14:26:47 +00001114 unlock_user_struct(frame, frame_addr, 0);
bellard66fb9762003-03-23 01:06:05 +00001115 force_sig(TARGET_SIGSEGV);
1116 return 0;
1117}
1118
1119long do_rt_sigreturn(CPUX86State *env)
1120{
bellard28be6232007-11-11 22:23:38 +00001121 abi_ulong frame_addr;
1122 struct rt_sigframe *frame;
bellard66fb9762003-03-23 01:06:05 +00001123 sigset_t set;
bellard66fb9762003-03-23 01:06:05 +00001124 int eax;
1125
bellard28be6232007-11-11 22:23:38 +00001126 frame_addr = env->regs[R_ESP] - 4;
1127 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
1128 goto badframe;
bellardb8076a72005-04-07 22:20:31 +00001129 target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
Alex Barcelo1c275922014-03-14 14:36:55 +00001130 do_sigprocmask(SIG_SETMASK, &set, NULL);
ths5fafdf22007-09-16 21:08:06 +00001131
bellardb8076a72005-04-07 22:20:31 +00001132 if (restore_sigcontext(env, &frame->uc.tuc_mcontext, &eax))
bellard66fb9762003-03-23 01:06:05 +00001133 goto badframe;
1134
bellard28be6232007-11-11 22:23:38 +00001135 if (do_sigaltstack(frame_addr + offsetof(struct rt_sigframe, uc.tuc_stack), 0,
1136 get_sp_from_cpustate(env)) == -EFAULT)
bellard66fb9762003-03-23 01:06:05 +00001137 goto badframe;
thsa04e1342007-09-27 13:57:58 +00001138
bellard28be6232007-11-11 22:23:38 +00001139 unlock_user_struct(frame, frame_addr, 0);
bellard66fb9762003-03-23 01:06:05 +00001140 return eax;
1141
1142badframe:
bellard28be6232007-11-11 22:23:38 +00001143 unlock_user_struct(frame, frame_addr, 0);
1144 force_sig(TARGET_SIGSEGV);
bellard66fb9762003-03-23 01:06:05 +00001145 return 0;
1146}
1147
Andreas Schwab1744aea2013-09-03 20:12:16 +01001148#elif defined(TARGET_AARCH64)
1149
1150struct target_sigcontext {
1151 uint64_t fault_address;
1152 /* AArch64 registers */
1153 uint64_t regs[31];
1154 uint64_t sp;
1155 uint64_t pc;
1156 uint64_t pstate;
1157 /* 4K reserved for FP/SIMD state and future expansion */
1158 char __reserved[4096] __attribute__((__aligned__(16)));
1159};
1160
1161struct target_ucontext {
1162 abi_ulong tuc_flags;
1163 abi_ulong tuc_link;
1164 target_stack_t tuc_stack;
1165 target_sigset_t tuc_sigmask;
1166 /* glibc uses a 1024-bit sigset_t */
1167 char __unused[1024 / 8 - sizeof(target_sigset_t)];
1168 /* last for future expansion */
1169 struct target_sigcontext tuc_mcontext;
1170};
1171
1172/*
1173 * Header to be used at the beginning of structures extending the user
1174 * context. Such structures must be placed after the rt_sigframe on the stack
1175 * and be 16-byte aligned. The last structure must be a dummy one with the
1176 * magic and size set to 0.
1177 */
1178struct target_aarch64_ctx {
1179 uint32_t magic;
1180 uint32_t size;
1181};
1182
1183#define TARGET_FPSIMD_MAGIC 0x46508001
1184
1185struct target_fpsimd_context {
1186 struct target_aarch64_ctx head;
1187 uint32_t fpsr;
1188 uint32_t fpcr;
1189 uint64_t vregs[32 * 2]; /* really uint128_t vregs[32] */
1190};
1191
1192/*
1193 * Auxiliary context saved in the sigcontext.__reserved array. Not exported to
1194 * user space as it will change with the addition of new context. User space
1195 * should check the magic/size information.
1196 */
1197struct target_aux_context {
1198 struct target_fpsimd_context fpsimd;
1199 /* additional context to be added before "end" */
1200 struct target_aarch64_ctx end;
1201};
1202
1203struct target_rt_sigframe {
1204 struct target_siginfo info;
1205 struct target_ucontext uc;
1206 uint64_t fp;
1207 uint64_t lr;
1208 uint32_t tramp[2];
1209};
1210
1211static int target_setup_sigframe(struct target_rt_sigframe *sf,
1212 CPUARMState *env, target_sigset_t *set)
1213{
1214 int i;
1215 struct target_aux_context *aux =
1216 (struct target_aux_context *)sf->uc.tuc_mcontext.__reserved;
1217
1218 /* set up the stack frame for unwinding */
1219 __put_user(env->xregs[29], &sf->fp);
1220 __put_user(env->xregs[30], &sf->lr);
1221
1222 for (i = 0; i < 31; i++) {
1223 __put_user(env->xregs[i], &sf->uc.tuc_mcontext.regs[i]);
1224 }
1225 __put_user(env->xregs[31], &sf->uc.tuc_mcontext.sp);
1226 __put_user(env->pc, &sf->uc.tuc_mcontext.pc);
Peter Maydelld3563122013-12-17 19:42:30 +00001227 __put_user(pstate_read(env), &sf->uc.tuc_mcontext.pstate);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001228
Peter Maydell7af03922014-05-01 18:36:17 +01001229 __put_user(env->exception.vaddress, &sf->uc.tuc_mcontext.fault_address);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001230
1231 for (i = 0; i < TARGET_NSIG_WORDS; i++) {
1232 __put_user(set->sig[i], &sf->uc.tuc_sigmask.sig[i]);
1233 }
1234
1235 for (i = 0; i < 32; i++) {
1236#ifdef TARGET_WORDS_BIGENDIAN
1237 __put_user(env->vfp.regs[i * 2], &aux->fpsimd.vregs[i * 2 + 1]);
1238 __put_user(env->vfp.regs[i * 2 + 1], &aux->fpsimd.vregs[i * 2]);
1239#else
1240 __put_user(env->vfp.regs[i * 2], &aux->fpsimd.vregs[i * 2]);
1241 __put_user(env->vfp.regs[i * 2 + 1], &aux->fpsimd.vregs[i * 2 + 1]);
1242#endif
1243 }
Will Newtone0ee1382014-01-04 22:15:48 +00001244 __put_user(vfp_get_fpsr(env), &aux->fpsimd.fpsr);
1245 __put_user(vfp_get_fpcr(env), &aux->fpsimd.fpcr);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001246 __put_user(TARGET_FPSIMD_MAGIC, &aux->fpsimd.head.magic);
1247 __put_user(sizeof(struct target_fpsimd_context),
1248 &aux->fpsimd.head.size);
1249
1250 /* set the "end" magic */
1251 __put_user(0, &aux->end.magic);
1252 __put_user(0, &aux->end.size);
1253
1254 return 0;
1255}
1256
1257static int target_restore_sigframe(CPUARMState *env,
1258 struct target_rt_sigframe *sf)
1259{
1260 sigset_t set;
1261 int i;
1262 struct target_aux_context *aux =
1263 (struct target_aux_context *)sf->uc.tuc_mcontext.__reserved;
Will Newtone0ee1382014-01-04 22:15:48 +00001264 uint32_t magic, size, fpsr, fpcr;
Peter Maydelld3563122013-12-17 19:42:30 +00001265 uint64_t pstate;
Andreas Schwab1744aea2013-09-03 20:12:16 +01001266
1267 target_to_host_sigset(&set, &sf->uc.tuc_sigmask);
Alex Barcelo1c275922014-03-14 14:36:55 +00001268 do_sigprocmask(SIG_SETMASK, &set, NULL);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001269
1270 for (i = 0; i < 31; i++) {
1271 __get_user(env->xregs[i], &sf->uc.tuc_mcontext.regs[i]);
1272 }
1273
1274 __get_user(env->xregs[31], &sf->uc.tuc_mcontext.sp);
1275 __get_user(env->pc, &sf->uc.tuc_mcontext.pc);
Peter Maydelld3563122013-12-17 19:42:30 +00001276 __get_user(pstate, &sf->uc.tuc_mcontext.pstate);
1277 pstate_write(env, pstate);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001278
1279 __get_user(magic, &aux->fpsimd.head.magic);
1280 __get_user(size, &aux->fpsimd.head.size);
1281
1282 if (magic != TARGET_FPSIMD_MAGIC
1283 || size != sizeof(struct target_fpsimd_context)) {
1284 return 1;
1285 }
1286
Peter Maydell4cf23482014-03-02 19:36:38 +00001287 for (i = 0; i < 32; i++) {
1288#ifdef TARGET_WORDS_BIGENDIAN
1289 __get_user(env->vfp.regs[i * 2], &aux->fpsimd.vregs[i * 2 + 1]);
1290 __get_user(env->vfp.regs[i * 2 + 1], &aux->fpsimd.vregs[i * 2]);
1291#else
1292 __get_user(env->vfp.regs[i * 2], &aux->fpsimd.vregs[i * 2]);
1293 __get_user(env->vfp.regs[i * 2 + 1], &aux->fpsimd.vregs[i * 2 + 1]);
1294#endif
Andreas Schwab1744aea2013-09-03 20:12:16 +01001295 }
Will Newtone0ee1382014-01-04 22:15:48 +00001296 __get_user(fpsr, &aux->fpsimd.fpsr);
1297 vfp_set_fpsr(env, fpsr);
1298 __get_user(fpcr, &aux->fpsimd.fpcr);
1299 vfp_set_fpcr(env, fpcr);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001300
1301 return 0;
1302}
1303
1304static abi_ulong get_sigframe(struct target_sigaction *ka, CPUARMState *env)
1305{
1306 abi_ulong sp;
1307
1308 sp = env->xregs[31];
1309
1310 /*
1311 * This is the X/Open sanctioned signal stack switching.
1312 */
1313 if ((ka->sa_flags & SA_ONSTACK) && !sas_ss_flags(sp)) {
1314 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
1315 }
1316
1317 sp = (sp - sizeof(struct target_rt_sigframe)) & ~15;
1318
1319 return sp;
1320}
1321
1322static void target_setup_frame(int usig, struct target_sigaction *ka,
1323 target_siginfo_t *info, target_sigset_t *set,
1324 CPUARMState *env)
1325{
1326 struct target_rt_sigframe *frame;
Michael Matz8a3ae912014-03-02 19:36:39 +00001327 abi_ulong frame_addr, return_addr;
Andreas Schwab1744aea2013-09-03 20:12:16 +01001328
1329 frame_addr = get_sigframe(ka, env);
1330 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
1331 goto give_sigsegv;
1332 }
1333
1334 __put_user(0, &frame->uc.tuc_flags);
1335 __put_user(0, &frame->uc.tuc_link);
1336
1337 __put_user(target_sigaltstack_used.ss_sp,
1338 &frame->uc.tuc_stack.ss_sp);
1339 __put_user(sas_ss_flags(env->xregs[31]),
1340 &frame->uc.tuc_stack.ss_flags);
1341 __put_user(target_sigaltstack_used.ss_size,
1342 &frame->uc.tuc_stack.ss_size);
1343 target_setup_sigframe(frame, env, set);
Michael Matz8a3ae912014-03-02 19:36:39 +00001344 if (ka->sa_flags & TARGET_SA_RESTORER) {
1345 return_addr = ka->sa_restorer;
1346 } else {
1347 /* mov x8,#__NR_rt_sigreturn; svc #0 */
1348 __put_user(0xd2801168, &frame->tramp[0]);
1349 __put_user(0xd4000001, &frame->tramp[1]);
1350 return_addr = frame_addr + offsetof(struct target_rt_sigframe, tramp);
1351 }
Andreas Schwab1744aea2013-09-03 20:12:16 +01001352 env->xregs[0] = usig;
1353 env->xregs[31] = frame_addr;
1354 env->xregs[29] = env->xregs[31] + offsetof(struct target_rt_sigframe, fp);
1355 env->pc = ka->_sa_handler;
Michael Matz8a3ae912014-03-02 19:36:39 +00001356 env->xregs[30] = return_addr;
Andreas Schwab1744aea2013-09-03 20:12:16 +01001357 if (info) {
Riku Voipiob0fd8d12014-04-23 10:46:13 +03001358 copy_siginfo_to_user(&frame->info, info);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001359 env->xregs[1] = frame_addr + offsetof(struct target_rt_sigframe, info);
1360 env->xregs[2] = frame_addr + offsetof(struct target_rt_sigframe, uc);
1361 }
1362
1363 unlock_user_struct(frame, frame_addr, 1);
1364 return;
1365
1366 give_sigsegv:
1367 unlock_user_struct(frame, frame_addr, 1);
1368 force_sig(TARGET_SIGSEGV);
1369}
1370
1371static void setup_rt_frame(int sig, struct target_sigaction *ka,
1372 target_siginfo_t *info, target_sigset_t *set,
1373 CPUARMState *env)
1374{
1375 target_setup_frame(sig, ka, info, set, env);
1376}
1377
1378static void setup_frame(int sig, struct target_sigaction *ka,
1379 target_sigset_t *set, CPUARMState *env)
1380{
1381 target_setup_frame(sig, ka, 0, set, env);
1382}
1383
1384long do_rt_sigreturn(CPUARMState *env)
1385{
Peter Maydell7f72cd22014-03-12 13:06:00 +00001386 struct target_rt_sigframe *frame = NULL;
Andreas Schwab1744aea2013-09-03 20:12:16 +01001387 abi_ulong frame_addr = env->xregs[31];
1388
1389 if (frame_addr & 15) {
1390 goto badframe;
1391 }
1392
1393 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
1394 goto badframe;
1395 }
1396
1397 if (target_restore_sigframe(env, frame)) {
1398 goto badframe;
1399 }
1400
1401 if (do_sigaltstack(frame_addr +
1402 offsetof(struct target_rt_sigframe, uc.tuc_stack),
1403 0, get_sp_from_cpustate(env)) == -EFAULT) {
1404 goto badframe;
1405 }
1406
1407 unlock_user_struct(frame, frame_addr, 0);
1408 return env->xregs[0];
1409
1410 badframe:
1411 unlock_user_struct(frame, frame_addr, 0);
1412 force_sig(TARGET_SIGSEGV);
1413 return 0;
1414}
1415
1416long do_sigreturn(CPUARMState *env)
1417{
1418 return do_rt_sigreturn(env);
1419}
1420
bellard43fff232003-07-09 19:31:39 +00001421#elif defined(TARGET_ARM)
1422
1423struct target_sigcontext {
blueswir1992f48a2007-10-14 16:27:31 +00001424 abi_ulong trap_no;
1425 abi_ulong error_code;
1426 abi_ulong oldmask;
1427 abi_ulong arm_r0;
1428 abi_ulong arm_r1;
1429 abi_ulong arm_r2;
1430 abi_ulong arm_r3;
1431 abi_ulong arm_r4;
1432 abi_ulong arm_r5;
1433 abi_ulong arm_r6;
1434 abi_ulong arm_r7;
1435 abi_ulong arm_r8;
1436 abi_ulong arm_r9;
1437 abi_ulong arm_r10;
1438 abi_ulong arm_fp;
1439 abi_ulong arm_ip;
1440 abi_ulong arm_sp;
1441 abi_ulong arm_lr;
1442 abi_ulong arm_pc;
1443 abi_ulong arm_cpsr;
1444 abi_ulong fault_address;
bellard43fff232003-07-09 19:31:39 +00001445};
1446
pbrooka745ec62008-05-06 15:36:17 +00001447struct target_ucontext_v1 {
blueswir1992f48a2007-10-14 16:27:31 +00001448 abi_ulong tuc_flags;
1449 abi_ulong tuc_link;
Anthony Liguoric227f092009-10-01 16:12:16 -05001450 target_stack_t tuc_stack;
bellardb8076a72005-04-07 22:20:31 +00001451 struct target_sigcontext tuc_mcontext;
Anthony Liguoric227f092009-10-01 16:12:16 -05001452 target_sigset_t tuc_sigmask; /* mask last for extensibility */
bellard43fff232003-07-09 19:31:39 +00001453};
1454
pbrooka745ec62008-05-06 15:36:17 +00001455struct target_ucontext_v2 {
1456 abi_ulong tuc_flags;
1457 abi_ulong tuc_link;
Anthony Liguoric227f092009-10-01 16:12:16 -05001458 target_stack_t tuc_stack;
pbrooka745ec62008-05-06 15:36:17 +00001459 struct target_sigcontext tuc_mcontext;
Anthony Liguoric227f092009-10-01 16:12:16 -05001460 target_sigset_t tuc_sigmask; /* mask last for extensibility */
Peter Maydell5f0b7c82010-11-24 15:20:03 +00001461 char __unused[128 - sizeof(target_sigset_t)];
pbrooka745ec62008-05-06 15:36:17 +00001462 abi_ulong tuc_regspace[128] __attribute__((__aligned__(8)));
1463};
1464
Peter Maydell0d871bd2010-11-24 15:20:05 +00001465struct target_user_vfp {
1466 uint64_t fpregs[32];
1467 abi_ulong fpscr;
1468};
1469
1470struct target_user_vfp_exc {
1471 abi_ulong fpexc;
1472 abi_ulong fpinst;
1473 abi_ulong fpinst2;
1474};
1475
1476struct target_vfp_sigframe {
1477 abi_ulong magic;
1478 abi_ulong size;
1479 struct target_user_vfp ufp;
1480 struct target_user_vfp_exc ufp_exc;
1481} __attribute__((__aligned__(8)));
1482
Peter Maydell08e11252010-11-24 15:20:07 +00001483struct target_iwmmxt_sigframe {
1484 abi_ulong magic;
1485 abi_ulong size;
1486 uint64_t regs[16];
1487 /* Note that not all the coprocessor control registers are stored here */
1488 uint32_t wcssf;
1489 uint32_t wcasf;
1490 uint32_t wcgr0;
1491 uint32_t wcgr1;
1492 uint32_t wcgr2;
1493 uint32_t wcgr3;
1494} __attribute__((__aligned__(8)));
1495
Peter Maydell0d871bd2010-11-24 15:20:05 +00001496#define TARGET_VFP_MAGIC 0x56465001
Peter Maydell08e11252010-11-24 15:20:07 +00001497#define TARGET_IWMMXT_MAGIC 0x12ef842a
Peter Maydell0d871bd2010-11-24 15:20:05 +00001498
pbrooka8c33202008-05-07 23:22:46 +00001499struct sigframe_v1
bellard43fff232003-07-09 19:31:39 +00001500{
1501 struct target_sigcontext sc;
blueswir1992f48a2007-10-14 16:27:31 +00001502 abi_ulong extramask[TARGET_NSIG_WORDS-1];
1503 abi_ulong retcode;
bellard43fff232003-07-09 19:31:39 +00001504};
1505
pbrooka8c33202008-05-07 23:22:46 +00001506struct sigframe_v2
1507{
1508 struct target_ucontext_v2 uc;
1509 abi_ulong retcode;
1510};
1511
pbrooka745ec62008-05-06 15:36:17 +00001512struct rt_sigframe_v1
bellard43fff232003-07-09 19:31:39 +00001513{
bellardf8b0aa22007-11-11 23:03:42 +00001514 abi_ulong pinfo;
1515 abi_ulong puc;
bellard43fff232003-07-09 19:31:39 +00001516 struct target_siginfo info;
pbrooka745ec62008-05-06 15:36:17 +00001517 struct target_ucontext_v1 uc;
1518 abi_ulong retcode;
1519};
1520
1521struct rt_sigframe_v2
1522{
1523 struct target_siginfo info;
1524 struct target_ucontext_v2 uc;
blueswir1992f48a2007-10-14 16:27:31 +00001525 abi_ulong retcode;
bellard43fff232003-07-09 19:31:39 +00001526};
1527
1528#define TARGET_CONFIG_CPU_32 1
1529
1530/*
1531 * For ARM syscalls, we encode the syscall number into the instruction.
1532 */
1533#define SWI_SYS_SIGRETURN (0xef000000|(TARGET_NR_sigreturn + ARM_SYSCALL_BASE))
1534#define SWI_SYS_RT_SIGRETURN (0xef000000|(TARGET_NR_rt_sigreturn + ARM_SYSCALL_BASE))
1535
1536/*
1537 * For Thumb syscalls, we pass the syscall number via r7. We therefore
1538 * need two 16-bit instructions.
1539 */
1540#define SWI_THUMB_SIGRETURN (0xdf00 << 16 | 0x2700 | (TARGET_NR_sigreturn))
1541#define SWI_THUMB_RT_SIGRETURN (0xdf00 << 16 | 0x2700 | (TARGET_NR_rt_sigreturn))
1542
blueswir1992f48a2007-10-14 16:27:31 +00001543static const abi_ulong retcodes[4] = {
bellard43fff232003-07-09 19:31:39 +00001544 SWI_SYS_SIGRETURN, SWI_THUMB_SIGRETURN,
1545 SWI_SYS_RT_SIGRETURN, SWI_THUMB_RT_SIGRETURN
1546};
1547
1548
Andreas Färber05390242012-02-25 03:37:53 +01001549static inline int valid_user_regs(CPUARMState *regs)
bellard43fff232003-07-09 19:31:39 +00001550{
1551 return 1;
1552}
1553
pbrooka8c33202008-05-07 23:22:46 +00001554static void
bellard43fff232003-07-09 19:31:39 +00001555setup_sigcontext(struct target_sigcontext *sc, /*struct _fpstate *fpstate,*/
Andreas Färber05390242012-02-25 03:37:53 +01001556 CPUARMState *env, abi_ulong mask)
bellard43fff232003-07-09 19:31:39 +00001557{
pbrooka8c33202008-05-07 23:22:46 +00001558 __put_user(env->regs[0], &sc->arm_r0);
1559 __put_user(env->regs[1], &sc->arm_r1);
1560 __put_user(env->regs[2], &sc->arm_r2);
1561 __put_user(env->regs[3], &sc->arm_r3);
1562 __put_user(env->regs[4], &sc->arm_r4);
1563 __put_user(env->regs[5], &sc->arm_r5);
1564 __put_user(env->regs[6], &sc->arm_r6);
1565 __put_user(env->regs[7], &sc->arm_r7);
1566 __put_user(env->regs[8], &sc->arm_r8);
1567 __put_user(env->regs[9], &sc->arm_r9);
1568 __put_user(env->regs[10], &sc->arm_r10);
1569 __put_user(env->regs[11], &sc->arm_fp);
1570 __put_user(env->regs[12], &sc->arm_ip);
1571 __put_user(env->regs[13], &sc->arm_sp);
1572 __put_user(env->regs[14], &sc->arm_lr);
1573 __put_user(env->regs[15], &sc->arm_pc);
bellard43fff232003-07-09 19:31:39 +00001574#ifdef TARGET_CONFIG_CPU_32
pbrooka8c33202008-05-07 23:22:46 +00001575 __put_user(cpsr_read(env), &sc->arm_cpsr);
bellard43fff232003-07-09 19:31:39 +00001576#endif
1577
pbrooka8c33202008-05-07 23:22:46 +00001578 __put_user(/* current->thread.trap_no */ 0, &sc->trap_no);
1579 __put_user(/* current->thread.error_code */ 0, &sc->error_code);
1580 __put_user(/* current->thread.address */ 0, &sc->fault_address);
1581 __put_user(mask, &sc->oldmask);
bellard43fff232003-07-09 19:31:39 +00001582}
1583
bellard579a97f2007-11-11 14:26:47 +00001584static inline abi_ulong
Andreas Färber05390242012-02-25 03:37:53 +01001585get_sigframe(struct target_sigaction *ka, CPUARMState *regs, int framesize)
bellard43fff232003-07-09 19:31:39 +00001586{
1587 unsigned long sp = regs->regs[13];
1588
bellard43fff232003-07-09 19:31:39 +00001589 /*
1590 * This is the X/Open sanctioned signal stack switching.
1591 */
pbrook624f7972008-05-31 16:11:38 +00001592 if ((ka->sa_flags & TARGET_SA_ONSTACK) && !sas_ss_flags(sp))
thsa04e1342007-09-27 13:57:58 +00001593 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
bellard43fff232003-07-09 19:31:39 +00001594 /*
1595 * ATPCS B01 mandates 8-byte alignment
1596 */
bellard579a97f2007-11-11 14:26:47 +00001597 return (sp - framesize) & ~7;
bellard43fff232003-07-09 19:31:39 +00001598}
1599
1600static int
Andreas Färber05390242012-02-25 03:37:53 +01001601setup_return(CPUARMState *env, struct target_sigaction *ka,
bellardf8b0aa22007-11-11 23:03:42 +00001602 abi_ulong *rc, abi_ulong frame_addr, int usig, abi_ulong rc_addr)
bellard43fff232003-07-09 19:31:39 +00001603{
pbrook624f7972008-05-31 16:11:38 +00001604 abi_ulong handler = ka->_sa_handler;
blueswir1992f48a2007-10-14 16:27:31 +00001605 abi_ulong retcode;
pbrook75b680e2008-03-21 16:07:30 +00001606 int thumb = handler & 1;
Peter Maydell964413d2011-01-14 20:39:19 +01001607 uint32_t cpsr = cpsr_read(env);
1608
1609 cpsr &= ~CPSR_IT;
1610 if (thumb) {
1611 cpsr |= CPSR_T;
1612 } else {
1613 cpsr &= ~CPSR_T;
1614 }
bellard43fff232003-07-09 19:31:39 +00001615
pbrook624f7972008-05-31 16:11:38 +00001616 if (ka->sa_flags & TARGET_SA_RESTORER) {
1617 retcode = ka->sa_restorer;
bellard43fff232003-07-09 19:31:39 +00001618 } else {
1619 unsigned int idx = thumb;
1620
pbrook624f7972008-05-31 16:11:38 +00001621 if (ka->sa_flags & TARGET_SA_SIGINFO)
bellard43fff232003-07-09 19:31:39 +00001622 idx += 2;
1623
1624 if (__put_user(retcodes[idx], rc))
1625 return 1;
Stefan Weilca8a2772011-10-03 22:43:19 +02001626
bellardf8b0aa22007-11-11 23:03:42 +00001627 retcode = rc_addr + thumb;
bellard43fff232003-07-09 19:31:39 +00001628 }
1629
1630 env->regs[0] = usig;
bellardf8b0aa22007-11-11 23:03:42 +00001631 env->regs[13] = frame_addr;
bellard43fff232003-07-09 19:31:39 +00001632 env->regs[14] = retcode;
1633 env->regs[15] = handler & (thumb ? ~1 : ~3);
Peter Maydell964413d2011-01-14 20:39:19 +01001634 cpsr_write(env, cpsr, 0xffffffff);
bellard43fff232003-07-09 19:31:39 +00001635
1636 return 0;
1637}
1638
Andreas Färber05390242012-02-25 03:37:53 +01001639static abi_ulong *setup_sigframe_v2_vfp(abi_ulong *regspace, CPUARMState *env)
Peter Maydell0d871bd2010-11-24 15:20:05 +00001640{
1641 int i;
1642 struct target_vfp_sigframe *vfpframe;
1643 vfpframe = (struct target_vfp_sigframe *)regspace;
1644 __put_user(TARGET_VFP_MAGIC, &vfpframe->magic);
1645 __put_user(sizeof(*vfpframe), &vfpframe->size);
1646 for (i = 0; i < 32; i++) {
Peter Maydell005e1a02011-02-10 13:59:35 +00001647 __put_user(float64_val(env->vfp.regs[i]), &vfpframe->ufp.fpregs[i]);
Peter Maydell0d871bd2010-11-24 15:20:05 +00001648 }
1649 __put_user(vfp_get_fpscr(env), &vfpframe->ufp.fpscr);
1650 __put_user(env->vfp.xregs[ARM_VFP_FPEXC], &vfpframe->ufp_exc.fpexc);
1651 __put_user(env->vfp.xregs[ARM_VFP_FPINST], &vfpframe->ufp_exc.fpinst);
1652 __put_user(env->vfp.xregs[ARM_VFP_FPINST2], &vfpframe->ufp_exc.fpinst2);
1653 return (abi_ulong*)(vfpframe+1);
1654}
1655
Andreas Färber05390242012-02-25 03:37:53 +01001656static abi_ulong *setup_sigframe_v2_iwmmxt(abi_ulong *regspace,
1657 CPUARMState *env)
Peter Maydell08e11252010-11-24 15:20:07 +00001658{
1659 int i;
1660 struct target_iwmmxt_sigframe *iwmmxtframe;
1661 iwmmxtframe = (struct target_iwmmxt_sigframe *)regspace;
1662 __put_user(TARGET_IWMMXT_MAGIC, &iwmmxtframe->magic);
1663 __put_user(sizeof(*iwmmxtframe), &iwmmxtframe->size);
1664 for (i = 0; i < 16; i++) {
1665 __put_user(env->iwmmxt.regs[i], &iwmmxtframe->regs[i]);
1666 }
1667 __put_user(env->vfp.xregs[ARM_IWMMXT_wCSSF], &iwmmxtframe->wcssf);
1668 __put_user(env->vfp.xregs[ARM_IWMMXT_wCASF], &iwmmxtframe->wcssf);
1669 __put_user(env->vfp.xregs[ARM_IWMMXT_wCGR0], &iwmmxtframe->wcgr0);
1670 __put_user(env->vfp.xregs[ARM_IWMMXT_wCGR1], &iwmmxtframe->wcgr1);
1671 __put_user(env->vfp.xregs[ARM_IWMMXT_wCGR2], &iwmmxtframe->wcgr2);
1672 __put_user(env->vfp.xregs[ARM_IWMMXT_wCGR3], &iwmmxtframe->wcgr3);
1673 return (abi_ulong*)(iwmmxtframe+1);
1674}
1675
pbrooka8c33202008-05-07 23:22:46 +00001676static void setup_sigframe_v2(struct target_ucontext_v2 *uc,
Andreas Färber05390242012-02-25 03:37:53 +01001677 target_sigset_t *set, CPUARMState *env)
bellard43fff232003-07-09 19:31:39 +00001678{
pbrooka8c33202008-05-07 23:22:46 +00001679 struct target_sigaltstack stack;
1680 int i;
Peter Maydell0d871bd2010-11-24 15:20:05 +00001681 abi_ulong *regspace;
pbrooka8c33202008-05-07 23:22:46 +00001682
1683 /* Clear all the bits of the ucontext we don't use. */
1684 memset(uc, 0, offsetof(struct target_ucontext_v2, tuc_mcontext));
1685
1686 memset(&stack, 0, sizeof(stack));
1687 __put_user(target_sigaltstack_used.ss_sp, &stack.ss_sp);
1688 __put_user(target_sigaltstack_used.ss_size, &stack.ss_size);
1689 __put_user(sas_ss_flags(get_sp_from_cpustate(env)), &stack.ss_flags);
1690 memcpy(&uc->tuc_stack, &stack, sizeof(stack));
1691
1692 setup_sigcontext(&uc->tuc_mcontext, env, set->sig[0]);
Peter Maydell0d871bd2010-11-24 15:20:05 +00001693 /* Save coprocessor signal frame. */
1694 regspace = uc->tuc_regspace;
1695 if (arm_feature(env, ARM_FEATURE_VFP)) {
1696 regspace = setup_sigframe_v2_vfp(regspace, env);
1697 }
Peter Maydell08e11252010-11-24 15:20:07 +00001698 if (arm_feature(env, ARM_FEATURE_IWMMXT)) {
1699 regspace = setup_sigframe_v2_iwmmxt(regspace, env);
1700 }
1701
Peter Maydell0d871bd2010-11-24 15:20:05 +00001702 /* Write terminating magic word */
1703 __put_user(0, regspace);
1704
pbrooka8c33202008-05-07 23:22:46 +00001705 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
1706 __put_user(set->sig[i], &uc->tuc_sigmask.sig[i]);
1707 }
1708}
1709
1710/* compare linux/arch/arm/kernel/signal.c:setup_frame() */
pbrook624f7972008-05-31 16:11:38 +00001711static void setup_frame_v1(int usig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01001712 target_sigset_t *set, CPUARMState *regs)
pbrooka8c33202008-05-07 23:22:46 +00001713{
1714 struct sigframe_v1 *frame;
bellard579a97f2007-11-11 14:26:47 +00001715 abi_ulong frame_addr = get_sigframe(ka, regs, sizeof(*frame));
pbrooka8c33202008-05-07 23:22:46 +00001716 int i;
bellard43fff232003-07-09 19:31:39 +00001717
bellard579a97f2007-11-11 14:26:47 +00001718 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
1719 return;
1720
pbrooka8c33202008-05-07 23:22:46 +00001721 setup_sigcontext(&frame->sc, regs, set->sig[0]);
bellard43fff232003-07-09 19:31:39 +00001722
bellard92319442004-06-19 16:58:13 +00001723 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
1724 if (__put_user(set->sig[i], &frame->extramask[i - 1]))
bellard579a97f2007-11-11 14:26:47 +00001725 goto end;
bellard43fff232003-07-09 19:31:39 +00001726 }
1727
pbrooka8c33202008-05-07 23:22:46 +00001728 setup_return(regs, ka, &frame->retcode, frame_addr, usig,
1729 frame_addr + offsetof(struct sigframe_v1, retcode));
bellard579a97f2007-11-11 14:26:47 +00001730
1731end:
1732 unlock_user_struct(frame, frame_addr, 1);
pbrooka8c33202008-05-07 23:22:46 +00001733}
1734
pbrook624f7972008-05-31 16:11:38 +00001735static void setup_frame_v2(int usig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01001736 target_sigset_t *set, CPUARMState *regs)
pbrooka8c33202008-05-07 23:22:46 +00001737{
1738 struct sigframe_v2 *frame;
1739 abi_ulong frame_addr = get_sigframe(ka, regs, sizeof(*frame));
1740
1741 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
1742 return;
1743
1744 setup_sigframe_v2(&frame->uc, set, regs);
1745
1746 setup_return(regs, ka, &frame->retcode, frame_addr, usig,
1747 frame_addr + offsetof(struct sigframe_v2, retcode));
1748
1749 unlock_user_struct(frame, frame_addr, 1);
1750}
1751
pbrook624f7972008-05-31 16:11:38 +00001752static void setup_frame(int usig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01001753 target_sigset_t *set, CPUARMState *regs)
pbrooka8c33202008-05-07 23:22:46 +00001754{
1755 if (get_osversion() >= 0x020612) {
1756 setup_frame_v2(usig, ka, set, regs);
1757 } else {
1758 setup_frame_v1(usig, ka, set, regs);
1759 }
bellard43fff232003-07-09 19:31:39 +00001760}
1761
bellard579a97f2007-11-11 14:26:47 +00001762/* compare linux/arch/arm/kernel/signal.c:setup_rt_frame() */
pbrook624f7972008-05-31 16:11:38 +00001763static void setup_rt_frame_v1(int usig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05001764 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01001765 target_sigset_t *set, CPUARMState *env)
bellard43fff232003-07-09 19:31:39 +00001766{
pbrooka745ec62008-05-06 15:36:17 +00001767 struct rt_sigframe_v1 *frame;
bellard579a97f2007-11-11 14:26:47 +00001768 abi_ulong frame_addr = get_sigframe(ka, env, sizeof(*frame));
thsa04e1342007-09-27 13:57:58 +00001769 struct target_sigaltstack stack;
pbrooka8c33202008-05-07 23:22:46 +00001770 int i;
bellardf8b0aa22007-11-11 23:03:42 +00001771 abi_ulong info_addr, uc_addr;
bellard43fff232003-07-09 19:31:39 +00001772
bellard579a97f2007-11-11 14:26:47 +00001773 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
bellardedf779f2004-02-22 13:40:13 +00001774 return /* 1 */;
1775
pbrooka745ec62008-05-06 15:36:17 +00001776 info_addr = frame_addr + offsetof(struct rt_sigframe_v1, info);
pbrooka8c33202008-05-07 23:22:46 +00001777 __put_user(info_addr, &frame->pinfo);
pbrooka745ec62008-05-06 15:36:17 +00001778 uc_addr = frame_addr + offsetof(struct rt_sigframe_v1, uc);
pbrooka8c33202008-05-07 23:22:46 +00001779 __put_user(uc_addr, &frame->puc);
1780 copy_siginfo_to_user(&frame->info, info);
bellard43fff232003-07-09 19:31:39 +00001781
1782 /* Clear all the bits of the ucontext we don't use. */
pbrooka745ec62008-05-06 15:36:17 +00001783 memset(&frame->uc, 0, offsetof(struct target_ucontext_v1, tuc_mcontext));
bellard43fff232003-07-09 19:31:39 +00001784
thsa04e1342007-09-27 13:57:58 +00001785 memset(&stack, 0, sizeof(stack));
1786 __put_user(target_sigaltstack_used.ss_sp, &stack.ss_sp);
1787 __put_user(target_sigaltstack_used.ss_size, &stack.ss_size);
1788 __put_user(sas_ss_flags(get_sp_from_cpustate(env)), &stack.ss_flags);
bellard775b58d2007-11-11 16:22:17 +00001789 memcpy(&frame->uc.tuc_stack, &stack, sizeof(stack));
thsa04e1342007-09-27 13:57:58 +00001790
pbrooka8c33202008-05-07 23:22:46 +00001791 setup_sigcontext(&frame->uc.tuc_mcontext, env, set->sig[0]);
bellard92319442004-06-19 16:58:13 +00001792 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
bellardb8076a72005-04-07 22:20:31 +00001793 if (__put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]))
bellard579a97f2007-11-11 14:26:47 +00001794 goto end;
bellard92319442004-06-19 16:58:13 +00001795 }
bellard43fff232003-07-09 19:31:39 +00001796
pbrooka8c33202008-05-07 23:22:46 +00001797 setup_return(env, ka, &frame->retcode, frame_addr, usig,
1798 frame_addr + offsetof(struct rt_sigframe_v1, retcode));
pbrooka745ec62008-05-06 15:36:17 +00001799
pbrooka8c33202008-05-07 23:22:46 +00001800 env->regs[1] = info_addr;
1801 env->regs[2] = uc_addr;
pbrooka745ec62008-05-06 15:36:17 +00001802
1803end:
1804 unlock_user_struct(frame, frame_addr, 1);
pbrooka745ec62008-05-06 15:36:17 +00001805}
1806
pbrook624f7972008-05-31 16:11:38 +00001807static void setup_rt_frame_v2(int usig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05001808 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01001809 target_sigset_t *set, CPUARMState *env)
pbrooka745ec62008-05-06 15:36:17 +00001810{
1811 struct rt_sigframe_v2 *frame;
1812 abi_ulong frame_addr = get_sigframe(ka, env, sizeof(*frame));
pbrooka745ec62008-05-06 15:36:17 +00001813 abi_ulong info_addr, uc_addr;
1814
1815 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
1816 return /* 1 */;
1817
1818 info_addr = frame_addr + offsetof(struct rt_sigframe_v2, info);
1819 uc_addr = frame_addr + offsetof(struct rt_sigframe_v2, uc);
pbrooka8c33202008-05-07 23:22:46 +00001820 copy_siginfo_to_user(&frame->info, info);
pbrooka745ec62008-05-06 15:36:17 +00001821
pbrooka8c33202008-05-07 23:22:46 +00001822 setup_sigframe_v2(&frame->uc, set, env);
pbrooka745ec62008-05-06 15:36:17 +00001823
pbrooka8c33202008-05-07 23:22:46 +00001824 setup_return(env, ka, &frame->retcode, frame_addr, usig,
1825 frame_addr + offsetof(struct rt_sigframe_v2, retcode));
pbrooka745ec62008-05-06 15:36:17 +00001826
pbrooka8c33202008-05-07 23:22:46 +00001827 env->regs[1] = info_addr;
1828 env->regs[2] = uc_addr;
pbrooka745ec62008-05-06 15:36:17 +00001829
bellard579a97f2007-11-11 14:26:47 +00001830 unlock_user_struct(frame, frame_addr, 1);
bellard43fff232003-07-09 19:31:39 +00001831}
1832
pbrook624f7972008-05-31 16:11:38 +00001833static void setup_rt_frame(int usig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05001834 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01001835 target_sigset_t *set, CPUARMState *env)
pbrooka745ec62008-05-06 15:36:17 +00001836{
1837 if (get_osversion() >= 0x020612) {
1838 setup_rt_frame_v2(usig, ka, info, set, env);
1839 } else {
1840 setup_rt_frame_v1(usig, ka, info, set, env);
1841 }
1842}
1843
bellard43fff232003-07-09 19:31:39 +00001844static int
Andreas Färber05390242012-02-25 03:37:53 +01001845restore_sigcontext(CPUARMState *env, struct target_sigcontext *sc)
bellard43fff232003-07-09 19:31:39 +00001846{
1847 int err = 0;
bellardb5ff1b32005-11-26 10:38:39 +00001848 uint32_t cpsr;
bellard43fff232003-07-09 19:31:39 +00001849
Riku Voipio1d8b5122014-04-23 10:26:05 +03001850 __get_user(env->regs[0], &sc->arm_r0);
1851 __get_user(env->regs[1], &sc->arm_r1);
1852 __get_user(env->regs[2], &sc->arm_r2);
1853 __get_user(env->regs[3], &sc->arm_r3);
1854 __get_user(env->regs[4], &sc->arm_r4);
1855 __get_user(env->regs[5], &sc->arm_r5);
1856 __get_user(env->regs[6], &sc->arm_r6);
1857 __get_user(env->regs[7], &sc->arm_r7);
1858 __get_user(env->regs[8], &sc->arm_r8);
1859 __get_user(env->regs[9], &sc->arm_r9);
1860 __get_user(env->regs[10], &sc->arm_r10);
1861 __get_user(env->regs[11], &sc->arm_fp);
1862 __get_user(env->regs[12], &sc->arm_ip);
1863 __get_user(env->regs[13], &sc->arm_sp);
1864 __get_user(env->regs[14], &sc->arm_lr);
1865 __get_user(env->regs[15], &sc->arm_pc);
bellard43fff232003-07-09 19:31:39 +00001866#ifdef TARGET_CONFIG_CPU_32
Riku Voipio1d8b5122014-04-23 10:26:05 +03001867 __get_user(cpsr, &sc->arm_cpsr);
pbrook75b680e2008-03-21 16:07:30 +00001868 cpsr_write(env, cpsr, CPSR_USER | CPSR_EXEC);
bellard43fff232003-07-09 19:31:39 +00001869#endif
1870
1871 err |= !valid_user_regs(env);
1872
1873 return err;
1874}
1875
Andreas Färber05390242012-02-25 03:37:53 +01001876static long do_sigreturn_v1(CPUARMState *env)
bellard43fff232003-07-09 19:31:39 +00001877{
bellardf8b0aa22007-11-11 23:03:42 +00001878 abi_ulong frame_addr;
Peter Maydell978fae92013-07-29 12:00:32 +01001879 struct sigframe_v1 *frame = NULL;
Anthony Liguoric227f092009-10-01 16:12:16 -05001880 target_sigset_t set;
bellard43fff232003-07-09 19:31:39 +00001881 sigset_t host_set;
bellard92319442004-06-19 16:58:13 +00001882 int i;
bellard43fff232003-07-09 19:31:39 +00001883
1884 /*
1885 * Since we stacked the signal on a 64-bit boundary,
1886 * then 'sp' should be word aligned here. If it's
1887 * not, then the user is trying to mess with us.
1888 */
bellardf8b0aa22007-11-11 23:03:42 +00001889 frame_addr = env->regs[13];
Peter Maydell978fae92013-07-29 12:00:32 +01001890 if (frame_addr & 7) {
1891 goto badframe;
1892 }
1893
bellardf8b0aa22007-11-11 23:03:42 +00001894 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
1895 goto badframe;
bellard43fff232003-07-09 19:31:39 +00001896
Riku Voipiof5f601a2014-04-23 13:00:17 +03001897 __get_user(set.sig[0], &frame->sc.oldmask);
1898 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
1899 __get_user(set.sig[i], &frame->extramask[i - 1]);
1900 }
bellard43fff232003-07-09 19:31:39 +00001901
bellard92319442004-06-19 16:58:13 +00001902 target_to_host_sigset_internal(&host_set, &set);
Alex Barcelo1c275922014-03-14 14:36:55 +00001903 do_sigprocmask(SIG_SETMASK, &host_set, NULL);
bellard43fff232003-07-09 19:31:39 +00001904
1905 if (restore_sigcontext(env, &frame->sc))
1906 goto badframe;
1907
1908#if 0
1909 /* Send SIGTRAP if we're single-stepping */
1910 if (ptrace_cancel_bpt(current))
1911 send_sig(SIGTRAP, current, 1);
1912#endif
bellardf8b0aa22007-11-11 23:03:42 +00001913 unlock_user_struct(frame, frame_addr, 0);
1914 return env->regs[0];
bellard43fff232003-07-09 19:31:39 +00001915
1916badframe:
Riku Voipio66393fb2009-12-04 15:16:32 +02001917 force_sig(TARGET_SIGSEGV /* , current */);
bellard43fff232003-07-09 19:31:39 +00001918 return 0;
1919}
1920
Andreas Färber05390242012-02-25 03:37:53 +01001921static abi_ulong *restore_sigframe_v2_vfp(CPUARMState *env, abi_ulong *regspace)
Peter Maydell5f9099d2010-11-24 15:20:06 +00001922{
1923 int i;
1924 abi_ulong magic, sz;
1925 uint32_t fpscr, fpexc;
1926 struct target_vfp_sigframe *vfpframe;
1927 vfpframe = (struct target_vfp_sigframe *)regspace;
1928
1929 __get_user(magic, &vfpframe->magic);
1930 __get_user(sz, &vfpframe->size);
1931 if (magic != TARGET_VFP_MAGIC || sz != sizeof(*vfpframe)) {
1932 return 0;
1933 }
1934 for (i = 0; i < 32; i++) {
Peter Maydell005e1a02011-02-10 13:59:35 +00001935 __get_user(float64_val(env->vfp.regs[i]), &vfpframe->ufp.fpregs[i]);
Peter Maydell5f9099d2010-11-24 15:20:06 +00001936 }
1937 __get_user(fpscr, &vfpframe->ufp.fpscr);
1938 vfp_set_fpscr(env, fpscr);
1939 __get_user(fpexc, &vfpframe->ufp_exc.fpexc);
1940 /* Sanitise FPEXC: ensure VFP is enabled, FPINST2 is invalid
1941 * and the exception flag is cleared
1942 */
1943 fpexc |= (1 << 30);
1944 fpexc &= ~((1 << 31) | (1 << 28));
1945 env->vfp.xregs[ARM_VFP_FPEXC] = fpexc;
1946 __get_user(env->vfp.xregs[ARM_VFP_FPINST], &vfpframe->ufp_exc.fpinst);
1947 __get_user(env->vfp.xregs[ARM_VFP_FPINST2], &vfpframe->ufp_exc.fpinst2);
1948 return (abi_ulong*)(vfpframe + 1);
1949}
1950
Andreas Färber05390242012-02-25 03:37:53 +01001951static abi_ulong *restore_sigframe_v2_iwmmxt(CPUARMState *env,
1952 abi_ulong *regspace)
Peter Maydella59d69d2010-11-24 15:20:08 +00001953{
1954 int i;
1955 abi_ulong magic, sz;
1956 struct target_iwmmxt_sigframe *iwmmxtframe;
1957 iwmmxtframe = (struct target_iwmmxt_sigframe *)regspace;
1958
1959 __get_user(magic, &iwmmxtframe->magic);
1960 __get_user(sz, &iwmmxtframe->size);
1961 if (magic != TARGET_IWMMXT_MAGIC || sz != sizeof(*iwmmxtframe)) {
1962 return 0;
1963 }
1964 for (i = 0; i < 16; i++) {
1965 __get_user(env->iwmmxt.regs[i], &iwmmxtframe->regs[i]);
1966 }
1967 __get_user(env->vfp.xregs[ARM_IWMMXT_wCSSF], &iwmmxtframe->wcssf);
1968 __get_user(env->vfp.xregs[ARM_IWMMXT_wCASF], &iwmmxtframe->wcssf);
1969 __get_user(env->vfp.xregs[ARM_IWMMXT_wCGR0], &iwmmxtframe->wcgr0);
1970 __get_user(env->vfp.xregs[ARM_IWMMXT_wCGR1], &iwmmxtframe->wcgr1);
1971 __get_user(env->vfp.xregs[ARM_IWMMXT_wCGR2], &iwmmxtframe->wcgr2);
1972 __get_user(env->vfp.xregs[ARM_IWMMXT_wCGR3], &iwmmxtframe->wcgr3);
1973 return (abi_ulong*)(iwmmxtframe + 1);
1974}
1975
Andreas Färber05390242012-02-25 03:37:53 +01001976static int do_sigframe_return_v2(CPUARMState *env, target_ulong frame_addr,
pbrooka8c33202008-05-07 23:22:46 +00001977 struct target_ucontext_v2 *uc)
1978{
1979 sigset_t host_set;
Peter Maydell5f9099d2010-11-24 15:20:06 +00001980 abi_ulong *regspace;
pbrooka8c33202008-05-07 23:22:46 +00001981
1982 target_to_host_sigset(&host_set, &uc->tuc_sigmask);
Alex Barcelo1c275922014-03-14 14:36:55 +00001983 do_sigprocmask(SIG_SETMASK, &host_set, NULL);
pbrooka8c33202008-05-07 23:22:46 +00001984
1985 if (restore_sigcontext(env, &uc->tuc_mcontext))
1986 return 1;
1987
Peter Maydell5f9099d2010-11-24 15:20:06 +00001988 /* Restore coprocessor signal frame */
1989 regspace = uc->tuc_regspace;
1990 if (arm_feature(env, ARM_FEATURE_VFP)) {
1991 regspace = restore_sigframe_v2_vfp(env, regspace);
1992 if (!regspace) {
1993 return 1;
1994 }
1995 }
Peter Maydella59d69d2010-11-24 15:20:08 +00001996 if (arm_feature(env, ARM_FEATURE_IWMMXT)) {
1997 regspace = restore_sigframe_v2_iwmmxt(env, regspace);
1998 if (!regspace) {
1999 return 1;
2000 }
2001 }
Peter Maydell5f9099d2010-11-24 15:20:06 +00002002
pbrooka8c33202008-05-07 23:22:46 +00002003 if (do_sigaltstack(frame_addr + offsetof(struct target_ucontext_v2, tuc_stack), 0, get_sp_from_cpustate(env)) == -EFAULT)
2004 return 1;
2005
2006#if 0
2007 /* Send SIGTRAP if we're single-stepping */
2008 if (ptrace_cancel_bpt(current))
2009 send_sig(SIGTRAP, current, 1);
2010#endif
2011
2012 return 0;
2013}
2014
Andreas Färber05390242012-02-25 03:37:53 +01002015static long do_sigreturn_v2(CPUARMState *env)
pbrooka8c33202008-05-07 23:22:46 +00002016{
2017 abi_ulong frame_addr;
Peter Maydell978fae92013-07-29 12:00:32 +01002018 struct sigframe_v2 *frame = NULL;
pbrooka8c33202008-05-07 23:22:46 +00002019
2020 /*
2021 * Since we stacked the signal on a 64-bit boundary,
2022 * then 'sp' should be word aligned here. If it's
2023 * not, then the user is trying to mess with us.
2024 */
pbrooka8c33202008-05-07 23:22:46 +00002025 frame_addr = env->regs[13];
Peter Maydell978fae92013-07-29 12:00:32 +01002026 if (frame_addr & 7) {
2027 goto badframe;
2028 }
2029
pbrooka8c33202008-05-07 23:22:46 +00002030 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
2031 goto badframe;
2032
2033 if (do_sigframe_return_v2(env, frame_addr, &frame->uc))
2034 goto badframe;
2035
2036 unlock_user_struct(frame, frame_addr, 0);
2037 return env->regs[0];
2038
2039badframe:
2040 unlock_user_struct(frame, frame_addr, 0);
Riku Voipio66393fb2009-12-04 15:16:32 +02002041 force_sig(TARGET_SIGSEGV /* , current */);
pbrooka8c33202008-05-07 23:22:46 +00002042 return 0;
2043}
2044
Andreas Färber05390242012-02-25 03:37:53 +01002045long do_sigreturn(CPUARMState *env)
pbrooka8c33202008-05-07 23:22:46 +00002046{
2047 if (get_osversion() >= 0x020612) {
2048 return do_sigreturn_v2(env);
2049 } else {
2050 return do_sigreturn_v1(env);
2051 }
2052}
2053
Andreas Färber05390242012-02-25 03:37:53 +01002054static long do_rt_sigreturn_v1(CPUARMState *env)
bellard43fff232003-07-09 19:31:39 +00002055{
bellardf8b0aa22007-11-11 23:03:42 +00002056 abi_ulong frame_addr;
Peter Maydell978fae92013-07-29 12:00:32 +01002057 struct rt_sigframe_v1 *frame = NULL;
bellard43fff232003-07-09 19:31:39 +00002058 sigset_t host_set;
2059
2060 /*
2061 * Since we stacked the signal on a 64-bit boundary,
2062 * then 'sp' should be word aligned here. If it's
2063 * not, then the user is trying to mess with us.
2064 */
bellardf8b0aa22007-11-11 23:03:42 +00002065 frame_addr = env->regs[13];
Peter Maydell978fae92013-07-29 12:00:32 +01002066 if (frame_addr & 7) {
2067 goto badframe;
2068 }
2069
bellardf8b0aa22007-11-11 23:03:42 +00002070 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
2071 goto badframe;
bellard43fff232003-07-09 19:31:39 +00002072
bellardb8076a72005-04-07 22:20:31 +00002073 target_to_host_sigset(&host_set, &frame->uc.tuc_sigmask);
Alex Barcelo1c275922014-03-14 14:36:55 +00002074 do_sigprocmask(SIG_SETMASK, &host_set, NULL);
bellard43fff232003-07-09 19:31:39 +00002075
bellardb8076a72005-04-07 22:20:31 +00002076 if (restore_sigcontext(env, &frame->uc.tuc_mcontext))
bellard43fff232003-07-09 19:31:39 +00002077 goto badframe;
2078
pbrooka745ec62008-05-06 15:36:17 +00002079 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 +00002080 goto badframe;
2081
bellard43fff232003-07-09 19:31:39 +00002082#if 0
2083 /* Send SIGTRAP if we're single-stepping */
2084 if (ptrace_cancel_bpt(current))
2085 send_sig(SIGTRAP, current, 1);
2086#endif
bellardf8b0aa22007-11-11 23:03:42 +00002087 unlock_user_struct(frame, frame_addr, 0);
bellard43fff232003-07-09 19:31:39 +00002088 return env->regs[0];
2089
2090badframe:
bellardf8b0aa22007-11-11 23:03:42 +00002091 unlock_user_struct(frame, frame_addr, 0);
Riku Voipio66393fb2009-12-04 15:16:32 +02002092 force_sig(TARGET_SIGSEGV /* , current */);
bellard43fff232003-07-09 19:31:39 +00002093 return 0;
2094}
2095
Andreas Färber05390242012-02-25 03:37:53 +01002096static long do_rt_sigreturn_v2(CPUARMState *env)
pbrooka745ec62008-05-06 15:36:17 +00002097{
2098 abi_ulong frame_addr;
Peter Maydell978fae92013-07-29 12:00:32 +01002099 struct rt_sigframe_v2 *frame = NULL;
pbrooka745ec62008-05-06 15:36:17 +00002100
2101 /*
2102 * Since we stacked the signal on a 64-bit boundary,
2103 * then 'sp' should be word aligned here. If it's
2104 * not, then the user is trying to mess with us.
2105 */
pbrooka745ec62008-05-06 15:36:17 +00002106 frame_addr = env->regs[13];
Peter Maydell978fae92013-07-29 12:00:32 +01002107 if (frame_addr & 7) {
2108 goto badframe;
2109 }
2110
pbrooka745ec62008-05-06 15:36:17 +00002111 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
2112 goto badframe;
2113
pbrooka8c33202008-05-07 23:22:46 +00002114 if (do_sigframe_return_v2(env, frame_addr, &frame->uc))
2115 goto badframe;
pbrooka745ec62008-05-06 15:36:17 +00002116
pbrooka745ec62008-05-06 15:36:17 +00002117 unlock_user_struct(frame, frame_addr, 0);
2118 return env->regs[0];
2119
2120badframe:
2121 unlock_user_struct(frame, frame_addr, 0);
Riku Voipio66393fb2009-12-04 15:16:32 +02002122 force_sig(TARGET_SIGSEGV /* , current */);
pbrooka745ec62008-05-06 15:36:17 +00002123 return 0;
2124}
2125
Andreas Färber05390242012-02-25 03:37:53 +01002126long do_rt_sigreturn(CPUARMState *env)
pbrooka745ec62008-05-06 15:36:17 +00002127{
2128 if (get_osversion() >= 0x020612) {
2129 return do_rt_sigreturn_v2(env);
2130 } else {
2131 return do_rt_sigreturn_v1(env);
2132 }
2133}
2134
bellard6d5e2162004-09-30 22:04:13 +00002135#elif defined(TARGET_SPARC)
bellard80a9d032005-01-03 23:31:27 +00002136
bellard6d5e2162004-09-30 22:04:13 +00002137#define __SUNOS_MAXWIN 31
2138
2139/* This is what SunOS does, so shall I. */
2140struct target_sigcontext {
blueswir1992f48a2007-10-14 16:27:31 +00002141 abi_ulong sigc_onstack; /* state to restore */
bellard6d5e2162004-09-30 22:04:13 +00002142
blueswir1992f48a2007-10-14 16:27:31 +00002143 abi_ulong sigc_mask; /* sigmask to restore */
2144 abi_ulong sigc_sp; /* stack pointer */
2145 abi_ulong sigc_pc; /* program counter */
2146 abi_ulong sigc_npc; /* next program counter */
2147 abi_ulong sigc_psr; /* for condition codes etc */
2148 abi_ulong sigc_g1; /* User uses these two registers */
2149 abi_ulong sigc_o0; /* within the trampoline code. */
bellard6d5e2162004-09-30 22:04:13 +00002150
2151 /* Now comes information regarding the users window set
2152 * at the time of the signal.
2153 */
blueswir1992f48a2007-10-14 16:27:31 +00002154 abi_ulong sigc_oswins; /* outstanding windows */
bellard6d5e2162004-09-30 22:04:13 +00002155
2156 /* stack ptrs for each regwin buf */
2157 char *sigc_spbuf[__SUNOS_MAXWIN];
2158
2159 /* Windows to restore after signal */
2160 struct {
blueswir1992f48a2007-10-14 16:27:31 +00002161 abi_ulong locals[8];
2162 abi_ulong ins[8];
bellard6d5e2162004-09-30 22:04:13 +00002163 } sigc_wbuf[__SUNOS_MAXWIN];
2164};
2165/* A Sparc stack frame */
2166struct sparc_stackf {
blueswir1992f48a2007-10-14 16:27:31 +00002167 abi_ulong locals[8];
Peter Maydelle321c342011-02-01 15:54:52 +00002168 abi_ulong ins[8];
2169 /* It's simpler to treat fp and callers_pc as elements of ins[]
2170 * since we never need to access them ourselves.
2171 */
bellard6d5e2162004-09-30 22:04:13 +00002172 char *structptr;
blueswir1992f48a2007-10-14 16:27:31 +00002173 abi_ulong xargs[6];
2174 abi_ulong xxargs[1];
bellard6d5e2162004-09-30 22:04:13 +00002175};
2176
2177typedef struct {
2178 struct {
blueswir1992f48a2007-10-14 16:27:31 +00002179 abi_ulong psr;
2180 abi_ulong pc;
2181 abi_ulong npc;
2182 abi_ulong y;
2183 abi_ulong u_regs[16]; /* globals and ins */
bellard6d5e2162004-09-30 22:04:13 +00002184 } si_regs;
2185 int si_mask;
2186} __siginfo_t;
2187
2188typedef struct {
Blue Swirl8954bae2012-07-30 15:29:11 +00002189 abi_ulong si_float_regs[32];
bellard6d5e2162004-09-30 22:04:13 +00002190 unsigned long si_fsr;
2191 unsigned long si_fpqdepth;
2192 struct {
2193 unsigned long *insn_addr;
2194 unsigned long insn;
2195 } si_fpqueue [16];
Anthony Liguoric227f092009-10-01 16:12:16 -05002196} qemu_siginfo_fpu_t;
bellard6d5e2162004-09-30 22:04:13 +00002197
2198
2199struct target_signal_frame {
2200 struct sparc_stackf ss;
2201 __siginfo_t info;
bellardf8b0aa22007-11-11 23:03:42 +00002202 abi_ulong fpu_save;
blueswir1992f48a2007-10-14 16:27:31 +00002203 abi_ulong insns[2] __attribute__ ((aligned (8)));
2204 abi_ulong extramask[TARGET_NSIG_WORDS - 1];
2205 abi_ulong extra_size; /* Should be 0 */
Anthony Liguoric227f092009-10-01 16:12:16 -05002206 qemu_siginfo_fpu_t fpu_state;
bellard6d5e2162004-09-30 22:04:13 +00002207};
2208struct target_rt_signal_frame {
2209 struct sparc_stackf ss;
2210 siginfo_t info;
blueswir1992f48a2007-10-14 16:27:31 +00002211 abi_ulong regs[20];
bellard6d5e2162004-09-30 22:04:13 +00002212 sigset_t mask;
bellardf8b0aa22007-11-11 23:03:42 +00002213 abi_ulong fpu_save;
bellard6d5e2162004-09-30 22:04:13 +00002214 unsigned int insns[2];
2215 stack_t stack;
2216 unsigned int extra_size; /* Should be 0 */
Anthony Liguoric227f092009-10-01 16:12:16 -05002217 qemu_siginfo_fpu_t fpu_state;
bellard6d5e2162004-09-30 22:04:13 +00002218};
2219
bellarde80cfcf2004-12-19 23:18:01 +00002220#define UREG_O0 16
2221#define UREG_O6 22
2222#define UREG_I0 0
2223#define UREG_I1 1
2224#define UREG_I2 2
blueswir15bfb56b2007-10-05 17:01:51 +00002225#define UREG_I3 3
2226#define UREG_I4 4
2227#define UREG_I5 5
bellarde80cfcf2004-12-19 23:18:01 +00002228#define UREG_I6 6
2229#define UREG_I7 7
2230#define UREG_L0 8
bellard6d5e2162004-09-30 22:04:13 +00002231#define UREG_FP UREG_I6
2232#define UREG_SP UREG_O6
2233
pbrook624f7972008-05-31 16:11:38 +00002234static inline abi_ulong get_sigframe(struct target_sigaction *sa,
Andreas Färber05390242012-02-25 03:37:53 +01002235 CPUSPARCState *env,
2236 unsigned long framesize)
bellard6d5e2162004-09-30 22:04:13 +00002237{
bellard459a4012007-11-11 19:45:10 +00002238 abi_ulong sp;
bellard6d5e2162004-09-30 22:04:13 +00002239
2240 sp = env->regwptr[UREG_FP];
bellard6d5e2162004-09-30 22:04:13 +00002241
2242 /* This is the X/Open sanctioned signal stack switching. */
pbrook624f7972008-05-31 16:11:38 +00002243 if (sa->sa_flags & TARGET_SA_ONSTACK) {
thsa04e1342007-09-27 13:57:58 +00002244 if (!on_sig_stack(sp)
2245 && !((target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size) & 7))
2246 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
bellard6d5e2162004-09-30 22:04:13 +00002247 }
bellard459a4012007-11-11 19:45:10 +00002248 return sp - framesize;
bellard6d5e2162004-09-30 22:04:13 +00002249}
2250
2251static int
Andreas Färber05390242012-02-25 03:37:53 +01002252setup___siginfo(__siginfo_t *si, CPUSPARCState *env, abi_ulong mask)
bellard6d5e2162004-09-30 22:04:13 +00002253{
2254 int err = 0, i;
2255
Riku Voipio1d8b5122014-04-23 10:26:05 +03002256 __put_user(env->psr, &si->si_regs.psr);
2257 __put_user(env->pc, &si->si_regs.pc);
2258 __put_user(env->npc, &si->si_regs.npc);
2259 __put_user(env->y, &si->si_regs.y);
bellarda315a142005-01-30 22:59:18 +00002260 for (i=0; i < 8; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002261 __put_user(env->gregs[i], &si->si_regs.u_regs[i]);
bellard6d5e2162004-09-30 22:04:13 +00002262 }
bellarda315a142005-01-30 22:59:18 +00002263 for (i=0; i < 8; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002264 __put_user(env->regwptr[UREG_I0 + i], &si->si_regs.u_regs[i+8]);
bellard6d5e2162004-09-30 22:04:13 +00002265 }
Riku Voipio1d8b5122014-04-23 10:26:05 +03002266 __put_user(mask, &si->si_mask);
bellard6d5e2162004-09-30 22:04:13 +00002267 return err;
2268}
bellarde80cfcf2004-12-19 23:18:01 +00002269
bellard80a9d032005-01-03 23:31:27 +00002270#if 0
bellard6d5e2162004-09-30 22:04:13 +00002271static int
2272setup_sigcontext(struct target_sigcontext *sc, /*struct _fpstate *fpstate,*/
Andreas Färber05390242012-02-25 03:37:53 +01002273 CPUSPARCState *env, unsigned long mask)
bellard6d5e2162004-09-30 22:04:13 +00002274{
2275 int err = 0;
2276
Riku Voipio1d8b5122014-04-23 10:26:05 +03002277 __put_user(mask, &sc->sigc_mask);
2278 __put_user(env->regwptr[UREG_SP], &sc->sigc_sp);
2279 __put_user(env->pc, &sc->sigc_pc);
2280 __put_user(env->npc, &sc->sigc_npc);
2281 __put_user(env->psr, &sc->sigc_psr);
2282 __put_user(env->gregs[1], &sc->sigc_g1);
2283 __put_user(env->regwptr[UREG_O0], &sc->sigc_o0);
bellard6d5e2162004-09-30 22:04:13 +00002284
2285 return err;
2286}
bellard80a9d032005-01-03 23:31:27 +00002287#endif
bellard6d5e2162004-09-30 22:04:13 +00002288#define NF_ALIGNEDSZ (((sizeof(struct target_signal_frame) + 7) & (~7)))
2289
pbrook624f7972008-05-31 16:11:38 +00002290static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01002291 target_sigset_t *set, CPUSPARCState *env)
bellard6d5e2162004-09-30 22:04:13 +00002292{
bellard459a4012007-11-11 19:45:10 +00002293 abi_ulong sf_addr;
bellard6d5e2162004-09-30 22:04:13 +00002294 struct target_signal_frame *sf;
2295 int sigframe_size, err, i;
2296
2297 /* 1. Make sure everything is clean */
2298 //synchronize_user_stack();
2299
2300 sigframe_size = NF_ALIGNEDSZ;
bellard459a4012007-11-11 19:45:10 +00002301 sf_addr = get_sigframe(ka, env, sigframe_size);
bellard6d5e2162004-09-30 22:04:13 +00002302
bellard459a4012007-11-11 19:45:10 +00002303 sf = lock_user(VERIFY_WRITE, sf_addr,
2304 sizeof(struct target_signal_frame), 0);
2305 if (!sf)
2306 goto sigsegv;
2307
bellarde80cfcf2004-12-19 23:18:01 +00002308 //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 +00002309#if 0
2310 if (invalid_frame_pointer(sf, sigframe_size))
2311 goto sigill_and_return;
2312#endif
2313 /* 2. Save the current process state */
2314 err = setup___siginfo(&sf->info, env, set->sig[0]);
Riku Voipio1d8b5122014-04-23 10:26:05 +03002315 __put_user(0, &sf->extra_size);
bellard6d5e2162004-09-30 22:04:13 +00002316
Riku Voipio1d8b5122014-04-23 10:26:05 +03002317 //save_fpu_state(regs, &sf->fpu_state);
2318 //__put_user(&sf->fpu_state, &sf->fpu_save);
bellard6d5e2162004-09-30 22:04:13 +00002319
Riku Voipio1d8b5122014-04-23 10:26:05 +03002320 __put_user(set->sig[0], &sf->info.si_mask);
bellard6d5e2162004-09-30 22:04:13 +00002321 for (i = 0; i < TARGET_NSIG_WORDS - 1; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002322 __put_user(set->sig[i + 1], &sf->extramask[i]);
bellard6d5e2162004-09-30 22:04:13 +00002323 }
2324
bellarda315a142005-01-30 22:59:18 +00002325 for (i = 0; i < 8; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002326 __put_user(env->regwptr[i + UREG_L0], &sf->ss.locals[i]);
bellard6d5e2162004-09-30 22:04:13 +00002327 }
bellarda315a142005-01-30 22:59:18 +00002328 for (i = 0; i < 8; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002329 __put_user(env->regwptr[i + UREG_I0], &sf->ss.ins[i]);
bellard6d5e2162004-09-30 22:04:13 +00002330 }
bellard6d5e2162004-09-30 22:04:13 +00002331 if (err)
2332 goto sigsegv;
2333
2334 /* 3. signal handler back-trampoline and parameters */
bellard459a4012007-11-11 19:45:10 +00002335 env->regwptr[UREG_FP] = sf_addr;
bellard6d5e2162004-09-30 22:04:13 +00002336 env->regwptr[UREG_I0] = sig;
bellard459a4012007-11-11 19:45:10 +00002337 env->regwptr[UREG_I1] = sf_addr +
2338 offsetof(struct target_signal_frame, info);
2339 env->regwptr[UREG_I2] = sf_addr +
2340 offsetof(struct target_signal_frame, info);
bellard6d5e2162004-09-30 22:04:13 +00002341
2342 /* 4. signal handler */
pbrook624f7972008-05-31 16:11:38 +00002343 env->pc = ka->_sa_handler;
bellard6d5e2162004-09-30 22:04:13 +00002344 env->npc = (env->pc + 4);
2345 /* 5. return to kernel instructions */
pbrook624f7972008-05-31 16:11:38 +00002346 if (ka->sa_restorer)
2347 env->regwptr[UREG_I7] = ka->sa_restorer;
bellard6d5e2162004-09-30 22:04:13 +00002348 else {
bellard775b58d2007-11-11 16:22:17 +00002349 uint32_t val32;
bellard459a4012007-11-11 19:45:10 +00002350
2351 env->regwptr[UREG_I7] = sf_addr +
2352 offsetof(struct target_signal_frame, insns) - 2 * 4;
bellard6d5e2162004-09-30 22:04:13 +00002353
2354 /* mov __NR_sigreturn, %g1 */
bellard775b58d2007-11-11 16:22:17 +00002355 val32 = 0x821020d8;
Riku Voipio1d8b5122014-04-23 10:26:05 +03002356 __put_user(val32, &sf->insns[0]);
bellard6d5e2162004-09-30 22:04:13 +00002357
2358 /* t 0x10 */
bellard775b58d2007-11-11 16:22:17 +00002359 val32 = 0x91d02010;
Riku Voipio1d8b5122014-04-23 10:26:05 +03002360 __put_user(val32, &sf->insns[1]);
bellard6d5e2162004-09-30 22:04:13 +00002361 if (err)
2362 goto sigsegv;
2363
2364 /* Flush instruction space. */
2365 //flush_sig_insns(current->mm, (unsigned long) &(sf->insns[0]));
bellard80a9d032005-01-03 23:31:27 +00002366 // tb_flush(env);
bellard6d5e2162004-09-30 22:04:13 +00002367 }
bellard459a4012007-11-11 19:45:10 +00002368 unlock_user(sf, sf_addr, sizeof(struct target_signal_frame));
bellard6d5e2162004-09-30 22:04:13 +00002369 return;
bellard459a4012007-11-11 19:45:10 +00002370#if 0
2371sigill_and_return:
bellard6d5e2162004-09-30 22:04:13 +00002372 force_sig(TARGET_SIGILL);
bellard459a4012007-11-11 19:45:10 +00002373#endif
bellard6d5e2162004-09-30 22:04:13 +00002374sigsegv:
bellarde80cfcf2004-12-19 23:18:01 +00002375 //fprintf(stderr, "force_sig\n");
bellard459a4012007-11-11 19:45:10 +00002376 unlock_user(sf, sf_addr, sizeof(struct target_signal_frame));
bellard6d5e2162004-09-30 22:04:13 +00002377 force_sig(TARGET_SIGSEGV);
2378}
bellard6d5e2162004-09-30 22:04:13 +00002379
pbrook624f7972008-05-31 16:11:38 +00002380static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05002381 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01002382 target_sigset_t *set, CPUSPARCState *env)
bellard6d5e2162004-09-30 22:04:13 +00002383{
2384 fprintf(stderr, "setup_rt_frame: not implemented\n");
2385}
2386
Andreas Färber05390242012-02-25 03:37:53 +01002387long do_sigreturn(CPUSPARCState *env)
bellard6d5e2162004-09-30 22:04:13 +00002388{
bellardf8b0aa22007-11-11 23:03:42 +00002389 abi_ulong sf_addr;
bellard6d5e2162004-09-30 22:04:13 +00002390 struct target_signal_frame *sf;
bellarde80cfcf2004-12-19 23:18:01 +00002391 uint32_t up_psr, pc, npc;
Anthony Liguoric227f092009-10-01 16:12:16 -05002392 target_sigset_t set;
bellarde80cfcf2004-12-19 23:18:01 +00002393 sigset_t host_set;
Riku Voipio1d8b5122014-04-23 10:26:05 +03002394 int err=0, i;
bellard6d5e2162004-09-30 22:04:13 +00002395
bellardf8b0aa22007-11-11 23:03:42 +00002396 sf_addr = env->regwptr[UREG_FP];
2397 if (!lock_user_struct(VERIFY_READ, sf, sf_addr, 1))
2398 goto segv_and_exit;
bellard80a9d032005-01-03 23:31:27 +00002399#if 0
bellarde80cfcf2004-12-19 23:18:01 +00002400 fprintf(stderr, "sigreturn\n");
2401 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 +00002402#endif
bellarde80cfcf2004-12-19 23:18:01 +00002403 //cpu_dump_state(env, stderr, fprintf, 0);
bellard6d5e2162004-09-30 22:04:13 +00002404
2405 /* 1. Make sure we are not getting garbage from the user */
bellard6d5e2162004-09-30 22:04:13 +00002406
bellardf8b0aa22007-11-11 23:03:42 +00002407 if (sf_addr & 3)
bellard6d5e2162004-09-30 22:04:13 +00002408 goto segv_and_exit;
2409
Riku Voipio1d8b5122014-04-23 10:26:05 +03002410 __get_user(pc, &sf->info.si_regs.pc);
2411 __get_user(npc, &sf->info.si_regs.npc);
bellard6d5e2162004-09-30 22:04:13 +00002412
bellard6d5e2162004-09-30 22:04:13 +00002413 if ((pc | npc) & 3)
2414 goto segv_and_exit;
2415
2416 /* 2. Restore the state */
Riku Voipio1d8b5122014-04-23 10:26:05 +03002417 __get_user(up_psr, &sf->info.si_regs.psr);
bellarde80cfcf2004-12-19 23:18:01 +00002418
bellard6d5e2162004-09-30 22:04:13 +00002419 /* User can only change condition codes and FPU enabling in %psr. */
bellarda315a142005-01-30 22:59:18 +00002420 env->psr = (up_psr & (PSR_ICC /* | PSR_EF */))
2421 | (env->psr & ~(PSR_ICC /* | PSR_EF */));
2422
2423 env->pc = pc;
2424 env->npc = npc;
Riku Voipio1d8b5122014-04-23 10:26:05 +03002425 __get_user(env->y, &sf->info.si_regs.y);
bellarda315a142005-01-30 22:59:18 +00002426 for (i=0; i < 8; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002427 __get_user(env->gregs[i], &sf->info.si_regs.u_regs[i]);
bellarde80cfcf2004-12-19 23:18:01 +00002428 }
bellarda315a142005-01-30 22:59:18 +00002429 for (i=0; i < 8; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002430 __get_user(env->regwptr[i + UREG_I0], &sf->info.si_regs.u_regs[i+8]);
bellarde80cfcf2004-12-19 23:18:01 +00002431 }
bellard6d5e2162004-09-30 22:04:13 +00002432
Peter Maydell2aec3a22011-06-16 17:37:14 +01002433 /* FIXME: implement FPU save/restore:
2434 * __get_user(fpu_save, &sf->fpu_save);
2435 * if (fpu_save)
2436 * err |= restore_fpu_state(env, fpu_save);
2437 */
bellard6d5e2162004-09-30 22:04:13 +00002438
2439 /* This is pretty much atomic, no amount locking would prevent
2440 * the races which exist anyways.
2441 */
Riku Voipio1d8b5122014-04-23 10:26:05 +03002442 __get_user(set.sig[0], &sf->info.si_mask);
bellarde80cfcf2004-12-19 23:18:01 +00002443 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002444 __get_user(set.sig[i], &sf->extramask[i - 1]);
bellarde80cfcf2004-12-19 23:18:01 +00002445 }
2446
2447 target_to_host_sigset_internal(&host_set, &set);
Alex Barcelo1c275922014-03-14 14:36:55 +00002448 do_sigprocmask(SIG_SETMASK, &host_set, NULL);
bellard6d5e2162004-09-30 22:04:13 +00002449
2450 if (err)
2451 goto segv_and_exit;
bellardf8b0aa22007-11-11 23:03:42 +00002452 unlock_user_struct(sf, sf_addr, 0);
bellard6d5e2162004-09-30 22:04:13 +00002453 return env->regwptr[0];
2454
2455segv_and_exit:
bellardf8b0aa22007-11-11 23:03:42 +00002456 unlock_user_struct(sf, sf_addr, 0);
bellard6d5e2162004-09-30 22:04:13 +00002457 force_sig(TARGET_SIGSEGV);
2458}
2459
Andreas Färber05390242012-02-25 03:37:53 +01002460long do_rt_sigreturn(CPUSPARCState *env)
bellard6d5e2162004-09-30 22:04:13 +00002461{
2462 fprintf(stderr, "do_rt_sigreturn: not implemented\n");
bellardf8b0aa22007-11-11 23:03:42 +00002463 return -TARGET_ENOSYS;
bellard6d5e2162004-09-30 22:04:13 +00002464}
2465
bellard459a4012007-11-11 19:45:10 +00002466#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
blueswir15bfb56b2007-10-05 17:01:51 +00002467#define MC_TSTATE 0
2468#define MC_PC 1
2469#define MC_NPC 2
2470#define MC_Y 3
2471#define MC_G1 4
2472#define MC_G2 5
2473#define MC_G3 6
2474#define MC_G4 7
2475#define MC_G5 8
2476#define MC_G6 9
2477#define MC_G7 10
2478#define MC_O0 11
2479#define MC_O1 12
2480#define MC_O2 13
2481#define MC_O3 14
2482#define MC_O4 15
2483#define MC_O5 16
2484#define MC_O6 17
2485#define MC_O7 18
2486#define MC_NGREG 19
2487
Anthony Liguoric227f092009-10-01 16:12:16 -05002488typedef abi_ulong target_mc_greg_t;
2489typedef target_mc_greg_t target_mc_gregset_t[MC_NGREG];
blueswir15bfb56b2007-10-05 17:01:51 +00002490
2491struct target_mc_fq {
blueswir1992f48a2007-10-14 16:27:31 +00002492 abi_ulong *mcfq_addr;
blueswir15bfb56b2007-10-05 17:01:51 +00002493 uint32_t mcfq_insn;
2494};
2495
2496struct target_mc_fpu {
2497 union {
2498 uint32_t sregs[32];
2499 uint64_t dregs[32];
2500 //uint128_t qregs[16];
2501 } mcfpu_fregs;
blueswir1992f48a2007-10-14 16:27:31 +00002502 abi_ulong mcfpu_fsr;
2503 abi_ulong mcfpu_fprs;
2504 abi_ulong mcfpu_gsr;
blueswir15bfb56b2007-10-05 17:01:51 +00002505 struct target_mc_fq *mcfpu_fq;
2506 unsigned char mcfpu_qcnt;
2507 unsigned char mcfpu_qentsz;
2508 unsigned char mcfpu_enab;
2509};
Anthony Liguoric227f092009-10-01 16:12:16 -05002510typedef struct target_mc_fpu target_mc_fpu_t;
blueswir15bfb56b2007-10-05 17:01:51 +00002511
2512typedef struct {
Anthony Liguoric227f092009-10-01 16:12:16 -05002513 target_mc_gregset_t mc_gregs;
2514 target_mc_greg_t mc_fp;
2515 target_mc_greg_t mc_i7;
2516 target_mc_fpu_t mc_fpregs;
2517} target_mcontext_t;
blueswir15bfb56b2007-10-05 17:01:51 +00002518
2519struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02002520 struct target_ucontext *tuc_link;
2521 abi_ulong tuc_flags;
2522 target_sigset_t tuc_sigmask;
2523 target_mcontext_t tuc_mcontext;
blueswir15bfb56b2007-10-05 17:01:51 +00002524};
2525
2526/* A V9 register window */
2527struct target_reg_window {
blueswir1992f48a2007-10-14 16:27:31 +00002528 abi_ulong locals[8];
2529 abi_ulong ins[8];
blueswir15bfb56b2007-10-05 17:01:51 +00002530};
2531
2532#define TARGET_STACK_BIAS 2047
2533
2534/* {set, get}context() needed for 64-bit SparcLinux userland. */
2535void sparc64_set_context(CPUSPARCState *env)
2536{
bellard459a4012007-11-11 19:45:10 +00002537 abi_ulong ucp_addr;
2538 struct target_ucontext *ucp;
Anthony Liguoric227f092009-10-01 16:12:16 -05002539 target_mc_gregset_t *grp;
blueswir1992f48a2007-10-14 16:27:31 +00002540 abi_ulong pc, npc, tstate;
bellard459a4012007-11-11 19:45:10 +00002541 abi_ulong fp, i7, w_addr;
Riku Voipio1d8b5122014-04-23 10:26:05 +03002542 int err = 0;
blueswir15bfb56b2007-10-05 17:01:51 +00002543 unsigned int i;
blueswir15bfb56b2007-10-05 17:01:51 +00002544
bellard459a4012007-11-11 19:45:10 +00002545 ucp_addr = env->regwptr[UREG_I0];
2546 if (!lock_user_struct(VERIFY_READ, ucp, ucp_addr, 1))
2547 goto do_sigsegv;
Aurelien Jarno60e99242010-03-29 02:12:51 +02002548 grp = &ucp->tuc_mcontext.mc_gregs;
Riku Voipio1d8b5122014-04-23 10:26:05 +03002549 __get_user(pc, &((*grp)[MC_PC]));
2550 __get_user(npc, &((*grp)[MC_NPC]));
blueswir15bfb56b2007-10-05 17:01:51 +00002551 if (err || ((pc | npc) & 3))
2552 goto do_sigsegv;
2553 if (env->regwptr[UREG_I1]) {
Anthony Liguoric227f092009-10-01 16:12:16 -05002554 target_sigset_t target_set;
blueswir15bfb56b2007-10-05 17:01:51 +00002555 sigset_t set;
2556
2557 if (TARGET_NSIG_WORDS == 1) {
Aurelien Jarno60e99242010-03-29 02:12:51 +02002558 if (__get_user(target_set.sig[0], &ucp->tuc_sigmask.sig[0]))
blueswir15bfb56b2007-10-05 17:01:51 +00002559 goto do_sigsegv;
2560 } else {
bellard459a4012007-11-11 19:45:10 +00002561 abi_ulong *src, *dst;
Aurelien Jarno60e99242010-03-29 02:12:51 +02002562 src = ucp->tuc_sigmask.sig;
bellard459a4012007-11-11 19:45:10 +00002563 dst = target_set.sig;
Stefan Weil0d9e61c2013-12-07 14:48:08 +01002564 for (i = 0; i < TARGET_NSIG_WORDS; i++, dst++, src++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002565 __get_user(*dst, src);
Stefan Weil0d9e61c2013-12-07 14:48:08 +01002566 }
blueswir15bfb56b2007-10-05 17:01:51 +00002567 if (err)
2568 goto do_sigsegv;
2569 }
2570 target_to_host_sigset_internal(&set, &target_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00002571 do_sigprocmask(SIG_SETMASK, &set, NULL);
blueswir15bfb56b2007-10-05 17:01:51 +00002572 }
2573 env->pc = pc;
2574 env->npc = npc;
Riku Voipio1d8b5122014-04-23 10:26:05 +03002575 __get_user(env->y, &((*grp)[MC_Y]));
2576 __get_user(tstate, &((*grp)[MC_TSTATE]));
blueswir15bfb56b2007-10-05 17:01:51 +00002577 env->asi = (tstate >> 24) & 0xff;
Blue Swirl5a834bb2010-05-09 20:19:04 +00002578 cpu_put_ccr(env, tstate >> 32);
2579 cpu_put_cwp64(env, tstate & 0x1f);
Riku Voipio1d8b5122014-04-23 10:26:05 +03002580 __get_user(env->gregs[1], (&(*grp)[MC_G1]));
2581 __get_user(env->gregs[2], (&(*grp)[MC_G2]));
2582 __get_user(env->gregs[3], (&(*grp)[MC_G3]));
2583 __get_user(env->gregs[4], (&(*grp)[MC_G4]));
2584 __get_user(env->gregs[5], (&(*grp)[MC_G5]));
2585 __get_user(env->gregs[6], (&(*grp)[MC_G6]));
2586 __get_user(env->gregs[7], (&(*grp)[MC_G7]));
2587 __get_user(env->regwptr[UREG_I0], (&(*grp)[MC_O0]));
2588 __get_user(env->regwptr[UREG_I1], (&(*grp)[MC_O1]));
2589 __get_user(env->regwptr[UREG_I2], (&(*grp)[MC_O2]));
2590 __get_user(env->regwptr[UREG_I3], (&(*grp)[MC_O3]));
2591 __get_user(env->regwptr[UREG_I4], (&(*grp)[MC_O4]));
2592 __get_user(env->regwptr[UREG_I5], (&(*grp)[MC_O5]));
2593 __get_user(env->regwptr[UREG_I6], (&(*grp)[MC_O6]));
2594 __get_user(env->regwptr[UREG_I7], (&(*grp)[MC_O7]));
blueswir15bfb56b2007-10-05 17:01:51 +00002595
Riku Voipio1d8b5122014-04-23 10:26:05 +03002596 __get_user(fp, &(ucp->tuc_mcontext.mc_fp));
2597 __get_user(i7, &(ucp->tuc_mcontext.mc_i7));
blueswir15bfb56b2007-10-05 17:01:51 +00002598
bellard459a4012007-11-11 19:45:10 +00002599 w_addr = TARGET_STACK_BIAS+env->regwptr[UREG_I6];
2600 if (put_user(fp, w_addr + offsetof(struct target_reg_window, ins[6]),
2601 abi_ulong) != 0)
2602 goto do_sigsegv;
2603 if (put_user(i7, w_addr + offsetof(struct target_reg_window, ins[7]),
2604 abi_ulong) != 0)
2605 goto do_sigsegv;
Peter Maydellc7b016b2011-06-16 17:37:15 +01002606 /* FIXME this does not match how the kernel handles the FPU in
2607 * its sparc64_set_context implementation. In particular the FPU
2608 * is only restored if fenab is non-zero in:
2609 * __get_user(fenab, &(ucp->tuc_mcontext.mc_fpregs.mcfpu_enab));
2610 */
Aurelien Jarno60e99242010-03-29 02:12:51 +02002611 err |= __get_user(env->fprs, &(ucp->tuc_mcontext.mc_fpregs.mcfpu_fprs));
bellard459a4012007-11-11 19:45:10 +00002612 {
Richard Henderson30038fd2011-10-17 10:42:49 -07002613 uint32_t *src = ucp->tuc_mcontext.mc_fpregs.mcfpu_fregs.sregs;
2614 for (i = 0; i < 64; i++, src++) {
2615 if (i & 1) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002616 __get_user(env->fpr[i/2].l.lower, src);
Richard Henderson30038fd2011-10-17 10:42:49 -07002617 } else {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002618 __get_user(env->fpr[i/2].l.upper, src);
Richard Henderson30038fd2011-10-17 10:42:49 -07002619 }
2620 }
bellard459a4012007-11-11 19:45:10 +00002621 }
Riku Voipio1d8b5122014-04-23 10:26:05 +03002622 __get_user(env->fsr,
2623 &(ucp->tuc_mcontext.mc_fpregs.mcfpu_fsr));
2624 __get_user(env->gsr,
2625 &(ucp->tuc_mcontext.mc_fpregs.mcfpu_gsr));
blueswir15bfb56b2007-10-05 17:01:51 +00002626 if (err)
2627 goto do_sigsegv;
bellard459a4012007-11-11 19:45:10 +00002628 unlock_user_struct(ucp, ucp_addr, 0);
blueswir15bfb56b2007-10-05 17:01:51 +00002629 return;
2630 do_sigsegv:
bellard459a4012007-11-11 19:45:10 +00002631 unlock_user_struct(ucp, ucp_addr, 0);
Riku Voipio66393fb2009-12-04 15:16:32 +02002632 force_sig(TARGET_SIGSEGV);
blueswir15bfb56b2007-10-05 17:01:51 +00002633}
2634
2635void sparc64_get_context(CPUSPARCState *env)
2636{
bellard459a4012007-11-11 19:45:10 +00002637 abi_ulong ucp_addr;
2638 struct target_ucontext *ucp;
Anthony Liguoric227f092009-10-01 16:12:16 -05002639 target_mc_gregset_t *grp;
2640 target_mcontext_t *mcp;
bellard459a4012007-11-11 19:45:10 +00002641 abi_ulong fp, i7, w_addr;
blueswir15bfb56b2007-10-05 17:01:51 +00002642 int err;
2643 unsigned int i;
Anthony Liguoric227f092009-10-01 16:12:16 -05002644 target_sigset_t target_set;
blueswir15bfb56b2007-10-05 17:01:51 +00002645 sigset_t set;
2646
bellard459a4012007-11-11 19:45:10 +00002647 ucp_addr = env->regwptr[UREG_I0];
2648 if (!lock_user_struct(VERIFY_WRITE, ucp, ucp_addr, 0))
2649 goto do_sigsegv;
2650
Aurelien Jarno60e99242010-03-29 02:12:51 +02002651 mcp = &ucp->tuc_mcontext;
blueswir15bfb56b2007-10-05 17:01:51 +00002652 grp = &mcp->mc_gregs;
2653
2654 /* Skip over the trap instruction, first. */
2655 env->pc = env->npc;
2656 env->npc += 4;
2657
2658 err = 0;
2659
Alex Barcelo1c275922014-03-14 14:36:55 +00002660 do_sigprocmask(0, NULL, &set);
blueswir15bfb56b2007-10-05 17:01:51 +00002661 host_to_target_sigset_internal(&target_set, &set);
bellard459a4012007-11-11 19:45:10 +00002662 if (TARGET_NSIG_WORDS == 1) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002663 __put_user(target_set.sig[0],
2664 (abi_ulong *)&ucp->tuc_sigmask);
bellard459a4012007-11-11 19:45:10 +00002665 } else {
2666 abi_ulong *src, *dst;
2667 src = target_set.sig;
Aurelien Jarno60e99242010-03-29 02:12:51 +02002668 dst = ucp->tuc_sigmask.sig;
Stefan Weil0d9e61c2013-12-07 14:48:08 +01002669 for (i = 0; i < TARGET_NSIG_WORDS; i++, dst++, src++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002670 __put_user(*src, dst);
Stefan Weil0d9e61c2013-12-07 14:48:08 +01002671 }
blueswir15bfb56b2007-10-05 17:01:51 +00002672 if (err)
2673 goto do_sigsegv;
2674 }
2675
bellard459a4012007-11-11 19:45:10 +00002676 /* XXX: tstate must be saved properly */
Riku Voipio1d8b5122014-04-23 10:26:05 +03002677 // __put_user(env->tstate, &((*grp)[MC_TSTATE]));
2678 __put_user(env->pc, &((*grp)[MC_PC]));
2679 __put_user(env->npc, &((*grp)[MC_NPC]));
2680 __put_user(env->y, &((*grp)[MC_Y]));
2681 __put_user(env->gregs[1], &((*grp)[MC_G1]));
2682 __put_user(env->gregs[2], &((*grp)[MC_G2]));
2683 __put_user(env->gregs[3], &((*grp)[MC_G3]));
2684 __put_user(env->gregs[4], &((*grp)[MC_G4]));
2685 __put_user(env->gregs[5], &((*grp)[MC_G5]));
2686 __put_user(env->gregs[6], &((*grp)[MC_G6]));
2687 __put_user(env->gregs[7], &((*grp)[MC_G7]));
2688 __put_user(env->regwptr[UREG_I0], &((*grp)[MC_O0]));
2689 __put_user(env->regwptr[UREG_I1], &((*grp)[MC_O1]));
2690 __put_user(env->regwptr[UREG_I2], &((*grp)[MC_O2]));
2691 __put_user(env->regwptr[UREG_I3], &((*grp)[MC_O3]));
2692 __put_user(env->regwptr[UREG_I4], &((*grp)[MC_O4]));
2693 __put_user(env->regwptr[UREG_I5], &((*grp)[MC_O5]));
2694 __put_user(env->regwptr[UREG_I6], &((*grp)[MC_O6]));
2695 __put_user(env->regwptr[UREG_I7], &((*grp)[MC_O7]));
blueswir15bfb56b2007-10-05 17:01:51 +00002696
bellard459a4012007-11-11 19:45:10 +00002697 w_addr = TARGET_STACK_BIAS+env->regwptr[UREG_I6];
2698 fp = i7 = 0;
2699 if (get_user(fp, w_addr + offsetof(struct target_reg_window, ins[6]),
2700 abi_ulong) != 0)
2701 goto do_sigsegv;
2702 if (get_user(i7, w_addr + offsetof(struct target_reg_window, ins[7]),
2703 abi_ulong) != 0)
2704 goto do_sigsegv;
Riku Voipio1d8b5122014-04-23 10:26:05 +03002705 __put_user(fp, &(mcp->mc_fp));
2706 __put_user(i7, &(mcp->mc_i7));
blueswir15bfb56b2007-10-05 17:01:51 +00002707
bellard459a4012007-11-11 19:45:10 +00002708 {
Richard Henderson30038fd2011-10-17 10:42:49 -07002709 uint32_t *dst = ucp->tuc_mcontext.mc_fpregs.mcfpu_fregs.sregs;
2710 for (i = 0; i < 64; i++, dst++) {
2711 if (i & 1) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002712 __put_user(env->fpr[i/2].l.lower, dst);
Richard Henderson30038fd2011-10-17 10:42:49 -07002713 } else {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002714 __put_user(env->fpr[i/2].l.upper, dst);
Richard Henderson30038fd2011-10-17 10:42:49 -07002715 }
2716 }
bellard459a4012007-11-11 19:45:10 +00002717 }
Riku Voipio1d8b5122014-04-23 10:26:05 +03002718 __put_user(env->fsr, &(mcp->mc_fpregs.mcfpu_fsr));
2719 __put_user(env->gsr, &(mcp->mc_fpregs.mcfpu_gsr));
2720 __put_user(env->fprs, &(mcp->mc_fpregs.mcfpu_fprs));
blueswir15bfb56b2007-10-05 17:01:51 +00002721
2722 if (err)
2723 goto do_sigsegv;
bellard459a4012007-11-11 19:45:10 +00002724 unlock_user_struct(ucp, ucp_addr, 1);
blueswir15bfb56b2007-10-05 17:01:51 +00002725 return;
2726 do_sigsegv:
bellard459a4012007-11-11 19:45:10 +00002727 unlock_user_struct(ucp, ucp_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02002728 force_sig(TARGET_SIGSEGV);
blueswir15bfb56b2007-10-05 17:01:51 +00002729}
2730#endif
Richard Hendersonff970902013-02-10 10:30:42 -08002731#elif defined(TARGET_MIPS) || defined(TARGET_MIPS64)
bellard106ec872006-06-27 21:08:10 +00002732
Richard Hendersonff970902013-02-10 10:30:42 -08002733# if defined(TARGET_ABI_MIPSO32)
bellard106ec872006-06-27 21:08:10 +00002734struct target_sigcontext {
2735 uint32_t sc_regmask; /* Unused */
2736 uint32_t sc_status;
2737 uint64_t sc_pc;
2738 uint64_t sc_regs[32];
2739 uint64_t sc_fpregs[32];
2740 uint32_t sc_ownedfp; /* Unused */
2741 uint32_t sc_fpc_csr;
2742 uint32_t sc_fpc_eir; /* Unused */
2743 uint32_t sc_used_math;
2744 uint32_t sc_dsp; /* dsp status, was sc_ssflags */
Paul Brook94c54952009-07-09 18:40:15 +01002745 uint32_t pad0;
bellard106ec872006-06-27 21:08:10 +00002746 uint64_t sc_mdhi;
2747 uint64_t sc_mdlo;
2748 target_ulong sc_hi1; /* Was sc_cause */
2749 target_ulong sc_lo1; /* Was sc_badvaddr */
2750 target_ulong sc_hi2; /* Was sc_sigset[4] */
2751 target_ulong sc_lo2;
2752 target_ulong sc_hi3;
2753 target_ulong sc_lo3;
2754};
Richard Hendersonff970902013-02-10 10:30:42 -08002755# else /* N32 || N64 */
2756struct target_sigcontext {
2757 uint64_t sc_regs[32];
2758 uint64_t sc_fpregs[32];
2759 uint64_t sc_mdhi;
2760 uint64_t sc_hi1;
2761 uint64_t sc_hi2;
2762 uint64_t sc_hi3;
2763 uint64_t sc_mdlo;
2764 uint64_t sc_lo1;
2765 uint64_t sc_lo2;
2766 uint64_t sc_lo3;
2767 uint64_t sc_pc;
2768 uint32_t sc_fpc_csr;
2769 uint32_t sc_used_math;
2770 uint32_t sc_dsp;
2771 uint32_t sc_reserved;
2772};
2773# endif /* O32 */
bellard106ec872006-06-27 21:08:10 +00002774
2775struct sigframe {
2776 uint32_t sf_ass[4]; /* argument save space for o32 */
2777 uint32_t sf_code[2]; /* signal trampoline */
2778 struct target_sigcontext sf_sc;
Anthony Liguoric227f092009-10-01 16:12:16 -05002779 target_sigset_t sf_mask;
bellard106ec872006-06-27 21:08:10 +00002780};
2781
pbrook0b1bcb02009-04-21 01:41:10 +00002782struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02002783 target_ulong tuc_flags;
2784 target_ulong tuc_link;
2785 target_stack_t tuc_stack;
Paul Brook94c54952009-07-09 18:40:15 +01002786 target_ulong pad0;
Aurelien Jarno60e99242010-03-29 02:12:51 +02002787 struct target_sigcontext tuc_mcontext;
2788 target_sigset_t tuc_sigmask;
pbrook0b1bcb02009-04-21 01:41:10 +00002789};
2790
2791struct target_rt_sigframe {
2792 uint32_t rs_ass[4]; /* argument save space for o32 */
2793 uint32_t rs_code[2]; /* signal trampoline */
2794 struct target_siginfo rs_info;
2795 struct target_ucontext rs_uc;
2796};
2797
bellard106ec872006-06-27 21:08:10 +00002798/* Install trampoline to jump back from signal handler */
2799static inline int install_sigtramp(unsigned int *tramp, unsigned int syscall)
2800{
Richard Henderson084d0492013-02-10 10:30:44 -08002801 int err = 0;
bellard106ec872006-06-27 21:08:10 +00002802
2803 /*
Richard Henderson084d0492013-02-10 10:30:44 -08002804 * Set up the return code ...
2805 *
2806 * li v0, __NR__foo_sigreturn
2807 * syscall
2808 */
bellard106ec872006-06-27 21:08:10 +00002809
Riku Voipio1d8b5122014-04-23 10:26:05 +03002810 __put_user(0x24020000 + syscall, tramp + 0);
2811 __put_user(0x0000000c , tramp + 1);
bellard106ec872006-06-27 21:08:10 +00002812 return err;
2813}
2814
Riku Voipio41ecc722014-04-23 11:01:00 +03002815static inline void setup_sigcontext(CPUMIPSState *regs,
2816 struct target_sigcontext *sc)
bellard106ec872006-06-27 21:08:10 +00002817{
Richard Henderson084d0492013-02-10 10:30:44 -08002818 int i;
bellard106ec872006-06-27 21:08:10 +00002819
Riku Voipio1d8b5122014-04-23 10:26:05 +03002820 __put_user(exception_resume_pc(regs), &sc->sc_pc);
Kwok Cheung Yeung1239b472013-05-17 14:51:21 -07002821 regs->hflags &= ~MIPS_HFLAG_BMASK;
bellard106ec872006-06-27 21:08:10 +00002822
Richard Henderson084d0492013-02-10 10:30:44 -08002823 __put_user(0, &sc->sc_regs[0]);
2824 for (i = 1; i < 32; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002825 __put_user(regs->active_tc.gpr[i], &sc->sc_regs[i]);
Richard Henderson084d0492013-02-10 10:30:44 -08002826 }
bellard106ec872006-06-27 21:08:10 +00002827
Riku Voipio1d8b5122014-04-23 10:26:05 +03002828 __put_user(regs->active_tc.HI[0], &sc->sc_mdhi);
2829 __put_user(regs->active_tc.LO[0], &sc->sc_mdlo);
bellard106ec872006-06-27 21:08:10 +00002830
Richard Henderson084d0492013-02-10 10:30:44 -08002831 /* Rather than checking for dsp existence, always copy. The storage
2832 would just be garbage otherwise. */
Riku Voipio1d8b5122014-04-23 10:26:05 +03002833 __put_user(regs->active_tc.HI[1], &sc->sc_hi1);
2834 __put_user(regs->active_tc.HI[2], &sc->sc_hi2);
2835 __put_user(regs->active_tc.HI[3], &sc->sc_hi3);
2836 __put_user(regs->active_tc.LO[1], &sc->sc_lo1);
2837 __put_user(regs->active_tc.LO[2], &sc->sc_lo2);
2838 __put_user(regs->active_tc.LO[3], &sc->sc_lo3);
Richard Henderson084d0492013-02-10 10:30:44 -08002839 {
2840 uint32_t dsp = cpu_rddsp(0x3ff, regs);
Riku Voipio1d8b5122014-04-23 10:26:05 +03002841 __put_user(dsp, &sc->sc_dsp);
bellard106ec872006-06-27 21:08:10 +00002842 }
Richard Henderson084d0492013-02-10 10:30:44 -08002843
Riku Voipio1d8b5122014-04-23 10:26:05 +03002844 __put_user(1, &sc->sc_used_math);
Richard Henderson084d0492013-02-10 10:30:44 -08002845
2846 for (i = 0; i < 32; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002847 __put_user(regs->active_fpu.fpr[i].d, &sc->sc_fpregs[i]);
bellard106ec872006-06-27 21:08:10 +00002848 }
bellard106ec872006-06-27 21:08:10 +00002849}
2850
Riku Voipio016d2e12014-04-23 11:19:48 +03002851static inline void
Andreas Färber05390242012-02-25 03:37:53 +01002852restore_sigcontext(CPUMIPSState *regs, struct target_sigcontext *sc)
bellard106ec872006-06-27 21:08:10 +00002853{
Richard Henderson084d0492013-02-10 10:30:44 -08002854 int i;
bellard106ec872006-06-27 21:08:10 +00002855
Riku Voipio1d8b5122014-04-23 10:26:05 +03002856 __get_user(regs->CP0_EPC, &sc->sc_pc);
bellard106ec872006-06-27 21:08:10 +00002857
Riku Voipio1d8b5122014-04-23 10:26:05 +03002858 __get_user(regs->active_tc.HI[0], &sc->sc_mdhi);
2859 __get_user(regs->active_tc.LO[0], &sc->sc_mdlo);
bellard106ec872006-06-27 21:08:10 +00002860
Richard Henderson084d0492013-02-10 10:30:44 -08002861 for (i = 1; i < 32; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002862 __get_user(regs->active_tc.gpr[i], &sc->sc_regs[i]);
bellard106ec872006-06-27 21:08:10 +00002863 }
2864
Riku Voipio1d8b5122014-04-23 10:26:05 +03002865 __get_user(regs->active_tc.HI[1], &sc->sc_hi1);
2866 __get_user(regs->active_tc.HI[2], &sc->sc_hi2);
2867 __get_user(regs->active_tc.HI[3], &sc->sc_hi3);
2868 __get_user(regs->active_tc.LO[1], &sc->sc_lo1);
2869 __get_user(regs->active_tc.LO[2], &sc->sc_lo2);
2870 __get_user(regs->active_tc.LO[3], &sc->sc_lo3);
Richard Henderson084d0492013-02-10 10:30:44 -08002871 {
2872 uint32_t dsp;
Riku Voipio1d8b5122014-04-23 10:26:05 +03002873 __get_user(dsp, &sc->sc_dsp);
Richard Henderson084d0492013-02-10 10:30:44 -08002874 cpu_wrdsp(dsp, 0x3ff, regs);
2875 }
2876
2877 for (i = 0; i < 32; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002878 __get_user(regs->active_fpu.fpr[i].d, &sc->sc_fpregs[i]);
Richard Henderson084d0492013-02-10 10:30:44 -08002879 }
bellard106ec872006-06-27 21:08:10 +00002880}
Richard Hendersonff970902013-02-10 10:30:42 -08002881
bellard106ec872006-06-27 21:08:10 +00002882/*
2883 * Determine which stack to use..
2884 */
bellard579a97f2007-11-11 14:26:47 +00002885static inline abi_ulong
Andreas Färber05390242012-02-25 03:37:53 +01002886get_sigframe(struct target_sigaction *ka, CPUMIPSState *regs, size_t frame_size)
bellard106ec872006-06-27 21:08:10 +00002887{
2888 unsigned long sp;
2889
2890 /* Default to using normal stack */
thsb5dc7732008-06-27 10:02:35 +00002891 sp = regs->active_tc.gpr[29];
bellard106ec872006-06-27 21:08:10 +00002892
2893 /*
Stefan Weil93148aa2012-02-26 18:46:12 +01002894 * FPU emulator may have its own trampoline active just
bellard106ec872006-06-27 21:08:10 +00002895 * above the user stack, 16-bytes before the next lowest
2896 * 16 byte boundary. Try to avoid trashing it.
2897 */
2898 sp -= 32;
2899
bellard106ec872006-06-27 21:08:10 +00002900 /* This is the X/Open sanctioned signal stack switching. */
pbrook624f7972008-05-31 16:11:38 +00002901 if ((ka->sa_flags & TARGET_SA_ONSTACK) && (sas_ss_flags (sp) == 0)) {
thsa04e1342007-09-27 13:57:58 +00002902 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
2903 }
bellard106ec872006-06-27 21:08:10 +00002904
bellard579a97f2007-11-11 14:26:47 +00002905 return (sp - frame_size) & ~7;
bellard106ec872006-06-27 21:08:10 +00002906}
2907
Kwok Cheung Yeungea3164a2013-05-17 14:51:20 -07002908static void mips_set_hflags_isa_mode_from_pc(CPUMIPSState *env)
2909{
2910 if (env->insn_flags & (ASE_MIPS16 | ASE_MICROMIPS)) {
2911 env->hflags &= ~MIPS_HFLAG_M16;
2912 env->hflags |= (env->active_tc.PC & 1) << MIPS_HFLAG_M16_SHIFT;
2913 env->active_tc.PC &= ~(target_ulong) 1;
2914 }
2915}
2916
Richard Hendersonff970902013-02-10 10:30:42 -08002917# if defined(TARGET_ABI_MIPSO32)
bellard579a97f2007-11-11 14:26:47 +00002918/* compare linux/arch/mips/kernel/signal.c:setup_frame() */
pbrook624f7972008-05-31 16:11:38 +00002919static void setup_frame(int sig, struct target_sigaction * ka,
Andreas Färber05390242012-02-25 03:37:53 +01002920 target_sigset_t *set, CPUMIPSState *regs)
bellard106ec872006-06-27 21:08:10 +00002921{
2922 struct sigframe *frame;
bellard579a97f2007-11-11 14:26:47 +00002923 abi_ulong frame_addr;
bellard106ec872006-06-27 21:08:10 +00002924 int i;
2925
bellard579a97f2007-11-11 14:26:47 +00002926 frame_addr = get_sigframe(ka, regs, sizeof(*frame));
2927 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
bellard106ec872006-06-27 21:08:10 +00002928 goto give_sigsegv;
2929
2930 install_sigtramp(frame->sf_code, TARGET_NR_sigreturn);
2931
Riku Voipio41ecc722014-04-23 11:01:00 +03002932 setup_sigcontext(regs, &frame->sf_sc);
bellard106ec872006-06-27 21:08:10 +00002933
2934 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
2935 if(__put_user(set->sig[i], &frame->sf_mask.sig[i]))
2936 goto give_sigsegv;
2937 }
2938
2939 /*
2940 * Arguments to signal handler:
2941 *
2942 * a0 = signal number
2943 * a1 = 0 (should be cause)
2944 * a2 = pointer to struct sigcontext
2945 *
2946 * $25 and PC point to the signal handler, $29 points to the
2947 * struct sigframe.
2948 */
thsb5dc7732008-06-27 10:02:35 +00002949 regs->active_tc.gpr[ 4] = sig;
2950 regs->active_tc.gpr[ 5] = 0;
2951 regs->active_tc.gpr[ 6] = frame_addr + offsetof(struct sigframe, sf_sc);
2952 regs->active_tc.gpr[29] = frame_addr;
2953 regs->active_tc.gpr[31] = frame_addr + offsetof(struct sigframe, sf_code);
bellard106ec872006-06-27 21:08:10 +00002954 /* The original kernel code sets CP0_EPC to the handler
2955 * since it returns to userland using eret
2956 * we cannot do this here, and we must set PC directly */
thsb5dc7732008-06-27 10:02:35 +00002957 regs->active_tc.PC = regs->active_tc.gpr[25] = ka->_sa_handler;
Kwok Cheung Yeungea3164a2013-05-17 14:51:20 -07002958 mips_set_hflags_isa_mode_from_pc(regs);
bellard579a97f2007-11-11 14:26:47 +00002959 unlock_user_struct(frame, frame_addr, 1);
bellard106ec872006-06-27 21:08:10 +00002960 return;
2961
2962give_sigsegv:
bellard579a97f2007-11-11 14:26:47 +00002963 unlock_user_struct(frame, frame_addr, 1);
bellard106ec872006-06-27 21:08:10 +00002964 force_sig(TARGET_SIGSEGV/*, current*/);
bellard106ec872006-06-27 21:08:10 +00002965}
2966
Andreas Färber05390242012-02-25 03:37:53 +01002967long do_sigreturn(CPUMIPSState *regs)
bellard106ec872006-06-27 21:08:10 +00002968{
ths388bb212007-05-13 13:58:00 +00002969 struct sigframe *frame;
bellard579a97f2007-11-11 14:26:47 +00002970 abi_ulong frame_addr;
ths388bb212007-05-13 13:58:00 +00002971 sigset_t blocked;
Anthony Liguoric227f092009-10-01 16:12:16 -05002972 target_sigset_t target_set;
ths388bb212007-05-13 13:58:00 +00002973 int i;
bellard106ec872006-06-27 21:08:10 +00002974
2975#if defined(DEBUG_SIGNAL)
ths388bb212007-05-13 13:58:00 +00002976 fprintf(stderr, "do_sigreturn\n");
bellard106ec872006-06-27 21:08:10 +00002977#endif
thsb5dc7732008-06-27 10:02:35 +00002978 frame_addr = regs->active_tc.gpr[29];
bellard579a97f2007-11-11 14:26:47 +00002979 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
bellard106ec872006-06-27 21:08:10 +00002980 goto badframe;
2981
ths388bb212007-05-13 13:58:00 +00002982 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
Riku Voipiof5f601a2014-04-23 13:00:17 +03002983 __get_user(target_set.sig[i], &frame->sf_mask.sig[i]);
ths388bb212007-05-13 13:58:00 +00002984 }
bellard106ec872006-06-27 21:08:10 +00002985
ths388bb212007-05-13 13:58:00 +00002986 target_to_host_sigset_internal(&blocked, &target_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00002987 do_sigprocmask(SIG_SETMASK, &blocked, NULL);
bellard106ec872006-06-27 21:08:10 +00002988
Riku Voipio016d2e12014-04-23 11:19:48 +03002989 restore_sigcontext(regs, &frame->sf_sc);
bellard106ec872006-06-27 21:08:10 +00002990
2991#if 0
ths388bb212007-05-13 13:58:00 +00002992 /*
2993 * Don't let your children do this ...
2994 */
2995 __asm__ __volatile__(
bellard106ec872006-06-27 21:08:10 +00002996 "move\t$29, %0\n\t"
2997 "j\tsyscall_exit"
2998 :/* no outputs */
2999 :"r" (&regs));
ths388bb212007-05-13 13:58:00 +00003000 /* Unreached */
bellard106ec872006-06-27 21:08:10 +00003001#endif
ths3b46e622007-09-17 08:09:54 +00003002
thsb5dc7732008-06-27 10:02:35 +00003003 regs->active_tc.PC = regs->CP0_EPC;
Kwok Cheung Yeungea3164a2013-05-17 14:51:20 -07003004 mips_set_hflags_isa_mode_from_pc(regs);
ths388bb212007-05-13 13:58:00 +00003005 /* I am not sure this is right, but it seems to work
bellard106ec872006-06-27 21:08:10 +00003006 * maybe a problem with nested signals ? */
3007 regs->CP0_EPC = 0;
pbrook0b1bcb02009-04-21 01:41:10 +00003008 return -TARGET_QEMU_ESIGRETURN;
bellard106ec872006-06-27 21:08:10 +00003009
3010badframe:
ths388bb212007-05-13 13:58:00 +00003011 force_sig(TARGET_SIGSEGV/*, current*/);
3012 return 0;
bellard106ec872006-06-27 21:08:10 +00003013}
Richard Hendersonff970902013-02-10 10:30:42 -08003014# endif /* O32 */
bellard106ec872006-06-27 21:08:10 +00003015
pbrook624f7972008-05-31 16:11:38 +00003016static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05003017 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01003018 target_sigset_t *set, CPUMIPSState *env)
bellard106ec872006-06-27 21:08:10 +00003019{
pbrook0b1bcb02009-04-21 01:41:10 +00003020 struct target_rt_sigframe *frame;
3021 abi_ulong frame_addr;
3022 int i;
3023
3024 frame_addr = get_sigframe(ka, env, sizeof(*frame));
3025 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
3026 goto give_sigsegv;
3027
3028 install_sigtramp(frame->rs_code, TARGET_NR_rt_sigreturn);
3029
3030 copy_siginfo_to_user(&frame->rs_info, info);
3031
Aurelien Jarno60e99242010-03-29 02:12:51 +02003032 __put_user(0, &frame->rs_uc.tuc_flags);
3033 __put_user(0, &frame->rs_uc.tuc_link);
3034 __put_user(target_sigaltstack_used.ss_sp, &frame->rs_uc.tuc_stack.ss_sp);
3035 __put_user(target_sigaltstack_used.ss_size, &frame->rs_uc.tuc_stack.ss_size);
pbrook0b1bcb02009-04-21 01:41:10 +00003036 __put_user(sas_ss_flags(get_sp_from_cpustate(env)),
Aurelien Jarno60e99242010-03-29 02:12:51 +02003037 &frame->rs_uc.tuc_stack.ss_flags);
pbrook0b1bcb02009-04-21 01:41:10 +00003038
Aurelien Jarno60e99242010-03-29 02:12:51 +02003039 setup_sigcontext(env, &frame->rs_uc.tuc_mcontext);
pbrook0b1bcb02009-04-21 01:41:10 +00003040
3041 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
Aurelien Jarno60e99242010-03-29 02:12:51 +02003042 __put_user(set->sig[i], &frame->rs_uc.tuc_sigmask.sig[i]);
pbrook0b1bcb02009-04-21 01:41:10 +00003043 }
3044
3045 /*
3046 * Arguments to signal handler:
3047 *
3048 * a0 = signal number
Richard W.M. Jones02d2bd52012-07-05 03:32:44 +00003049 * a1 = pointer to siginfo_t
pbrook0b1bcb02009-04-21 01:41:10 +00003050 * a2 = pointer to struct ucontext
3051 *
3052 * $25 and PC point to the signal handler, $29 points to the
3053 * struct sigframe.
3054 */
3055 env->active_tc.gpr[ 4] = sig;
3056 env->active_tc.gpr[ 5] = frame_addr
3057 + offsetof(struct target_rt_sigframe, rs_info);
3058 env->active_tc.gpr[ 6] = frame_addr
3059 + offsetof(struct target_rt_sigframe, rs_uc);
3060 env->active_tc.gpr[29] = frame_addr;
3061 env->active_tc.gpr[31] = frame_addr
3062 + offsetof(struct target_rt_sigframe, rs_code);
3063 /* The original kernel code sets CP0_EPC to the handler
3064 * since it returns to userland using eret
3065 * we cannot do this here, and we must set PC directly */
3066 env->active_tc.PC = env->active_tc.gpr[25] = ka->_sa_handler;
Kwok Cheung Yeungea3164a2013-05-17 14:51:20 -07003067 mips_set_hflags_isa_mode_from_pc(env);
pbrook0b1bcb02009-04-21 01:41:10 +00003068 unlock_user_struct(frame, frame_addr, 1);
3069 return;
3070
3071give_sigsegv:
3072 unlock_user_struct(frame, frame_addr, 1);
3073 force_sig(TARGET_SIGSEGV/*, current*/);
bellard106ec872006-06-27 21:08:10 +00003074}
3075
Andreas Färber05390242012-02-25 03:37:53 +01003076long do_rt_sigreturn(CPUMIPSState *env)
bellard106ec872006-06-27 21:08:10 +00003077{
pbrook0b1bcb02009-04-21 01:41:10 +00003078 struct target_rt_sigframe *frame;
3079 abi_ulong frame_addr;
3080 sigset_t blocked;
3081
3082#if defined(DEBUG_SIGNAL)
3083 fprintf(stderr, "do_rt_sigreturn\n");
3084#endif
3085 frame_addr = env->active_tc.gpr[29];
3086 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
3087 goto badframe;
3088
Aurelien Jarno60e99242010-03-29 02:12:51 +02003089 target_to_host_sigset(&blocked, &frame->rs_uc.tuc_sigmask);
Alex Barcelo1c275922014-03-14 14:36:55 +00003090 do_sigprocmask(SIG_SETMASK, &blocked, NULL);
pbrook0b1bcb02009-04-21 01:41:10 +00003091
Riku Voipio016d2e12014-04-23 11:19:48 +03003092 restore_sigcontext(env, &frame->rs_uc.tuc_mcontext);
pbrook0b1bcb02009-04-21 01:41:10 +00003093
3094 if (do_sigaltstack(frame_addr +
Aurelien Jarno60e99242010-03-29 02:12:51 +02003095 offsetof(struct target_rt_sigframe, rs_uc.tuc_stack),
pbrook0b1bcb02009-04-21 01:41:10 +00003096 0, get_sp_from_cpustate(env)) == -EFAULT)
3097 goto badframe;
3098
3099 env->active_tc.PC = env->CP0_EPC;
Kwok Cheung Yeungea3164a2013-05-17 14:51:20 -07003100 mips_set_hflags_isa_mode_from_pc(env);
pbrook0b1bcb02009-04-21 01:41:10 +00003101 /* I am not sure this is right, but it seems to work
3102 * maybe a problem with nested signals ? */
3103 env->CP0_EPC = 0;
3104 return -TARGET_QEMU_ESIGRETURN;
3105
3106badframe:
3107 force_sig(TARGET_SIGSEGV/*, current*/);
3108 return 0;
bellard106ec872006-06-27 21:08:10 +00003109}
bellard6d5e2162004-09-30 22:04:13 +00003110
thsc3b5bc82007-12-02 06:31:25 +00003111#elif defined(TARGET_SH4)
3112
3113/*
3114 * code and data structures from linux kernel:
3115 * include/asm-sh/sigcontext.h
3116 * arch/sh/kernel/signal.c
3117 */
3118
3119struct target_sigcontext {
3120 target_ulong oldmask;
3121
3122 /* CPU registers */
3123 target_ulong sc_gregs[16];
3124 target_ulong sc_pc;
3125 target_ulong sc_pr;
3126 target_ulong sc_sr;
3127 target_ulong sc_gbr;
3128 target_ulong sc_mach;
3129 target_ulong sc_macl;
3130
3131 /* FPU registers */
3132 target_ulong sc_fpregs[16];
3133 target_ulong sc_xfpregs[16];
3134 unsigned int sc_fpscr;
3135 unsigned int sc_fpul;
3136 unsigned int sc_ownedfp;
3137};
3138
3139struct target_sigframe
3140{
3141 struct target_sigcontext sc;
3142 target_ulong extramask[TARGET_NSIG_WORDS-1];
3143 uint16_t retcode[3];
3144};
3145
3146
3147struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02003148 target_ulong tuc_flags;
3149 struct target_ucontext *tuc_link;
3150 target_stack_t tuc_stack;
3151 struct target_sigcontext tuc_mcontext;
3152 target_sigset_t tuc_sigmask; /* mask last for extensibility */
thsc3b5bc82007-12-02 06:31:25 +00003153};
3154
3155struct target_rt_sigframe
3156{
3157 struct target_siginfo info;
3158 struct target_ucontext uc;
3159 uint16_t retcode[3];
3160};
3161
3162
3163#define MOVW(n) (0x9300|((n)-2)) /* Move mem word at PC+n to R3 */
3164#define TRAP_NOARG 0xc310 /* Syscall w/no args (NR in R3) SH3/4 */
3165
pbrook624f7972008-05-31 16:11:38 +00003166static abi_ulong get_sigframe(struct target_sigaction *ka,
thsc3b5bc82007-12-02 06:31:25 +00003167 unsigned long sp, size_t frame_size)
3168{
pbrook624f7972008-05-31 16:11:38 +00003169 if ((ka->sa_flags & TARGET_SA_ONSTACK) && (sas_ss_flags(sp) == 0)) {
thsc3b5bc82007-12-02 06:31:25 +00003170 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
3171 }
3172
3173 return (sp - frame_size) & -8ul;
3174}
3175
Riku Voipio41ecc722014-04-23 11:01:00 +03003176static void setup_sigcontext(struct target_sigcontext *sc,
Andreas Färber05390242012-02-25 03:37:53 +01003177 CPUSH4State *regs, unsigned long mask)
thsc3b5bc82007-12-02 06:31:25 +00003178{
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003179 int i;
thsc3b5bc82007-12-02 06:31:25 +00003180
Riku Voipio1d8b5122014-04-23 10:26:05 +03003181#define COPY(x) __put_user(regs->x, &sc->sc_##x)
thsc3b5bc82007-12-02 06:31:25 +00003182 COPY(gregs[0]); COPY(gregs[1]);
3183 COPY(gregs[2]); COPY(gregs[3]);
3184 COPY(gregs[4]); COPY(gregs[5]);
3185 COPY(gregs[6]); COPY(gregs[7]);
3186 COPY(gregs[8]); COPY(gregs[9]);
3187 COPY(gregs[10]); COPY(gregs[11]);
3188 COPY(gregs[12]); COPY(gregs[13]);
3189 COPY(gregs[14]); COPY(gregs[15]);
3190 COPY(gbr); COPY(mach);
3191 COPY(macl); COPY(pr);
3192 COPY(sr); COPY(pc);
3193#undef COPY
3194
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003195 for (i=0; i<16; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03003196 __put_user(regs->fregs[i], &sc->sc_fpregs[i]);
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003197 }
Riku Voipio1d8b5122014-04-23 10:26:05 +03003198 __put_user(regs->fpscr, &sc->sc_fpscr);
3199 __put_user(regs->fpul, &sc->sc_fpul);
thsc3b5bc82007-12-02 06:31:25 +00003200
3201 /* non-iBCS2 extensions.. */
Riku Voipio1d8b5122014-04-23 10:26:05 +03003202 __put_user(mask, &sc->oldmask);
thsc3b5bc82007-12-02 06:31:25 +00003203}
3204
Riku Voipio016d2e12014-04-23 11:19:48 +03003205static void restore_sigcontext(CPUSH4State *regs, struct target_sigcontext *sc,
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003206 target_ulong *r0_p)
thsc3b5bc82007-12-02 06:31:25 +00003207{
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003208 int i;
thsc3b5bc82007-12-02 06:31:25 +00003209
Riku Voipio1d8b5122014-04-23 10:26:05 +03003210#define COPY(x) __get_user(regs->x, &sc->sc_##x)
thsc3b5bc82007-12-02 06:31:25 +00003211 COPY(gregs[1]);
3212 COPY(gregs[2]); COPY(gregs[3]);
3213 COPY(gregs[4]); COPY(gregs[5]);
3214 COPY(gregs[6]); COPY(gregs[7]);
3215 COPY(gregs[8]); COPY(gregs[9]);
3216 COPY(gregs[10]); COPY(gregs[11]);
3217 COPY(gregs[12]); COPY(gregs[13]);
3218 COPY(gregs[14]); COPY(gregs[15]);
3219 COPY(gbr); COPY(mach);
3220 COPY(macl); COPY(pr);
3221 COPY(sr); COPY(pc);
3222#undef COPY
3223
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003224 for (i=0; i<16; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03003225 __get_user(regs->fregs[i], &sc->sc_fpregs[i]);
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003226 }
Riku Voipio1d8b5122014-04-23 10:26:05 +03003227 __get_user(regs->fpscr, &sc->sc_fpscr);
3228 __get_user(regs->fpul, &sc->sc_fpul);
thsc3b5bc82007-12-02 06:31:25 +00003229
3230 regs->tra = -1; /* disable syscall checks */
Riku Voipio1d8b5122014-04-23 10:26:05 +03003231 __get_user(*r0_p, &sc->sc_gregs[0]);
thsc3b5bc82007-12-02 06:31:25 +00003232}
3233
pbrook624f7972008-05-31 16:11:38 +00003234static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01003235 target_sigset_t *set, CPUSH4State *regs)
thsc3b5bc82007-12-02 06:31:25 +00003236{
3237 struct target_sigframe *frame;
3238 abi_ulong frame_addr;
3239 int i;
3240 int err = 0;
3241 int signal;
3242
3243 frame_addr = get_sigframe(ka, regs->gregs[15], sizeof(*frame));
3244 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
3245 goto give_sigsegv;
3246
3247 signal = current_exec_domain_sig(sig);
3248
Riku Voipio41ecc722014-04-23 11:01:00 +03003249 setup_sigcontext(&frame->sc, regs, set->sig[0]);
thsc3b5bc82007-12-02 06:31:25 +00003250
3251 for (i = 0; i < TARGET_NSIG_WORDS - 1; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03003252 __put_user(set->sig[i + 1], &frame->extramask[i]);
thsc3b5bc82007-12-02 06:31:25 +00003253 }
3254
3255 /* Set up to return from userspace. If provided, use a stub
3256 already in userspace. */
pbrook624f7972008-05-31 16:11:38 +00003257 if (ka->sa_flags & TARGET_SA_RESTORER) {
3258 regs->pr = (unsigned long) ka->sa_restorer;
thsc3b5bc82007-12-02 06:31:25 +00003259 } else {
3260 /* Generate return code (system call to sigreturn) */
Riku Voipio1d8b5122014-04-23 10:26:05 +03003261 __put_user(MOVW(2), &frame->retcode[0]);
3262 __put_user(TRAP_NOARG, &frame->retcode[1]);
3263 __put_user((TARGET_NR_sigreturn), &frame->retcode[2]);
thsc3b5bc82007-12-02 06:31:25 +00003264 regs->pr = (unsigned long) frame->retcode;
3265 }
3266
3267 if (err)
3268 goto give_sigsegv;
3269
3270 /* Set up registers for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003271 regs->gregs[15] = frame_addr;
thsc3b5bc82007-12-02 06:31:25 +00003272 regs->gregs[4] = signal; /* Arg for signal handler */
3273 regs->gregs[5] = 0;
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003274 regs->gregs[6] = frame_addr += offsetof(typeof(*frame), sc);
pbrook624f7972008-05-31 16:11:38 +00003275 regs->pc = (unsigned long) ka->_sa_handler;
thsc3b5bc82007-12-02 06:31:25 +00003276
3277 unlock_user_struct(frame, frame_addr, 1);
3278 return;
3279
3280give_sigsegv:
3281 unlock_user_struct(frame, frame_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02003282 force_sig(TARGET_SIGSEGV);
thsc3b5bc82007-12-02 06:31:25 +00003283}
3284
pbrook624f7972008-05-31 16:11:38 +00003285static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05003286 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01003287 target_sigset_t *set, CPUSH4State *regs)
thsc3b5bc82007-12-02 06:31:25 +00003288{
3289 struct target_rt_sigframe *frame;
3290 abi_ulong frame_addr;
3291 int i;
3292 int err = 0;
3293 int signal;
3294
3295 frame_addr = get_sigframe(ka, regs->gregs[15], sizeof(*frame));
3296 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
3297 goto give_sigsegv;
3298
3299 signal = current_exec_domain_sig(sig);
3300
Riku Voipiob0fd8d12014-04-23 10:46:13 +03003301 copy_siginfo_to_user(&frame->info, info);
thsc3b5bc82007-12-02 06:31:25 +00003302
3303 /* Create the ucontext. */
Riku Voipio1d8b5122014-04-23 10:26:05 +03003304 __put_user(0, &frame->uc.tuc_flags);
3305 __put_user(0, (unsigned long *)&frame->uc.tuc_link);
3306 __put_user((unsigned long)target_sigaltstack_used.ss_sp,
3307 &frame->uc.tuc_stack.ss_sp);
3308 __put_user(sas_ss_flags(regs->gregs[15]),
3309 &frame->uc.tuc_stack.ss_flags);
3310 __put_user(target_sigaltstack_used.ss_size,
3311 &frame->uc.tuc_stack.ss_size);
3312 setup_sigcontext(&frame->uc.tuc_mcontext,
thsc3b5bc82007-12-02 06:31:25 +00003313 regs, set->sig[0]);
3314 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03003315 __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
thsc3b5bc82007-12-02 06:31:25 +00003316 }
3317
3318 /* Set up to return from userspace. If provided, use a stub
3319 already in userspace. */
pbrook624f7972008-05-31 16:11:38 +00003320 if (ka->sa_flags & TARGET_SA_RESTORER) {
3321 regs->pr = (unsigned long) ka->sa_restorer;
thsc3b5bc82007-12-02 06:31:25 +00003322 } else {
3323 /* Generate return code (system call to sigreturn) */
Riku Voipio1d8b5122014-04-23 10:26:05 +03003324 __put_user(MOVW(2), &frame->retcode[0]);
3325 __put_user(TRAP_NOARG, &frame->retcode[1]);
3326 __put_user((TARGET_NR_rt_sigreturn), &frame->retcode[2]);
thsc3b5bc82007-12-02 06:31:25 +00003327 regs->pr = (unsigned long) frame->retcode;
3328 }
3329
3330 if (err)
3331 goto give_sigsegv;
3332
3333 /* Set up registers for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003334 regs->gregs[15] = frame_addr;
thsc3b5bc82007-12-02 06:31:25 +00003335 regs->gregs[4] = signal; /* Arg for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003336 regs->gregs[5] = frame_addr + offsetof(typeof(*frame), info);
3337 regs->gregs[6] = frame_addr + offsetof(typeof(*frame), uc);
pbrook624f7972008-05-31 16:11:38 +00003338 regs->pc = (unsigned long) ka->_sa_handler;
thsc3b5bc82007-12-02 06:31:25 +00003339
3340 unlock_user_struct(frame, frame_addr, 1);
3341 return;
3342
3343give_sigsegv:
3344 unlock_user_struct(frame, frame_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02003345 force_sig(TARGET_SIGSEGV);
thsc3b5bc82007-12-02 06:31:25 +00003346}
3347
Andreas Färber05390242012-02-25 03:37:53 +01003348long do_sigreturn(CPUSH4State *regs)
thsc3b5bc82007-12-02 06:31:25 +00003349{
3350 struct target_sigframe *frame;
3351 abi_ulong frame_addr;
3352 sigset_t blocked;
Anthony Liguoric227f092009-10-01 16:12:16 -05003353 target_sigset_t target_set;
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003354 target_ulong r0;
thsc3b5bc82007-12-02 06:31:25 +00003355 int i;
3356 int err = 0;
3357
3358#if defined(DEBUG_SIGNAL)
3359 fprintf(stderr, "do_sigreturn\n");
3360#endif
3361 frame_addr = regs->gregs[15];
3362 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
3363 goto badframe;
3364
Riku Voipio1d8b5122014-04-23 10:26:05 +03003365 __get_user(target_set.sig[0], &frame->sc.oldmask);
thsc3b5bc82007-12-02 06:31:25 +00003366 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03003367 __get_user(target_set.sig[i], &frame->extramask[i - 1]);
thsc3b5bc82007-12-02 06:31:25 +00003368 }
3369
3370 if (err)
3371 goto badframe;
3372
3373 target_to_host_sigset_internal(&blocked, &target_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00003374 do_sigprocmask(SIG_SETMASK, &blocked, NULL);
thsc3b5bc82007-12-02 06:31:25 +00003375
Riku Voipio016d2e12014-04-23 11:19:48 +03003376 restore_sigcontext(regs, &frame->sc, &r0);
thsc3b5bc82007-12-02 06:31:25 +00003377
3378 unlock_user_struct(frame, frame_addr, 0);
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003379 return r0;
thsc3b5bc82007-12-02 06:31:25 +00003380
3381badframe:
3382 unlock_user_struct(frame, frame_addr, 0);
3383 force_sig(TARGET_SIGSEGV);
3384 return 0;
3385}
3386
Andreas Färber05390242012-02-25 03:37:53 +01003387long do_rt_sigreturn(CPUSH4State *regs)
thsc3b5bc82007-12-02 06:31:25 +00003388{
3389 struct target_rt_sigframe *frame;
3390 abi_ulong frame_addr;
3391 sigset_t blocked;
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003392 target_ulong r0;
thsc3b5bc82007-12-02 06:31:25 +00003393
3394#if defined(DEBUG_SIGNAL)
3395 fprintf(stderr, "do_rt_sigreturn\n");
3396#endif
3397 frame_addr = regs->gregs[15];
3398 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
3399 goto badframe;
3400
Aurelien Jarno60e99242010-03-29 02:12:51 +02003401 target_to_host_sigset(&blocked, &frame->uc.tuc_sigmask);
Alex Barcelo1c275922014-03-14 14:36:55 +00003402 do_sigprocmask(SIG_SETMASK, &blocked, NULL);
thsc3b5bc82007-12-02 06:31:25 +00003403
Riku Voipio016d2e12014-04-23 11:19:48 +03003404 restore_sigcontext(regs, &frame->uc.tuc_mcontext, &r0);
thsc3b5bc82007-12-02 06:31:25 +00003405
3406 if (do_sigaltstack(frame_addr +
Aurelien Jarno60e99242010-03-29 02:12:51 +02003407 offsetof(struct target_rt_sigframe, uc.tuc_stack),
thsc3b5bc82007-12-02 06:31:25 +00003408 0, get_sp_from_cpustate(regs)) == -EFAULT)
3409 goto badframe;
3410
3411 unlock_user_struct(frame, frame_addr, 0);
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003412 return r0;
thsc3b5bc82007-12-02 06:31:25 +00003413
3414badframe:
3415 unlock_user_struct(frame, frame_addr, 0);
3416 force_sig(TARGET_SIGSEGV);
3417 return 0;
3418}
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003419#elif defined(TARGET_MICROBLAZE)
3420
3421struct target_sigcontext {
3422 struct target_pt_regs regs; /* needs to be first */
3423 uint32_t oldmask;
3424};
3425
Edgar E. Iglesiasb2178702010-07-23 09:30:37 +02003426struct target_stack_t {
3427 abi_ulong ss_sp;
3428 int ss_flags;
3429 unsigned int ss_size;
3430};
3431
3432struct target_ucontext {
Richard Hendersonf711df62010-11-22 14:57:52 -08003433 abi_ulong tuc_flags;
3434 abi_ulong tuc_link;
3435 struct target_stack_t tuc_stack;
3436 struct target_sigcontext tuc_mcontext;
3437 uint32_t tuc_extramask[TARGET_NSIG_WORDS - 1];
Edgar E. Iglesiasb2178702010-07-23 09:30:37 +02003438};
3439
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003440/* Signal frames. */
3441struct target_signal_frame {
Edgar E. Iglesiasb2178702010-07-23 09:30:37 +02003442 struct target_ucontext uc;
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003443 uint32_t extramask[TARGET_NSIG_WORDS - 1];
3444 uint32_t tramp[2];
3445};
3446
3447struct rt_signal_frame {
Richard W.M. Jones02d2bd52012-07-05 03:32:44 +00003448 siginfo_t info;
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003449 struct ucontext uc;
3450 uint32_t tramp[2];
3451};
3452
Andreas Färber05390242012-02-25 03:37:53 +01003453static void setup_sigcontext(struct target_sigcontext *sc, CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003454{
3455 __put_user(env->regs[0], &sc->regs.r0);
3456 __put_user(env->regs[1], &sc->regs.r1);
3457 __put_user(env->regs[2], &sc->regs.r2);
3458 __put_user(env->regs[3], &sc->regs.r3);
3459 __put_user(env->regs[4], &sc->regs.r4);
3460 __put_user(env->regs[5], &sc->regs.r5);
3461 __put_user(env->regs[6], &sc->regs.r6);
3462 __put_user(env->regs[7], &sc->regs.r7);
3463 __put_user(env->regs[8], &sc->regs.r8);
3464 __put_user(env->regs[9], &sc->regs.r9);
3465 __put_user(env->regs[10], &sc->regs.r10);
3466 __put_user(env->regs[11], &sc->regs.r11);
3467 __put_user(env->regs[12], &sc->regs.r12);
3468 __put_user(env->regs[13], &sc->regs.r13);
3469 __put_user(env->regs[14], &sc->regs.r14);
3470 __put_user(env->regs[15], &sc->regs.r15);
3471 __put_user(env->regs[16], &sc->regs.r16);
3472 __put_user(env->regs[17], &sc->regs.r17);
3473 __put_user(env->regs[18], &sc->regs.r18);
3474 __put_user(env->regs[19], &sc->regs.r19);
3475 __put_user(env->regs[20], &sc->regs.r20);
3476 __put_user(env->regs[21], &sc->regs.r21);
3477 __put_user(env->regs[22], &sc->regs.r22);
3478 __put_user(env->regs[23], &sc->regs.r23);
3479 __put_user(env->regs[24], &sc->regs.r24);
3480 __put_user(env->regs[25], &sc->regs.r25);
3481 __put_user(env->regs[26], &sc->regs.r26);
3482 __put_user(env->regs[27], &sc->regs.r27);
3483 __put_user(env->regs[28], &sc->regs.r28);
3484 __put_user(env->regs[29], &sc->regs.r29);
3485 __put_user(env->regs[30], &sc->regs.r30);
3486 __put_user(env->regs[31], &sc->regs.r31);
3487 __put_user(env->sregs[SR_PC], &sc->regs.pc);
3488}
3489
Andreas Färber05390242012-02-25 03:37:53 +01003490static void restore_sigcontext(struct target_sigcontext *sc, CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003491{
3492 __get_user(env->regs[0], &sc->regs.r0);
3493 __get_user(env->regs[1], &sc->regs.r1);
3494 __get_user(env->regs[2], &sc->regs.r2);
3495 __get_user(env->regs[3], &sc->regs.r3);
3496 __get_user(env->regs[4], &sc->regs.r4);
3497 __get_user(env->regs[5], &sc->regs.r5);
3498 __get_user(env->regs[6], &sc->regs.r6);
3499 __get_user(env->regs[7], &sc->regs.r7);
3500 __get_user(env->regs[8], &sc->regs.r8);
3501 __get_user(env->regs[9], &sc->regs.r9);
3502 __get_user(env->regs[10], &sc->regs.r10);
3503 __get_user(env->regs[11], &sc->regs.r11);
3504 __get_user(env->regs[12], &sc->regs.r12);
3505 __get_user(env->regs[13], &sc->regs.r13);
3506 __get_user(env->regs[14], &sc->regs.r14);
3507 __get_user(env->regs[15], &sc->regs.r15);
3508 __get_user(env->regs[16], &sc->regs.r16);
3509 __get_user(env->regs[17], &sc->regs.r17);
3510 __get_user(env->regs[18], &sc->regs.r18);
3511 __get_user(env->regs[19], &sc->regs.r19);
3512 __get_user(env->regs[20], &sc->regs.r20);
3513 __get_user(env->regs[21], &sc->regs.r21);
3514 __get_user(env->regs[22], &sc->regs.r22);
3515 __get_user(env->regs[23], &sc->regs.r23);
3516 __get_user(env->regs[24], &sc->regs.r24);
3517 __get_user(env->regs[25], &sc->regs.r25);
3518 __get_user(env->regs[26], &sc->regs.r26);
3519 __get_user(env->regs[27], &sc->regs.r27);
3520 __get_user(env->regs[28], &sc->regs.r28);
3521 __get_user(env->regs[29], &sc->regs.r29);
3522 __get_user(env->regs[30], &sc->regs.r30);
3523 __get_user(env->regs[31], &sc->regs.r31);
3524 __get_user(env->sregs[SR_PC], &sc->regs.pc);
3525}
3526
3527static abi_ulong get_sigframe(struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01003528 CPUMBState *env, int frame_size)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003529{
3530 abi_ulong sp = env->regs[1];
3531
3532 if ((ka->sa_flags & SA_ONSTACK) != 0 && !on_sig_stack(sp))
3533 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
3534
3535 return ((sp - frame_size) & -8UL);
3536}
3537
3538static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01003539 target_sigset_t *set, CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003540{
3541 struct target_signal_frame *frame;
3542 abi_ulong frame_addr;
3543 int err = 0;
3544 int i;
3545
3546 frame_addr = get_sigframe(ka, env, sizeof *frame);
3547 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
3548 goto badframe;
3549
3550 /* Save the mask. */
Riku Voipio1d8b5122014-04-23 10:26:05 +03003551 __put_user(set->sig[0], &frame->uc.tuc_mcontext.oldmask);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003552 if (err)
3553 goto badframe;
3554
3555 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
3556 if (__put_user(set->sig[i], &frame->extramask[i - 1]))
3557 goto badframe;
3558 }
3559
Richard Hendersonf711df62010-11-22 14:57:52 -08003560 setup_sigcontext(&frame->uc.tuc_mcontext, env);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003561
3562 /* Set up to return from userspace. If provided, use a stub
3563 already in userspace. */
3564 /* minus 8 is offset to cater for "rtsd r15,8" offset */
3565 if (ka->sa_flags & TARGET_SA_RESTORER) {
3566 env->regs[15] = ((unsigned long)ka->sa_restorer)-8;
3567 } else {
3568 uint32_t t;
3569 /* Note, these encodings are _big endian_! */
3570 /* addi r12, r0, __NR_sigreturn */
3571 t = 0x31800000UL | TARGET_NR_sigreturn;
Riku Voipio1d8b5122014-04-23 10:26:05 +03003572 __put_user(t, frame->tramp + 0);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003573 /* brki r14, 0x8 */
3574 t = 0xb9cc0008UL;
Riku Voipio1d8b5122014-04-23 10:26:05 +03003575 __put_user(t, frame->tramp + 1);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003576
3577 /* Return from sighandler will jump to the tramp.
3578 Negative 8 offset because return is rtsd r15, 8 */
3579 env->regs[15] = ((unsigned long)frame->tramp) - 8;
3580 }
3581
3582 if (err)
3583 goto badframe;
3584
3585 /* Set up registers for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003586 env->regs[1] = frame_addr;
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003587 /* Signal handler args: */
3588 env->regs[5] = sig; /* Arg 0: signum */
Edgar E. Iglesias187b4e02010-07-15 15:32:51 +02003589 env->regs[6] = 0;
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003590 /* arg 1: sigcontext */
3591 env->regs[7] = frame_addr += offsetof(typeof(*frame), uc);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003592
3593 /* Offset of 4 to handle microblaze rtid r14, 0 */
3594 env->sregs[SR_PC] = (unsigned long)ka->_sa_handler;
3595
3596 unlock_user_struct(frame, frame_addr, 1);
3597 return;
3598 badframe:
3599 unlock_user_struct(frame, frame_addr, 1);
3600 force_sig(TARGET_SIGSEGV);
3601}
3602
3603static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05003604 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01003605 target_sigset_t *set, CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003606{
3607 fprintf(stderr, "Microblaze setup_rt_frame: not implemented\n");
3608}
3609
Andreas Färber05390242012-02-25 03:37:53 +01003610long do_sigreturn(CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003611{
3612 struct target_signal_frame *frame;
3613 abi_ulong frame_addr;
Anthony Liguoric227f092009-10-01 16:12:16 -05003614 target_sigset_t target_set;
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003615 sigset_t set;
3616 int i;
3617
3618 frame_addr = env->regs[R_SP];
3619 /* Make sure the guest isn't playing games. */
3620 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 1))
3621 goto badframe;
3622
3623 /* Restore blocked signals */
Riku Voipiof5f601a2014-04-23 13:00:17 +03003624 __get_user(target_set.sig[0], &frame->uc.tuc_mcontext.oldmask);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003625 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
Riku Voipiof5f601a2014-04-23 13:00:17 +03003626 __get_user(target_set.sig[i], &frame->extramask[i - 1]);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003627 }
3628 target_to_host_sigset_internal(&set, &target_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00003629 do_sigprocmask(SIG_SETMASK, &set, NULL);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003630
Richard Hendersonf711df62010-11-22 14:57:52 -08003631 restore_sigcontext(&frame->uc.tuc_mcontext, env);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003632 /* We got here through a sigreturn syscall, our path back is via an
3633 rtb insn so setup r14 for that. */
3634 env->regs[14] = env->sregs[SR_PC];
3635
3636 unlock_user_struct(frame, frame_addr, 0);
3637 return env->regs[10];
3638 badframe:
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003639 force_sig(TARGET_SIGSEGV);
3640}
3641
Andreas Färber05390242012-02-25 03:37:53 +01003642long do_rt_sigreturn(CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003643{
3644 fprintf(stderr, "Microblaze do_rt_sigreturn: not implemented\n");
3645 return -TARGET_ENOSYS;
3646}
3647
edgar_iglb6d3abd2008-02-28 11:29:27 +00003648#elif defined(TARGET_CRIS)
3649
3650struct target_sigcontext {
3651 struct target_pt_regs regs; /* needs to be first */
3652 uint32_t oldmask;
3653 uint32_t usp; /* usp before stacking this gunk on it */
3654};
3655
3656/* Signal frames. */
3657struct target_signal_frame {
3658 struct target_sigcontext sc;
3659 uint32_t extramask[TARGET_NSIG_WORDS - 1];
Stefan Weil8cfc1142014-02-01 09:41:09 +01003660 uint16_t retcode[4]; /* Trampoline code. */
edgar_iglb6d3abd2008-02-28 11:29:27 +00003661};
3662
3663struct rt_signal_frame {
Richard W.M. Jones02d2bd52012-07-05 03:32:44 +00003664 siginfo_t *pinfo;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003665 void *puc;
Richard W.M. Jones02d2bd52012-07-05 03:32:44 +00003666 siginfo_t info;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003667 struct ucontext uc;
Stefan Weil8cfc1142014-02-01 09:41:09 +01003668 uint16_t retcode[4]; /* Trampoline code. */
edgar_iglb6d3abd2008-02-28 11:29:27 +00003669};
3670
Andreas Färber05390242012-02-25 03:37:53 +01003671static void setup_sigcontext(struct target_sigcontext *sc, CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003672{
edgar_igl9664d922008-03-03 22:23:53 +00003673 __put_user(env->regs[0], &sc->regs.r0);
3674 __put_user(env->regs[1], &sc->regs.r1);
3675 __put_user(env->regs[2], &sc->regs.r2);
3676 __put_user(env->regs[3], &sc->regs.r3);
3677 __put_user(env->regs[4], &sc->regs.r4);
3678 __put_user(env->regs[5], &sc->regs.r5);
3679 __put_user(env->regs[6], &sc->regs.r6);
3680 __put_user(env->regs[7], &sc->regs.r7);
3681 __put_user(env->regs[8], &sc->regs.r8);
3682 __put_user(env->regs[9], &sc->regs.r9);
3683 __put_user(env->regs[10], &sc->regs.r10);
3684 __put_user(env->regs[11], &sc->regs.r11);
3685 __put_user(env->regs[12], &sc->regs.r12);
3686 __put_user(env->regs[13], &sc->regs.r13);
3687 __put_user(env->regs[14], &sc->usp);
3688 __put_user(env->regs[15], &sc->regs.acr);
3689 __put_user(env->pregs[PR_MOF], &sc->regs.mof);
3690 __put_user(env->pregs[PR_SRP], &sc->regs.srp);
3691 __put_user(env->pc, &sc->regs.erp);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003692}
edgar_igl9664d922008-03-03 22:23:53 +00003693
Andreas Färber05390242012-02-25 03:37:53 +01003694static void restore_sigcontext(struct target_sigcontext *sc, CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003695{
edgar_igl9664d922008-03-03 22:23:53 +00003696 __get_user(env->regs[0], &sc->regs.r0);
3697 __get_user(env->regs[1], &sc->regs.r1);
3698 __get_user(env->regs[2], &sc->regs.r2);
3699 __get_user(env->regs[3], &sc->regs.r3);
3700 __get_user(env->regs[4], &sc->regs.r4);
3701 __get_user(env->regs[5], &sc->regs.r5);
3702 __get_user(env->regs[6], &sc->regs.r6);
3703 __get_user(env->regs[7], &sc->regs.r7);
3704 __get_user(env->regs[8], &sc->regs.r8);
3705 __get_user(env->regs[9], &sc->regs.r9);
3706 __get_user(env->regs[10], &sc->regs.r10);
3707 __get_user(env->regs[11], &sc->regs.r11);
3708 __get_user(env->regs[12], &sc->regs.r12);
3709 __get_user(env->regs[13], &sc->regs.r13);
3710 __get_user(env->regs[14], &sc->usp);
3711 __get_user(env->regs[15], &sc->regs.acr);
3712 __get_user(env->pregs[PR_MOF], &sc->regs.mof);
3713 __get_user(env->pregs[PR_SRP], &sc->regs.srp);
3714 __get_user(env->pc, &sc->regs.erp);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003715}
3716
Andreas Färber05390242012-02-25 03:37:53 +01003717static abi_ulong get_sigframe(CPUCRISState *env, int framesize)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003718{
edgar_igl9664d922008-03-03 22:23:53 +00003719 abi_ulong sp;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003720 /* Align the stack downwards to 4. */
edgar_igl9664d922008-03-03 22:23:53 +00003721 sp = (env->regs[R_SP] & ~3);
3722 return sp - framesize;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003723}
3724
pbrook624f7972008-05-31 16:11:38 +00003725static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01003726 target_sigset_t *set, CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003727{
3728 struct target_signal_frame *frame;
edgar_igl9664d922008-03-03 22:23:53 +00003729 abi_ulong frame_addr;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003730 int err = 0;
3731 int i;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003732
edgar_igl9664d922008-03-03 22:23:53 +00003733 frame_addr = get_sigframe(env, sizeof *frame);
3734 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
edgar_iglb6d3abd2008-02-28 11:29:27 +00003735 goto badframe;
3736
3737 /*
3738 * The CRIS signal return trampoline. A real linux/CRIS kernel doesn't
3739 * use this trampoline anymore but it sets it up for GDB.
3740 * In QEMU, using the trampoline simplifies things a bit so we use it.
3741 *
3742 * This is movu.w __NR_sigreturn, r9; break 13;
3743 */
Riku Voipio1d8b5122014-04-23 10:26:05 +03003744 __put_user(0x9c5f, frame->retcode+0);
3745 __put_user(TARGET_NR_sigreturn,
3746 frame->retcode + 1);
3747 __put_user(0xe93d, frame->retcode + 2);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003748
3749 /* Save the mask. */
Riku Voipio1d8b5122014-04-23 10:26:05 +03003750 __put_user(set->sig[0], &frame->sc.oldmask);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003751 if (err)
3752 goto badframe;
3753
3754 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
3755 if (__put_user(set->sig[i], &frame->extramask[i - 1]))
3756 goto badframe;
3757 }
3758
3759 setup_sigcontext(&frame->sc, env);
3760
3761 /* Move the stack and setup the arguments for the handler. */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003762 env->regs[R_SP] = frame_addr;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003763 env->regs[10] = sig;
pbrook624f7972008-05-31 16:11:38 +00003764 env->pc = (unsigned long) ka->_sa_handler;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003765 /* Link SRP so the guest returns through the trampoline. */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003766 env->pregs[PR_SRP] = frame_addr + offsetof(typeof(*frame), retcode);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003767
edgar_igl9664d922008-03-03 22:23:53 +00003768 unlock_user_struct(frame, frame_addr, 1);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003769 return;
3770 badframe:
edgar_igl9664d922008-03-03 22:23:53 +00003771 unlock_user_struct(frame, frame_addr, 1);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003772 force_sig(TARGET_SIGSEGV);
3773}
3774
pbrook624f7972008-05-31 16:11:38 +00003775static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05003776 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01003777 target_sigset_t *set, CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003778{
3779 fprintf(stderr, "CRIS setup_rt_frame: not implemented\n");
3780}
3781
Andreas Färber05390242012-02-25 03:37:53 +01003782long do_sigreturn(CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003783{
3784 struct target_signal_frame *frame;
edgar_igl9664d922008-03-03 22:23:53 +00003785 abi_ulong frame_addr;
Anthony Liguoric227f092009-10-01 16:12:16 -05003786 target_sigset_t target_set;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003787 sigset_t set;
3788 int i;
3789
edgar_igl9664d922008-03-03 22:23:53 +00003790 frame_addr = env->regs[R_SP];
edgar_iglb6d3abd2008-02-28 11:29:27 +00003791 /* Make sure the guest isn't playing games. */
edgar_igl9664d922008-03-03 22:23:53 +00003792 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 1))
edgar_iglb6d3abd2008-02-28 11:29:27 +00003793 goto badframe;
3794
3795 /* Restore blocked signals */
Riku Voipiof5f601a2014-04-23 13:00:17 +03003796 __get_user(target_set.sig[0], &frame->sc.oldmask);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003797 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
Riku Voipiof5f601a2014-04-23 13:00:17 +03003798 __get_user(target_set.sig[i], &frame->extramask[i - 1]);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003799 }
3800 target_to_host_sigset_internal(&set, &target_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00003801 do_sigprocmask(SIG_SETMASK, &set, NULL);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003802
3803 restore_sigcontext(&frame->sc, env);
edgar_igl9664d922008-03-03 22:23:53 +00003804 unlock_user_struct(frame, frame_addr, 0);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003805 return env->regs[10];
3806 badframe:
edgar_iglb6d3abd2008-02-28 11:29:27 +00003807 force_sig(TARGET_SIGSEGV);
3808}
3809
Andreas Färber05390242012-02-25 03:37:53 +01003810long do_rt_sigreturn(CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003811{
3812 fprintf(stderr, "CRIS do_rt_sigreturn: not implemented\n");
3813 return -TARGET_ENOSYS;
3814}
thsc3b5bc82007-12-02 06:31:25 +00003815
Jia Liud9627832012-07-20 15:50:52 +08003816#elif defined(TARGET_OPENRISC)
3817
3818struct target_sigcontext {
3819 struct target_pt_regs regs;
3820 abi_ulong oldmask;
3821 abi_ulong usp;
3822};
3823
3824struct target_ucontext {
3825 abi_ulong tuc_flags;
3826 abi_ulong tuc_link;
3827 target_stack_t tuc_stack;
3828 struct target_sigcontext tuc_mcontext;
3829 target_sigset_t tuc_sigmask; /* mask last for extensibility */
3830};
3831
3832struct target_rt_sigframe {
3833 abi_ulong pinfo;
3834 uint64_t puc;
3835 struct target_siginfo info;
3836 struct target_sigcontext sc;
3837 struct target_ucontext uc;
3838 unsigned char retcode[16]; /* trampoline code */
3839};
3840
3841/* This is the asm-generic/ucontext.h version */
3842#if 0
3843static int restore_sigcontext(CPUOpenRISCState *regs,
3844 struct target_sigcontext *sc)
3845{
3846 unsigned int err = 0;
3847 unsigned long old_usp;
3848
3849 /* Alwys make any pending restarted system call return -EINTR */
3850 current_thread_info()->restart_block.fn = do_no_restart_syscall;
3851
3852 /* restore the regs from &sc->regs (same as sc, since regs is first)
3853 * (sc is already checked for VERIFY_READ since the sigframe was
3854 * checked in sys_sigreturn previously)
3855 */
3856
3857 if (copy_from_user(regs, &sc, sizeof(struct target_pt_regs))) {
3858 goto badframe;
3859 }
3860
3861 /* make sure the U-flag is set so user-mode cannot fool us */
3862
3863 regs->sr &= ~SR_SM;
3864
3865 /* restore the old USP as it was before we stacked the sc etc.
3866 * (we cannot just pop the sigcontext since we aligned the sp and
3867 * stuff after pushing it)
3868 */
3869
Riku Voipio1d8b5122014-04-23 10:26:05 +03003870 __get_user(old_usp, &sc->usp);
Jia Liud9627832012-07-20 15:50:52 +08003871 phx_signal("old_usp 0x%lx", old_usp);
3872
3873 __PHX__ REALLY /* ??? */
3874 wrusp(old_usp);
3875 regs->gpr[1] = old_usp;
3876
3877 /* TODO: the other ports use regs->orig_XX to disable syscall checks
3878 * after this completes, but we don't use that mechanism. maybe we can
3879 * use it now ?
3880 */
3881
3882 return err;
3883
3884badframe:
3885 return 1;
3886}
3887#endif
3888
3889/* Set up a signal frame. */
3890
Riku Voipio41ecc722014-04-23 11:01:00 +03003891static void setup_sigcontext(struct target_sigcontext *sc,
Jia Liud9627832012-07-20 15:50:52 +08003892 CPUOpenRISCState *regs,
3893 unsigned long mask)
3894{
Jia Liud9627832012-07-20 15:50:52 +08003895 unsigned long usp = regs->gpr[1];
3896
3897 /* copy the regs. they are first in sc so we can use sc directly */
3898
Riku Voipio1d8b5122014-04-23 10:26:05 +03003899 /*copy_to_user(&sc, regs, sizeof(struct target_pt_regs));*/
Jia Liud9627832012-07-20 15:50:52 +08003900
3901 /* Set the frametype to CRIS_FRAME_NORMAL for the execution of
3902 the signal handler. The frametype will be restored to its previous
3903 value in restore_sigcontext. */
3904 /*regs->frametype = CRIS_FRAME_NORMAL;*/
3905
3906 /* then some other stuff */
Riku Voipio1d8b5122014-04-23 10:26:05 +03003907 __put_user(mask, &sc->oldmask);
Riku Voipio41ecc722014-04-23 11:01:00 +03003908 __put_user(usp, &sc->usp);
Jia Liud9627832012-07-20 15:50:52 +08003909}
3910
3911static inline unsigned long align_sigframe(unsigned long sp)
3912{
3913 unsigned long i;
3914 i = sp & ~3UL;
3915 return i;
3916}
3917
3918static inline abi_ulong get_sigframe(struct target_sigaction *ka,
3919 CPUOpenRISCState *regs,
3920 size_t frame_size)
3921{
3922 unsigned long sp = regs->gpr[1];
3923 int onsigstack = on_sig_stack(sp);
3924
3925 /* redzone */
3926 /* This is the X/Open sanctioned signal stack switching. */
3927 if ((ka->sa_flags & SA_ONSTACK) != 0 && !onsigstack) {
3928 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
3929 }
3930
3931 sp = align_sigframe(sp - frame_size);
3932
3933 /*
3934 * If we are on the alternate signal stack and would overflow it, don't.
3935 * Return an always-bogus address instead so we will die with SIGSEGV.
3936 */
3937
3938 if (onsigstack && !likely(on_sig_stack(sp))) {
3939 return -1L;
3940 }
3941
3942 return sp;
3943}
3944
3945static void setup_frame(int sig, struct target_sigaction *ka,
3946 target_sigset_t *set, CPUOpenRISCState *env)
3947{
3948 qemu_log("Not implement.\n");
3949}
3950
3951static void setup_rt_frame(int sig, struct target_sigaction *ka,
3952 target_siginfo_t *info,
3953 target_sigset_t *set, CPUOpenRISCState *env)
3954{
3955 int err = 0;
3956 abi_ulong frame_addr;
3957 unsigned long return_ip;
3958 struct target_rt_sigframe *frame;
3959 abi_ulong info_addr, uc_addr;
3960
Jia Liud9627832012-07-20 15:50:52 +08003961 frame_addr = get_sigframe(ka, env, sizeof(*frame));
3962 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
3963 goto give_sigsegv;
3964 }
3965
3966 info_addr = frame_addr + offsetof(struct target_rt_sigframe, info);
Riku Voipio1d8b5122014-04-23 10:26:05 +03003967 __put_user(info_addr, &frame->pinfo);
Jia Liud9627832012-07-20 15:50:52 +08003968 uc_addr = frame_addr + offsetof(struct target_rt_sigframe, uc);
Riku Voipio1d8b5122014-04-23 10:26:05 +03003969 __put_user(uc_addr, &frame->puc);
Jia Liud9627832012-07-20 15:50:52 +08003970
3971 if (ka->sa_flags & SA_SIGINFO) {
Riku Voipiob0fd8d12014-04-23 10:46:13 +03003972 copy_siginfo_to_user(&frame->info, info);
Jia Liud9627832012-07-20 15:50:52 +08003973 }
3974
3975 /*err |= __clear_user(&frame->uc, offsetof(struct ucontext, uc_mcontext));*/
Riku Voipio1d8b5122014-04-23 10:26:05 +03003976 __put_user(0, &frame->uc.tuc_flags);
3977 __put_user(0, &frame->uc.tuc_link);
3978 __put_user(target_sigaltstack_used.ss_sp,
3979 &frame->uc.tuc_stack.ss_sp);
3980 __put_user(sas_ss_flags(env->gpr[1]), &frame->uc.tuc_stack.ss_flags);
3981 __put_user(target_sigaltstack_used.ss_size,
3982 &frame->uc.tuc_stack.ss_size);
Riku Voipio41ecc722014-04-23 11:01:00 +03003983 setup_sigcontext(&frame->sc, env, set->sig[0]);
Jia Liud9627832012-07-20 15:50:52 +08003984
3985 /*err |= copy_to_user(frame->uc.tuc_sigmask, set, sizeof(*set));*/
3986
Jia Liud9627832012-07-20 15:50:52 +08003987 /* trampoline - the desired return ip is the retcode itself */
3988 return_ip = (unsigned long)&frame->retcode;
3989 /* This is l.ori r11,r0,__NR_sigreturn, l.sys 1 */
Riku Voipio1d8b5122014-04-23 10:26:05 +03003990 __put_user(0xa960, (short *)(frame->retcode + 0));
3991 __put_user(TARGET_NR_rt_sigreturn, (short *)(frame->retcode + 2));
3992 __put_user(0x20000001, (unsigned long *)(frame->retcode + 4));
3993 __put_user(0x15000000, (unsigned long *)(frame->retcode + 8));
Jia Liud9627832012-07-20 15:50:52 +08003994
3995 if (err) {
3996 goto give_sigsegv;
3997 }
3998
3999 /* TODO what is the current->exec_domain stuff and invmap ? */
4000
4001 /* Set up registers for signal handler */
4002 env->pc = (unsigned long)ka->_sa_handler; /* what we enter NOW */
4003 env->gpr[9] = (unsigned long)return_ip; /* what we enter LATER */
4004 env->gpr[3] = (unsigned long)sig; /* arg 1: signo */
4005 env->gpr[4] = (unsigned long)&frame->info; /* arg 2: (siginfo_t*) */
4006 env->gpr[5] = (unsigned long)&frame->uc; /* arg 3: ucontext */
4007
4008 /* actually move the usp to reflect the stacked frame */
4009 env->gpr[1] = (unsigned long)frame;
4010
4011 return;
4012
4013give_sigsegv:
4014 unlock_user_struct(frame, frame_addr, 1);
4015 if (sig == TARGET_SIGSEGV) {
4016 ka->_sa_handler = TARGET_SIG_DFL;
4017 }
4018 force_sig(TARGET_SIGSEGV);
4019}
4020
4021long do_sigreturn(CPUOpenRISCState *env)
4022{
4023
4024 qemu_log("do_sigreturn: not implemented\n");
4025 return -TARGET_ENOSYS;
4026}
4027
4028long do_rt_sigreturn(CPUOpenRISCState *env)
4029{
4030 qemu_log("do_rt_sigreturn: not implemented\n");
4031 return -TARGET_ENOSYS;
4032}
4033/* TARGET_OPENRISC */
4034
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004035#elif defined(TARGET_S390X)
4036
4037#define __NUM_GPRS 16
4038#define __NUM_FPRS 16
4039#define __NUM_ACRS 16
4040
4041#define S390_SYSCALL_SIZE 2
4042#define __SIGNAL_FRAMESIZE 160 /* FIXME: 31-bit mode -> 96 */
4043
4044#define _SIGCONTEXT_NSIG 64
4045#define _SIGCONTEXT_NSIG_BPW 64 /* FIXME: 31-bit mode -> 32 */
4046#define _SIGCONTEXT_NSIG_WORDS (_SIGCONTEXT_NSIG / _SIGCONTEXT_NSIG_BPW)
4047#define _SIGMASK_COPY_SIZE (sizeof(unsigned long)*_SIGCONTEXT_NSIG_WORDS)
4048#define PSW_ADDR_AMODE 0x0000000000000000UL /* 0x80000000UL for 31-bit */
4049#define S390_SYSCALL_OPCODE ((uint16_t)0x0a00)
4050
4051typedef struct {
4052 target_psw_t psw;
4053 target_ulong gprs[__NUM_GPRS];
4054 unsigned int acrs[__NUM_ACRS];
4055} target_s390_regs_common;
4056
4057typedef struct {
4058 unsigned int fpc;
4059 double fprs[__NUM_FPRS];
4060} target_s390_fp_regs;
4061
4062typedef struct {
4063 target_s390_regs_common regs;
4064 target_s390_fp_regs fpregs;
4065} target_sigregs;
4066
4067struct target_sigcontext {
4068 target_ulong oldmask[_SIGCONTEXT_NSIG_WORDS];
4069 target_sigregs *sregs;
4070};
4071
4072typedef struct {
4073 uint8_t callee_used_stack[__SIGNAL_FRAMESIZE];
4074 struct target_sigcontext sc;
4075 target_sigregs sregs;
4076 int signo;
4077 uint8_t retcode[S390_SYSCALL_SIZE];
4078} sigframe;
4079
4080struct target_ucontext {
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004081 target_ulong tuc_flags;
4082 struct target_ucontext *tuc_link;
4083 target_stack_t tuc_stack;
4084 target_sigregs tuc_mcontext;
4085 target_sigset_t tuc_sigmask; /* mask last for extensibility */
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004086};
4087
4088typedef struct {
4089 uint8_t callee_used_stack[__SIGNAL_FRAMESIZE];
4090 uint8_t retcode[S390_SYSCALL_SIZE];
4091 struct target_siginfo info;
4092 struct target_ucontext uc;
4093} rt_sigframe;
4094
4095static inline abi_ulong
Andreas Färber05390242012-02-25 03:37:53 +01004096get_sigframe(struct target_sigaction *ka, CPUS390XState *env, size_t frame_size)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004097{
4098 abi_ulong sp;
4099
4100 /* Default to using normal stack */
4101 sp = env->regs[15];
4102
4103 /* This is the X/Open sanctioned signal stack switching. */
4104 if (ka->sa_flags & TARGET_SA_ONSTACK) {
4105 if (!sas_ss_flags(sp)) {
4106 sp = target_sigaltstack_used.ss_sp +
4107 target_sigaltstack_used.ss_size;
4108 }
4109 }
4110
4111 /* This is the legacy signal stack switching. */
4112 else if (/* FIXME !user_mode(regs) */ 0 &&
4113 !(ka->sa_flags & TARGET_SA_RESTORER) &&
4114 ka->sa_restorer) {
4115 sp = (abi_ulong) ka->sa_restorer;
4116 }
4117
4118 return (sp - frame_size) & -8ul;
4119}
4120
Andreas Färber05390242012-02-25 03:37:53 +01004121static void save_sigregs(CPUS390XState *env, target_sigregs *sregs)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004122{
4123 int i;
4124 //save_access_regs(current->thread.acrs); FIXME
4125
4126 /* Copy a 'clean' PSW mask to the user to avoid leaking
4127 information about whether PER is currently on. */
4128 __put_user(env->psw.mask, &sregs->regs.psw.mask);
4129 __put_user(env->psw.addr, &sregs->regs.psw.addr);
4130 for (i = 0; i < 16; i++) {
4131 __put_user(env->regs[i], &sregs->regs.gprs[i]);
4132 }
4133 for (i = 0; i < 16; i++) {
4134 __put_user(env->aregs[i], &sregs->regs.acrs[i]);
4135 }
4136 /*
4137 * We have to store the fp registers to current->thread.fp_regs
4138 * to merge them with the emulated registers.
4139 */
4140 //save_fp_regs(&current->thread.fp_regs); FIXME
4141 for (i = 0; i < 16; i++) {
4142 __put_user(env->fregs[i].ll, &sregs->fpregs.fprs[i]);
4143 }
4144}
4145
4146static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01004147 target_sigset_t *set, CPUS390XState *env)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004148{
4149 sigframe *frame;
4150 abi_ulong frame_addr;
4151
4152 frame_addr = get_sigframe(ka, env, sizeof(*frame));
4153 qemu_log("%s: frame_addr 0x%llx\n", __FUNCTION__,
4154 (unsigned long long)frame_addr);
4155 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
4156 goto give_sigsegv;
4157 }
4158
4159 qemu_log("%s: 1\n", __FUNCTION__);
4160 if (__put_user(set->sig[0], &frame->sc.oldmask[0])) {
4161 goto give_sigsegv;
4162 }
4163
4164 save_sigregs(env, &frame->sregs);
4165
4166 __put_user((abi_ulong)(unsigned long)&frame->sregs,
4167 (abi_ulong *)&frame->sc.sregs);
4168
4169 /* Set up to return from userspace. If provided, use a stub
4170 already in userspace. */
4171 if (ka->sa_flags & TARGET_SA_RESTORER) {
4172 env->regs[14] = (unsigned long)
4173 ka->sa_restorer | PSW_ADDR_AMODE;
4174 } else {
4175 env->regs[14] = (unsigned long)
4176 frame->retcode | PSW_ADDR_AMODE;
4177 if (__put_user(S390_SYSCALL_OPCODE | TARGET_NR_sigreturn,
4178 (uint16_t *)(frame->retcode)))
4179 goto give_sigsegv;
4180 }
4181
4182 /* Set up backchain. */
4183 if (__put_user(env->regs[15], (abi_ulong *) frame)) {
4184 goto give_sigsegv;
4185 }
4186
4187 /* Set up registers for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02004188 env->regs[15] = frame_addr;
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004189 env->psw.addr = (target_ulong) ka->_sa_handler | PSW_ADDR_AMODE;
4190
4191 env->regs[2] = sig; //map_signal(sig);
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02004192 env->regs[3] = frame_addr += offsetof(typeof(*frame), sc);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004193
4194 /* We forgot to include these in the sigcontext.
4195 To avoid breaking binary compatibility, they are passed as args. */
4196 env->regs[4] = 0; // FIXME: no clue... current->thread.trap_no;
4197 env->regs[5] = 0; // FIXME: no clue... current->thread.prot_addr;
4198
4199 /* Place signal number on stack to allow backtrace from handler. */
4200 if (__put_user(env->regs[2], (int *) &frame->signo)) {
4201 goto give_sigsegv;
4202 }
4203 unlock_user_struct(frame, frame_addr, 1);
4204 return;
4205
4206give_sigsegv:
4207 qemu_log("%s: give_sigsegv\n", __FUNCTION__);
4208 unlock_user_struct(frame, frame_addr, 1);
4209 force_sig(TARGET_SIGSEGV);
4210}
4211
4212static void setup_rt_frame(int sig, struct target_sigaction *ka,
4213 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01004214 target_sigset_t *set, CPUS390XState *env)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004215{
4216 int i;
4217 rt_sigframe *frame;
4218 abi_ulong frame_addr;
4219
4220 frame_addr = get_sigframe(ka, env, sizeof *frame);
4221 qemu_log("%s: frame_addr 0x%llx\n", __FUNCTION__,
4222 (unsigned long long)frame_addr);
4223 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
4224 goto give_sigsegv;
4225 }
4226
4227 qemu_log("%s: 1\n", __FUNCTION__);
Riku Voipiob0fd8d12014-04-23 10:46:13 +03004228 copy_siginfo_to_user(&frame->info, info);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004229
4230 /* Create the ucontext. */
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004231 __put_user(0, &frame->uc.tuc_flags);
4232 __put_user((abi_ulong)0, (abi_ulong *)&frame->uc.tuc_link);
4233 __put_user(target_sigaltstack_used.ss_sp, &frame->uc.tuc_stack.ss_sp);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004234 __put_user(sas_ss_flags(get_sp_from_cpustate(env)),
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004235 &frame->uc.tuc_stack.ss_flags);
4236 __put_user(target_sigaltstack_used.ss_size, &frame->uc.tuc_stack.ss_size);
4237 save_sigregs(env, &frame->uc.tuc_mcontext);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004238 for (i = 0; i < TARGET_NSIG_WORDS; i++) {
4239 __put_user((abi_ulong)set->sig[i],
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004240 (abi_ulong *)&frame->uc.tuc_sigmask.sig[i]);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004241 }
4242
4243 /* Set up to return from userspace. If provided, use a stub
4244 already in userspace. */
4245 if (ka->sa_flags & TARGET_SA_RESTORER) {
4246 env->regs[14] = (unsigned long) ka->sa_restorer | PSW_ADDR_AMODE;
4247 } else {
4248 env->regs[14] = (unsigned long) frame->retcode | PSW_ADDR_AMODE;
4249 if (__put_user(S390_SYSCALL_OPCODE | TARGET_NR_rt_sigreturn,
4250 (uint16_t *)(frame->retcode))) {
4251 goto give_sigsegv;
4252 }
4253 }
4254
4255 /* Set up backchain. */
4256 if (__put_user(env->regs[15], (abi_ulong *) frame)) {
4257 goto give_sigsegv;
4258 }
4259
4260 /* Set up registers for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02004261 env->regs[15] = frame_addr;
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004262 env->psw.addr = (target_ulong) ka->_sa_handler | PSW_ADDR_AMODE;
4263
4264 env->regs[2] = sig; //map_signal(sig);
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02004265 env->regs[3] = frame_addr + offsetof(typeof(*frame), info);
4266 env->regs[4] = frame_addr + offsetof(typeof(*frame), uc);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004267 return;
4268
4269give_sigsegv:
4270 qemu_log("%s: give_sigsegv\n", __FUNCTION__);
4271 unlock_user_struct(frame, frame_addr, 1);
4272 force_sig(TARGET_SIGSEGV);
4273}
4274
4275static int
Andreas Färber05390242012-02-25 03:37:53 +01004276restore_sigregs(CPUS390XState *env, target_sigregs *sc)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004277{
4278 int err = 0;
4279 int i;
4280
4281 for (i = 0; i < 16; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03004282 __get_user(env->regs[i], &sc->regs.gprs[i]);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004283 }
4284
Riku Voipio1d8b5122014-04-23 10:26:05 +03004285 __get_user(env->psw.mask, &sc->regs.psw.mask);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004286 qemu_log("%s: sc->regs.psw.addr 0x%llx env->psw.addr 0x%llx\n",
4287 __FUNCTION__, (unsigned long long)sc->regs.psw.addr,
4288 (unsigned long long)env->psw.addr);
Riku Voipio1d8b5122014-04-23 10:26:05 +03004289 __get_user(env->psw.addr, &sc->regs.psw.addr);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004290 /* FIXME: 31-bit -> | PSW_ADDR_AMODE */
4291
4292 for (i = 0; i < 16; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03004293 __get_user(env->aregs[i], &sc->regs.acrs[i]);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004294 }
4295 for (i = 0; i < 16; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03004296 __get_user(env->fregs[i].ll, &sc->fpregs.fprs[i]);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004297 }
4298
4299 return err;
4300}
4301
Andreas Färber05390242012-02-25 03:37:53 +01004302long do_sigreturn(CPUS390XState *env)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004303{
4304 sigframe *frame;
4305 abi_ulong frame_addr = env->regs[15];
4306 qemu_log("%s: frame_addr 0x%llx\n", __FUNCTION__,
4307 (unsigned long long)frame_addr);
4308 target_sigset_t target_set;
4309 sigset_t set;
4310
4311 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
4312 goto badframe;
4313 }
Riku Voipiof5f601a2014-04-23 13:00:17 +03004314 __get_user(target_set.sig[0], &frame->sc.oldmask[0]);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004315
4316 target_to_host_sigset_internal(&set, &target_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00004317 do_sigprocmask(SIG_SETMASK, &set, NULL); /* ~_BLOCKABLE? */
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004318
4319 if (restore_sigregs(env, &frame->sregs)) {
4320 goto badframe;
4321 }
4322
4323 unlock_user_struct(frame, frame_addr, 0);
4324 return env->regs[2];
4325
4326badframe:
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004327 force_sig(TARGET_SIGSEGV);
4328 return 0;
4329}
4330
Andreas Färber05390242012-02-25 03:37:53 +01004331long do_rt_sigreturn(CPUS390XState *env)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004332{
4333 rt_sigframe *frame;
4334 abi_ulong frame_addr = env->regs[15];
4335 qemu_log("%s: frame_addr 0x%llx\n", __FUNCTION__,
4336 (unsigned long long)frame_addr);
4337 sigset_t set;
4338
4339 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
4340 goto badframe;
4341 }
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004342 target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004343
Alex Barcelo1c275922014-03-14 14:36:55 +00004344 do_sigprocmask(SIG_SETMASK, &set, NULL); /* ~_BLOCKABLE? */
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004345
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004346 if (restore_sigregs(env, &frame->uc.tuc_mcontext)) {
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004347 goto badframe;
4348 }
4349
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004350 if (do_sigaltstack(frame_addr + offsetof(rt_sigframe, uc.tuc_stack), 0,
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004351 get_sp_from_cpustate(env)) == -EFAULT) {
4352 goto badframe;
4353 }
4354 unlock_user_struct(frame, frame_addr, 0);
4355 return env->regs[2];
4356
4357badframe:
4358 unlock_user_struct(frame, frame_addr, 0);
4359 force_sig(TARGET_SIGSEGV);
4360 return 0;
4361}
4362
Nathan Froydbcd49332009-05-12 19:13:18 -07004363#elif defined(TARGET_PPC) && !defined(TARGET_PPC64)
4364
4365/* FIXME: Many of the structures are defined for both PPC and PPC64, but
4366 the signal handling is different enough that we haven't implemented
4367 support for PPC64 yet. Hence the restriction above.
4368
4369 There are various #if'd blocks for code for TARGET_PPC64. These
4370 blocks should go away so that we can successfully run 32-bit and
4371 64-bit binaries on a QEMU configured for PPC64. */
4372
4373/* Size of dummy stack frame allocated when calling signal handler.
4374 See arch/powerpc/include/asm/ptrace.h. */
4375#if defined(TARGET_PPC64)
4376#define SIGNAL_FRAMESIZE 128
4377#else
4378#define SIGNAL_FRAMESIZE 64
4379#endif
4380
4381/* See arch/powerpc/include/asm/sigcontext.h. */
4382struct target_sigcontext {
4383 target_ulong _unused[4];
4384 int32_t signal;
4385#if defined(TARGET_PPC64)
4386 int32_t pad0;
4387#endif
4388 target_ulong handler;
4389 target_ulong oldmask;
4390 target_ulong regs; /* struct pt_regs __user * */
4391 /* TODO: PPC64 includes extra bits here. */
4392};
4393
4394/* Indices for target_mcontext.mc_gregs, below.
4395 See arch/powerpc/include/asm/ptrace.h for details. */
4396enum {
4397 TARGET_PT_R0 = 0,
4398 TARGET_PT_R1 = 1,
4399 TARGET_PT_R2 = 2,
4400 TARGET_PT_R3 = 3,
4401 TARGET_PT_R4 = 4,
4402 TARGET_PT_R5 = 5,
4403 TARGET_PT_R6 = 6,
4404 TARGET_PT_R7 = 7,
4405 TARGET_PT_R8 = 8,
4406 TARGET_PT_R9 = 9,
4407 TARGET_PT_R10 = 10,
4408 TARGET_PT_R11 = 11,
4409 TARGET_PT_R12 = 12,
4410 TARGET_PT_R13 = 13,
4411 TARGET_PT_R14 = 14,
4412 TARGET_PT_R15 = 15,
4413 TARGET_PT_R16 = 16,
4414 TARGET_PT_R17 = 17,
4415 TARGET_PT_R18 = 18,
4416 TARGET_PT_R19 = 19,
4417 TARGET_PT_R20 = 20,
4418 TARGET_PT_R21 = 21,
4419 TARGET_PT_R22 = 22,
4420 TARGET_PT_R23 = 23,
4421 TARGET_PT_R24 = 24,
4422 TARGET_PT_R25 = 25,
4423 TARGET_PT_R26 = 26,
4424 TARGET_PT_R27 = 27,
4425 TARGET_PT_R28 = 28,
4426 TARGET_PT_R29 = 29,
4427 TARGET_PT_R30 = 30,
4428 TARGET_PT_R31 = 31,
4429 TARGET_PT_NIP = 32,
4430 TARGET_PT_MSR = 33,
4431 TARGET_PT_ORIG_R3 = 34,
4432 TARGET_PT_CTR = 35,
4433 TARGET_PT_LNK = 36,
4434 TARGET_PT_XER = 37,
4435 TARGET_PT_CCR = 38,
4436 /* Yes, there are two registers with #39. One is 64-bit only. */
4437 TARGET_PT_MQ = 39,
4438 TARGET_PT_SOFTE = 39,
4439 TARGET_PT_TRAP = 40,
4440 TARGET_PT_DAR = 41,
4441 TARGET_PT_DSISR = 42,
4442 TARGET_PT_RESULT = 43,
4443 TARGET_PT_REGS_COUNT = 44
4444};
4445
4446/* See arch/powerpc/include/asm/ucontext.h. Only used for 32-bit PPC;
4447 on 64-bit PPC, sigcontext and mcontext are one and the same. */
4448struct target_mcontext {
4449 target_ulong mc_gregs[48];
4450 /* Includes fpscr. */
4451 uint64_t mc_fregs[33];
4452 target_ulong mc_pad[2];
4453 /* We need to handle Altivec and SPE at the same time, which no
4454 kernel needs to do. Fortunately, the kernel defines this bit to
4455 be Altivec-register-large all the time, rather than trying to
4456 twiddle it based on the specific platform. */
4457 union {
4458 /* SPE vector registers. One extra for SPEFSCR. */
4459 uint32_t spe[33];
4460 /* Altivec vector registers. The packing of VSCR and VRSAVE
4461 varies depending on whether we're PPC64 or not: PPC64 splits
4462 them apart; PPC32 stuffs them together. */
4463#if defined(TARGET_PPC64)
malc3efa9a62009-07-18 13:10:12 +04004464#define QEMU_NVRREG 34
Nathan Froydbcd49332009-05-12 19:13:18 -07004465#else
malc3efa9a62009-07-18 13:10:12 +04004466#define QEMU_NVRREG 33
Nathan Froydbcd49332009-05-12 19:13:18 -07004467#endif
Anthony Liguoric227f092009-10-01 16:12:16 -05004468 ppc_avr_t altivec[QEMU_NVRREG];
malc3efa9a62009-07-18 13:10:12 +04004469#undef QEMU_NVRREG
Nathan Froydbcd49332009-05-12 19:13:18 -07004470 } mc_vregs __attribute__((__aligned__(16)));
4471};
4472
4473struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02004474 target_ulong tuc_flags;
4475 target_ulong tuc_link; /* struct ucontext __user * */
4476 struct target_sigaltstack tuc_stack;
Nathan Froydbcd49332009-05-12 19:13:18 -07004477#if !defined(TARGET_PPC64)
Aurelien Jarno60e99242010-03-29 02:12:51 +02004478 int32_t tuc_pad[7];
4479 target_ulong tuc_regs; /* struct mcontext __user *
Nathan Froydbcd49332009-05-12 19:13:18 -07004480 points to uc_mcontext field */
4481#endif
Aurelien Jarno60e99242010-03-29 02:12:51 +02004482 target_sigset_t tuc_sigmask;
Nathan Froydbcd49332009-05-12 19:13:18 -07004483#if defined(TARGET_PPC64)
Anthony Liguoric227f092009-10-01 16:12:16 -05004484 target_sigset_t unused[15]; /* Allow for uc_sigmask growth */
Aurelien Jarno60e99242010-03-29 02:12:51 +02004485 struct target_sigcontext tuc_mcontext;
Nathan Froydbcd49332009-05-12 19:13:18 -07004486#else
Aurelien Jarno60e99242010-03-29 02:12:51 +02004487 int32_t tuc_maskext[30];
4488 int32_t tuc_pad2[3];
4489 struct target_mcontext tuc_mcontext;
Nathan Froydbcd49332009-05-12 19:13:18 -07004490#endif
4491};
4492
4493/* See arch/powerpc/kernel/signal_32.c. */
4494struct target_sigframe {
4495 struct target_sigcontext sctx;
4496 struct target_mcontext mctx;
4497 int32_t abigap[56];
4498};
4499
4500struct target_rt_sigframe {
4501 struct target_siginfo info;
4502 struct target_ucontext uc;
4503 int32_t abigap[56];
4504};
4505
4506/* We use the mc_pad field for the signal return trampoline. */
4507#define tramp mc_pad
4508
4509/* See arch/powerpc/kernel/signal.c. */
4510static target_ulong get_sigframe(struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01004511 CPUPPCState *env,
Nathan Froydbcd49332009-05-12 19:13:18 -07004512 int frame_size)
4513{
4514 target_ulong oldsp, newsp;
4515
4516 oldsp = env->gpr[1];
4517
4518 if ((ka->sa_flags & TARGET_SA_ONSTACK) &&
Alex Barcelo32a20032012-02-09 23:55:46 +00004519 (sas_ss_flags(oldsp) == 0)) {
Nathan Froydbcd49332009-05-12 19:13:18 -07004520 oldsp = (target_sigaltstack_used.ss_sp
4521 + target_sigaltstack_used.ss_size);
4522 }
4523
4524 newsp = (oldsp - frame_size) & ~0xFUL;
4525
4526 return newsp;
4527}
4528
Andreas Färber05390242012-02-25 03:37:53 +01004529static int save_user_regs(CPUPPCState *env, struct target_mcontext *frame,
Nathan Froydbcd49332009-05-12 19:13:18 -07004530 int sigret)
4531{
4532 target_ulong msr = env->msr;
4533 int i;
4534 target_ulong ccr = 0;
4535
4536 /* In general, the kernel attempts to be intelligent about what it
4537 needs to save for Altivec/FP/SPE registers. We don't care that
4538 much, so we just go ahead and save everything. */
4539
4540 /* Save general registers. */
4541 for (i = 0; i < ARRAY_SIZE(env->gpr); i++) {
4542 if (__put_user(env->gpr[i], &frame->mc_gregs[i])) {
4543 return 1;
4544 }
4545 }
4546 if (__put_user(env->nip, &frame->mc_gregs[TARGET_PT_NIP])
4547 || __put_user(env->ctr, &frame->mc_gregs[TARGET_PT_CTR])
4548 || __put_user(env->lr, &frame->mc_gregs[TARGET_PT_LNK])
4549 || __put_user(env->xer, &frame->mc_gregs[TARGET_PT_XER]))
4550 return 1;
4551
4552 for (i = 0; i < ARRAY_SIZE(env->crf); i++) {
4553 ccr |= env->crf[i] << (32 - ((i + 1) * 4));
4554 }
4555 if (__put_user(ccr, &frame->mc_gregs[TARGET_PT_CCR]))
4556 return 1;
4557
4558 /* Save Altivec registers if necessary. */
4559 if (env->insns_flags & PPC_ALTIVEC) {
4560 for (i = 0; i < ARRAY_SIZE(env->avr); i++) {
Anthony Liguoric227f092009-10-01 16:12:16 -05004561 ppc_avr_t *avr = &env->avr[i];
4562 ppc_avr_t *vreg = &frame->mc_vregs.altivec[i];
Nathan Froydbcd49332009-05-12 19:13:18 -07004563
4564 if (__put_user(avr->u64[0], &vreg->u64[0]) ||
4565 __put_user(avr->u64[1], &vreg->u64[1])) {
4566 return 1;
4567 }
4568 }
4569 /* Set MSR_VR in the saved MSR value to indicate that
4570 frame->mc_vregs contains valid data. */
4571 msr |= MSR_VR;
4572 if (__put_user((uint32_t)env->spr[SPR_VRSAVE],
4573 &frame->mc_vregs.altivec[32].u32[3]))
4574 return 1;
4575 }
4576
4577 /* Save floating point registers. */
4578 if (env->insns_flags & PPC_FLOAT) {
4579 for (i = 0; i < ARRAY_SIZE(env->fpr); i++) {
4580 if (__put_user(env->fpr[i], &frame->mc_fregs[i])) {
4581 return 1;
4582 }
4583 }
4584 if (__put_user((uint64_t) env->fpscr, &frame->mc_fregs[32]))
4585 return 1;
4586 }
4587
4588 /* Save SPE registers. The kernel only saves the high half. */
4589 if (env->insns_flags & PPC_SPE) {
4590#if defined(TARGET_PPC64)
4591 for (i = 0; i < ARRAY_SIZE(env->gpr); i++) {
4592 if (__put_user(env->gpr[i] >> 32, &frame->mc_vregs.spe[i])) {
4593 return 1;
4594 }
4595 }
4596#else
4597 for (i = 0; i < ARRAY_SIZE(env->gprh); i++) {
4598 if (__put_user(env->gprh[i], &frame->mc_vregs.spe[i])) {
4599 return 1;
4600 }
4601 }
4602#endif
4603 /* Set MSR_SPE in the saved MSR value to indicate that
4604 frame->mc_vregs contains valid data. */
4605 msr |= MSR_SPE;
4606 if (__put_user(env->spe_fscr, &frame->mc_vregs.spe[32]))
4607 return 1;
4608 }
4609
4610 /* Store MSR. */
4611 if (__put_user(msr, &frame->mc_gregs[TARGET_PT_MSR]))
4612 return 1;
4613
4614 /* Set up the sigreturn trampoline: li r0,sigret; sc. */
4615 if (sigret) {
4616 if (__put_user(0x38000000UL | sigret, &frame->tramp[0]) ||
4617 __put_user(0x44000002UL, &frame->tramp[1])) {
4618 return 1;
4619 }
4620 }
4621
4622 return 0;
4623}
4624
Andreas Färber05390242012-02-25 03:37:53 +01004625static int restore_user_regs(CPUPPCState *env,
Nathan Froydbcd49332009-05-12 19:13:18 -07004626 struct target_mcontext *frame, int sig)
4627{
4628 target_ulong save_r2 = 0;
4629 target_ulong msr;
4630 target_ulong ccr;
4631
4632 int i;
4633
4634 if (!sig) {
4635 save_r2 = env->gpr[2];
4636 }
4637
4638 /* Restore general registers. */
4639 for (i = 0; i < ARRAY_SIZE(env->gpr); i++) {
4640 if (__get_user(env->gpr[i], &frame->mc_gregs[i])) {
4641 return 1;
4642 }
4643 }
4644 if (__get_user(env->nip, &frame->mc_gregs[TARGET_PT_NIP])
4645 || __get_user(env->ctr, &frame->mc_gregs[TARGET_PT_CTR])
4646 || __get_user(env->lr, &frame->mc_gregs[TARGET_PT_LNK])
4647 || __get_user(env->xer, &frame->mc_gregs[TARGET_PT_XER]))
4648 return 1;
4649 if (__get_user(ccr, &frame->mc_gregs[TARGET_PT_CCR]))
4650 return 1;
4651
4652 for (i = 0; i < ARRAY_SIZE(env->crf); i++) {
4653 env->crf[i] = (ccr >> (32 - ((i + 1) * 4))) & 0xf;
4654 }
4655
4656 if (!sig) {
4657 env->gpr[2] = save_r2;
4658 }
4659 /* Restore MSR. */
4660 if (__get_user(msr, &frame->mc_gregs[TARGET_PT_MSR]))
4661 return 1;
4662
4663 /* If doing signal return, restore the previous little-endian mode. */
4664 if (sig)
4665 env->msr = (env->msr & ~MSR_LE) | (msr & MSR_LE);
4666
4667 /* Restore Altivec registers if necessary. */
4668 if (env->insns_flags & PPC_ALTIVEC) {
4669 for (i = 0; i < ARRAY_SIZE(env->avr); i++) {
Anthony Liguoric227f092009-10-01 16:12:16 -05004670 ppc_avr_t *avr = &env->avr[i];
4671 ppc_avr_t *vreg = &frame->mc_vregs.altivec[i];
Nathan Froydbcd49332009-05-12 19:13:18 -07004672
4673 if (__get_user(avr->u64[0], &vreg->u64[0]) ||
4674 __get_user(avr->u64[1], &vreg->u64[1])) {
4675 return 1;
4676 }
4677 }
4678 /* Set MSR_VEC in the saved MSR value to indicate that
4679 frame->mc_vregs contains valid data. */
4680 if (__get_user(env->spr[SPR_VRSAVE],
4681 (target_ulong *)(&frame->mc_vregs.altivec[32].u32[3])))
4682 return 1;
4683 }
4684
4685 /* Restore floating point registers. */
4686 if (env->insns_flags & PPC_FLOAT) {
4687 uint64_t fpscr;
4688 for (i = 0; i < ARRAY_SIZE(env->fpr); i++) {
4689 if (__get_user(env->fpr[i], &frame->mc_fregs[i])) {
4690 return 1;
4691 }
4692 }
4693 if (__get_user(fpscr, &frame->mc_fregs[32]))
4694 return 1;
4695 env->fpscr = (uint32_t) fpscr;
4696 }
4697
4698 /* Save SPE registers. The kernel only saves the high half. */
4699 if (env->insns_flags & PPC_SPE) {
4700#if defined(TARGET_PPC64)
4701 for (i = 0; i < ARRAY_SIZE(env->gpr); i++) {
4702 uint32_t hi;
4703
4704 if (__get_user(hi, &frame->mc_vregs.spe[i])) {
4705 return 1;
4706 }
4707 env->gpr[i] = ((uint64_t)hi << 32) | ((uint32_t) env->gpr[i]);
4708 }
4709#else
4710 for (i = 0; i < ARRAY_SIZE(env->gprh); i++) {
4711 if (__get_user(env->gprh[i], &frame->mc_vregs.spe[i])) {
4712 return 1;
4713 }
4714 }
4715#endif
4716 if (__get_user(env->spe_fscr, &frame->mc_vregs.spe[32]))
4717 return 1;
4718 }
4719
4720 return 0;
4721}
4722
4723static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01004724 target_sigset_t *set, CPUPPCState *env)
Nathan Froydbcd49332009-05-12 19:13:18 -07004725{
4726 struct target_sigframe *frame;
4727 struct target_sigcontext *sc;
4728 target_ulong frame_addr, newsp;
4729 int err = 0;
4730 int signal;
4731
4732 frame_addr = get_sigframe(ka, env, sizeof(*frame));
4733 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 1))
4734 goto sigsegv;
4735 sc = &frame->sctx;
4736
4737 signal = current_exec_domain_sig(sig);
4738
Riku Voipio1d8b5122014-04-23 10:26:05 +03004739 __put_user(ka->_sa_handler, &sc->handler);
4740 __put_user(set->sig[0], &sc->oldmask);
Nathan Froydbcd49332009-05-12 19:13:18 -07004741#if defined(TARGET_PPC64)
Riku Voipio1d8b5122014-04-23 10:26:05 +03004742 __put_user(set->sig[0] >> 32, &sc->_unused[3]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004743#else
Riku Voipio1d8b5122014-04-23 10:26:05 +03004744 __put_user(set->sig[1], &sc->_unused[3]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004745#endif
Riku Voipio1d8b5122014-04-23 10:26:05 +03004746 __put_user(h2g(&frame->mctx), &sc->regs);
4747 __put_user(sig, &sc->signal);
Nathan Froydbcd49332009-05-12 19:13:18 -07004748
4749 /* Save user regs. */
4750 err |= save_user_regs(env, &frame->mctx, TARGET_NR_sigreturn);
4751
4752 /* The kernel checks for the presence of a VDSO here. We don't
4753 emulate a vdso, so use a sigreturn system call. */
4754 env->lr = (target_ulong) h2g(frame->mctx.tramp);
4755
4756 /* Turn off all fp exceptions. */
4757 env->fpscr = 0;
4758
4759 /* Create a stack frame for the caller of the handler. */
4760 newsp = frame_addr - SIGNAL_FRAMESIZE;
Samuel Seaybeb526b2013-01-02 10:53:46 +00004761 err |= put_user(env->gpr[1], newsp, target_ulong);
Nathan Froydbcd49332009-05-12 19:13:18 -07004762
4763 if (err)
4764 goto sigsegv;
4765
4766 /* Set up registers for signal handler. */
4767 env->gpr[1] = newsp;
4768 env->gpr[3] = signal;
Samuel Seay61993a62013-01-04 14:35:48 +00004769 env->gpr[4] = frame_addr + offsetof(struct target_sigframe, sctx);
Nathan Froydbcd49332009-05-12 19:13:18 -07004770 env->nip = (target_ulong) ka->_sa_handler;
4771 /* Signal handlers are entered in big-endian mode. */
4772 env->msr &= ~MSR_LE;
4773
4774 unlock_user_struct(frame, frame_addr, 1);
4775 return;
4776
4777sigsegv:
4778 unlock_user_struct(frame, frame_addr, 1);
Blue Swirleeacee42012-06-03 16:35:32 +00004779 qemu_log("segfaulting from setup_frame\n");
Riku Voipio66393fb2009-12-04 15:16:32 +02004780 force_sig(TARGET_SIGSEGV);
Nathan Froydbcd49332009-05-12 19:13:18 -07004781}
4782
4783static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05004784 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01004785 target_sigset_t *set, CPUPPCState *env)
Nathan Froydbcd49332009-05-12 19:13:18 -07004786{
4787 struct target_rt_sigframe *rt_sf;
4788 struct target_mcontext *frame;
4789 target_ulong rt_sf_addr, newsp = 0;
4790 int i, err = 0;
4791 int signal;
4792
4793 rt_sf_addr = get_sigframe(ka, env, sizeof(*rt_sf));
4794 if (!lock_user_struct(VERIFY_WRITE, rt_sf, rt_sf_addr, 1))
4795 goto sigsegv;
4796
4797 signal = current_exec_domain_sig(sig);
4798
Riku Voipiob0fd8d12014-04-23 10:46:13 +03004799 copy_siginfo_to_user(&rt_sf->info, info);
Nathan Froydbcd49332009-05-12 19:13:18 -07004800
Riku Voipio1d8b5122014-04-23 10:26:05 +03004801 __put_user(0, &rt_sf->uc.tuc_flags);
4802 __put_user(0, &rt_sf->uc.tuc_link);
4803 __put_user((target_ulong)target_sigaltstack_used.ss_sp,
4804 &rt_sf->uc.tuc_stack.ss_sp);
4805 __put_user(sas_ss_flags(env->gpr[1]),
4806 &rt_sf->uc.tuc_stack.ss_flags);
4807 __put_user(target_sigaltstack_used.ss_size,
4808 &rt_sf->uc.tuc_stack.ss_size);
4809 __put_user(h2g (&rt_sf->uc.tuc_mcontext),
4810 &rt_sf->uc.tuc_regs);
Nathan Froydbcd49332009-05-12 19:13:18 -07004811 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03004812 __put_user(set->sig[i], &rt_sf->uc.tuc_sigmask.sig[i]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004813 }
4814
Aurelien Jarno60e99242010-03-29 02:12:51 +02004815 frame = &rt_sf->uc.tuc_mcontext;
Nathan Froydbcd49332009-05-12 19:13:18 -07004816 err |= save_user_regs(env, frame, TARGET_NR_rt_sigreturn);
4817
4818 /* The kernel checks for the presence of a VDSO here. We don't
4819 emulate a vdso, so use a sigreturn system call. */
4820 env->lr = (target_ulong) h2g(frame->tramp);
4821
4822 /* Turn off all fp exceptions. */
4823 env->fpscr = 0;
4824
4825 /* Create a stack frame for the caller of the handler. */
4826 newsp = rt_sf_addr - (SIGNAL_FRAMESIZE + 16);
Riku Voipio1d8b5122014-04-23 10:26:05 +03004827 __put_user(env->gpr[1], (target_ulong *)(uintptr_t) newsp);
Nathan Froydbcd49332009-05-12 19:13:18 -07004828
4829 if (err)
4830 goto sigsegv;
4831
4832 /* Set up registers for signal handler. */
4833 env->gpr[1] = newsp;
4834 env->gpr[3] = (target_ulong) signal;
4835 env->gpr[4] = (target_ulong) h2g(&rt_sf->info);
4836 env->gpr[5] = (target_ulong) h2g(&rt_sf->uc);
4837 env->gpr[6] = (target_ulong) h2g(rt_sf);
4838 env->nip = (target_ulong) ka->_sa_handler;
4839 /* Signal handlers are entered in big-endian mode. */
4840 env->msr &= ~MSR_LE;
4841
4842 unlock_user_struct(rt_sf, rt_sf_addr, 1);
4843 return;
4844
4845sigsegv:
4846 unlock_user_struct(rt_sf, rt_sf_addr, 1);
Blue Swirleeacee42012-06-03 16:35:32 +00004847 qemu_log("segfaulting from setup_rt_frame\n");
Riku Voipio66393fb2009-12-04 15:16:32 +02004848 force_sig(TARGET_SIGSEGV);
Nathan Froydbcd49332009-05-12 19:13:18 -07004849
4850}
4851
Andreas Färber05390242012-02-25 03:37:53 +01004852long do_sigreturn(CPUPPCState *env)
Nathan Froydbcd49332009-05-12 19:13:18 -07004853{
4854 struct target_sigcontext *sc = NULL;
4855 struct target_mcontext *sr = NULL;
Peter Maydellb04636f2013-07-29 12:00:31 +01004856 target_ulong sr_addr = 0, sc_addr;
Nathan Froydbcd49332009-05-12 19:13:18 -07004857 sigset_t blocked;
Anthony Liguoric227f092009-10-01 16:12:16 -05004858 target_sigset_t set;
Nathan Froydbcd49332009-05-12 19:13:18 -07004859
4860 sc_addr = env->gpr[1] + SIGNAL_FRAMESIZE;
4861 if (!lock_user_struct(VERIFY_READ, sc, sc_addr, 1))
4862 goto sigsegv;
4863
4864#if defined(TARGET_PPC64)
4865 set.sig[0] = sc->oldmask + ((long)(sc->_unused[3]) << 32);
4866#else
Riku Voipiof5f601a2014-04-23 13:00:17 +03004867 __get_user(set.sig[0], &sc->oldmask);
4868 __get_user(set.sig[1], &sc->_unused[3]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004869#endif
4870 target_to_host_sigset_internal(&blocked, &set);
Alex Barcelo1c275922014-03-14 14:36:55 +00004871 do_sigprocmask(SIG_SETMASK, &blocked, NULL);
Nathan Froydbcd49332009-05-12 19:13:18 -07004872
Riku Voipiof5f601a2014-04-23 13:00:17 +03004873 __get_user(sr_addr, &sc->regs);
Nathan Froydbcd49332009-05-12 19:13:18 -07004874 if (!lock_user_struct(VERIFY_READ, sr, sr_addr, 1))
4875 goto sigsegv;
4876 if (restore_user_regs(env, sr, 1))
4877 goto sigsegv;
4878
4879 unlock_user_struct(sr, sr_addr, 1);
4880 unlock_user_struct(sc, sc_addr, 1);
4881 return -TARGET_QEMU_ESIGRETURN;
4882
4883sigsegv:
4884 unlock_user_struct(sr, sr_addr, 1);
4885 unlock_user_struct(sc, sc_addr, 1);
Blue Swirleeacee42012-06-03 16:35:32 +00004886 qemu_log("segfaulting from do_sigreturn\n");
Riku Voipio66393fb2009-12-04 15:16:32 +02004887 force_sig(TARGET_SIGSEGV);
Nathan Froydbcd49332009-05-12 19:13:18 -07004888 return 0;
4889}
4890
4891/* See arch/powerpc/kernel/signal_32.c. */
Andreas Färber05390242012-02-25 03:37:53 +01004892static int do_setcontext(struct target_ucontext *ucp, CPUPPCState *env, int sig)
Nathan Froydbcd49332009-05-12 19:13:18 -07004893{
4894 struct target_mcontext *mcp;
4895 target_ulong mcp_addr;
4896 sigset_t blocked;
Anthony Liguoric227f092009-10-01 16:12:16 -05004897 target_sigset_t set;
Nathan Froydbcd49332009-05-12 19:13:18 -07004898
Aurelien Jarno60e99242010-03-29 02:12:51 +02004899 if (copy_from_user(&set, h2g(ucp) + offsetof(struct target_ucontext, tuc_sigmask),
Nathan Froydbcd49332009-05-12 19:13:18 -07004900 sizeof (set)))
4901 return 1;
4902
4903#if defined(TARGET_PPC64)
4904 fprintf (stderr, "do_setcontext: not implemented\n");
4905 return 0;
4906#else
Aurelien Jarno60e99242010-03-29 02:12:51 +02004907 if (__get_user(mcp_addr, &ucp->tuc_regs))
Nathan Froydbcd49332009-05-12 19:13:18 -07004908 return 1;
4909
4910 if (!lock_user_struct(VERIFY_READ, mcp, mcp_addr, 1))
4911 return 1;
4912
4913 target_to_host_sigset_internal(&blocked, &set);
Alex Barcelo1c275922014-03-14 14:36:55 +00004914 do_sigprocmask(SIG_SETMASK, &blocked, NULL);
Nathan Froydbcd49332009-05-12 19:13:18 -07004915 if (restore_user_regs(env, mcp, sig))
4916 goto sigsegv;
4917
4918 unlock_user_struct(mcp, mcp_addr, 1);
4919 return 0;
4920
4921sigsegv:
4922 unlock_user_struct(mcp, mcp_addr, 1);
4923 return 1;
4924#endif
4925}
4926
Andreas Färber05390242012-02-25 03:37:53 +01004927long do_rt_sigreturn(CPUPPCState *env)
Nathan Froydbcd49332009-05-12 19:13:18 -07004928{
4929 struct target_rt_sigframe *rt_sf = NULL;
4930 target_ulong rt_sf_addr;
4931
4932 rt_sf_addr = env->gpr[1] + SIGNAL_FRAMESIZE + 16;
4933 if (!lock_user_struct(VERIFY_READ, rt_sf, rt_sf_addr, 1))
4934 goto sigsegv;
4935
4936 if (do_setcontext(&rt_sf->uc, env, 1))
4937 goto sigsegv;
4938
4939 do_sigaltstack(rt_sf_addr
Aurelien Jarno60e99242010-03-29 02:12:51 +02004940 + offsetof(struct target_rt_sigframe, uc.tuc_stack),
Nathan Froydbcd49332009-05-12 19:13:18 -07004941 0, env->gpr[1]);
4942
4943 unlock_user_struct(rt_sf, rt_sf_addr, 1);
4944 return -TARGET_QEMU_ESIGRETURN;
4945
4946sigsegv:
4947 unlock_user_struct(rt_sf, rt_sf_addr, 1);
Blue Swirleeacee42012-06-03 16:35:32 +00004948 qemu_log("segfaulting from do_rt_sigreturn\n");
Riku Voipio66393fb2009-12-04 15:16:32 +02004949 force_sig(TARGET_SIGSEGV);
Nathan Froydbcd49332009-05-12 19:13:18 -07004950 return 0;
4951}
4952
Laurent Vivier492a8742009-08-03 16:12:17 +02004953#elif defined(TARGET_M68K)
4954
4955struct target_sigcontext {
4956 abi_ulong sc_mask;
4957 abi_ulong sc_usp;
4958 abi_ulong sc_d0;
4959 abi_ulong sc_d1;
4960 abi_ulong sc_a0;
4961 abi_ulong sc_a1;
4962 unsigned short sc_sr;
4963 abi_ulong sc_pc;
4964};
4965
4966struct target_sigframe
4967{
4968 abi_ulong pretcode;
4969 int sig;
4970 int code;
4971 abi_ulong psc;
4972 char retcode[8];
4973 abi_ulong extramask[TARGET_NSIG_WORDS-1];
4974 struct target_sigcontext sc;
4975};
Laurent Vivier71811552009-08-03 16:12:18 +02004976
Anthony Liguoric227f092009-10-01 16:12:16 -05004977typedef int target_greg_t;
Laurent Vivier71811552009-08-03 16:12:18 +02004978#define TARGET_NGREG 18
Anthony Liguoric227f092009-10-01 16:12:16 -05004979typedef target_greg_t target_gregset_t[TARGET_NGREG];
Laurent Vivier71811552009-08-03 16:12:18 +02004980
4981typedef struct target_fpregset {
4982 int f_fpcntl[3];
4983 int f_fpregs[8*3];
Anthony Liguoric227f092009-10-01 16:12:16 -05004984} target_fpregset_t;
Laurent Vivier71811552009-08-03 16:12:18 +02004985
4986struct target_mcontext {
4987 int version;
Anthony Liguoric227f092009-10-01 16:12:16 -05004988 target_gregset_t gregs;
4989 target_fpregset_t fpregs;
Laurent Vivier71811552009-08-03 16:12:18 +02004990};
4991
4992#define TARGET_MCONTEXT_VERSION 2
4993
4994struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02004995 abi_ulong tuc_flags;
4996 abi_ulong tuc_link;
4997 target_stack_t tuc_stack;
4998 struct target_mcontext tuc_mcontext;
4999 abi_long tuc_filler[80];
5000 target_sigset_t tuc_sigmask;
Laurent Vivier71811552009-08-03 16:12:18 +02005001};
5002
5003struct target_rt_sigframe
5004{
5005 abi_ulong pretcode;
5006 int sig;
5007 abi_ulong pinfo;
5008 abi_ulong puc;
5009 char retcode[8];
5010 struct target_siginfo info;
5011 struct target_ucontext uc;
5012};
Laurent Vivier492a8742009-08-03 16:12:17 +02005013
Riku Voipio41ecc722014-04-23 11:01:00 +03005014static void setup_sigcontext(struct target_sigcontext *sc, CPUM68KState *env,
5015 abi_ulong mask)
Laurent Vivier492a8742009-08-03 16:12:17 +02005016{
Riku Voipio1d8b5122014-04-23 10:26:05 +03005017 __put_user(mask, &sc->sc_mask);
5018 __put_user(env->aregs[7], &sc->sc_usp);
5019 __put_user(env->dregs[0], &sc->sc_d0);
5020 __put_user(env->dregs[1], &sc->sc_d1);
5021 __put_user(env->aregs[0], &sc->sc_a0);
5022 __put_user(env->aregs[1], &sc->sc_a1);
5023 __put_user(env->sr, &sc->sc_sr);
5024 __put_user(env->pc, &sc->sc_pc);
Laurent Vivier492a8742009-08-03 16:12:17 +02005025}
5026
Riku Voipio016d2e12014-04-23 11:19:48 +03005027static void
Andreas Färber05390242012-02-25 03:37:53 +01005028restore_sigcontext(CPUM68KState *env, struct target_sigcontext *sc, int *pd0)
Laurent Vivier492a8742009-08-03 16:12:17 +02005029{
Laurent Vivier492a8742009-08-03 16:12:17 +02005030 int temp;
5031
Riku Voipio1d8b5122014-04-23 10:26:05 +03005032 __get_user(env->aregs[7], &sc->sc_usp);
5033 __get_user(env->dregs[1], &sc->sc_d1);
5034 __get_user(env->aregs[0], &sc->sc_a0);
5035 __get_user(env->aregs[1], &sc->sc_a1);
5036 __get_user(env->pc, &sc->sc_pc);
5037 __get_user(temp, &sc->sc_sr);
Laurent Vivier492a8742009-08-03 16:12:17 +02005038 env->sr = (env->sr & 0xff00) | (temp & 0xff);
5039
5040 *pd0 = tswapl(sc->sc_d0);
Laurent Vivier492a8742009-08-03 16:12:17 +02005041}
5042
5043/*
5044 * Determine which stack to use..
5045 */
5046static inline abi_ulong
Andreas Färber05390242012-02-25 03:37:53 +01005047get_sigframe(struct target_sigaction *ka, CPUM68KState *regs,
5048 size_t frame_size)
Laurent Vivier492a8742009-08-03 16:12:17 +02005049{
5050 unsigned long sp;
5051
5052 sp = regs->aregs[7];
5053
5054 /* This is the X/Open sanctioned signal stack switching. */
5055 if ((ka->sa_flags & TARGET_SA_ONSTACK) && (sas_ss_flags (sp) == 0)) {
5056 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
5057 }
5058
5059 return ((sp - frame_size) & -8UL);
5060}
5061
5062static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01005063 target_sigset_t *set, CPUM68KState *env)
Laurent Vivier492a8742009-08-03 16:12:17 +02005064{
5065 struct target_sigframe *frame;
5066 abi_ulong frame_addr;
5067 abi_ulong retcode_addr;
5068 abi_ulong sc_addr;
5069 int err = 0;
5070 int i;
5071
5072 frame_addr = get_sigframe(ka, env, sizeof *frame);
5073 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
5074 goto give_sigsegv;
5075
Riku Voipio1d8b5122014-04-23 10:26:05 +03005076 __put_user(sig, &frame->sig);
Laurent Vivier492a8742009-08-03 16:12:17 +02005077
5078 sc_addr = frame_addr + offsetof(struct target_sigframe, sc);
Riku Voipio1d8b5122014-04-23 10:26:05 +03005079 __put_user(sc_addr, &frame->psc);
Laurent Vivier492a8742009-08-03 16:12:17 +02005080
Riku Voipio41ecc722014-04-23 11:01:00 +03005081 setup_sigcontext(&frame->sc, env, set->sig[0]);
Laurent Vivier492a8742009-08-03 16:12:17 +02005082
5083 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
5084 if (__put_user(set->sig[i], &frame->extramask[i - 1]))
5085 goto give_sigsegv;
5086 }
5087
5088 /* Set up to return from userspace. */
5089
5090 retcode_addr = frame_addr + offsetof(struct target_sigframe, retcode);
Riku Voipio1d8b5122014-04-23 10:26:05 +03005091 __put_user(retcode_addr, &frame->pretcode);
Laurent Vivier492a8742009-08-03 16:12:17 +02005092
5093 /* moveq #,d0; trap #0 */
5094
Riku Voipio1d8b5122014-04-23 10:26:05 +03005095 __put_user(0x70004e40 + (TARGET_NR_sigreturn << 16),
Laurent Vivier492a8742009-08-03 16:12:17 +02005096 (long *)(frame->retcode));
5097
5098 if (err)
5099 goto give_sigsegv;
5100
5101 /* Set up to return from userspace */
5102
5103 env->aregs[7] = frame_addr;
5104 env->pc = ka->_sa_handler;
5105
5106 unlock_user_struct(frame, frame_addr, 1);
5107 return;
5108
5109give_sigsegv:
5110 unlock_user_struct(frame, frame_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02005111 force_sig(TARGET_SIGSEGV);
Laurent Vivier492a8742009-08-03 16:12:17 +02005112}
5113
Laurent Vivier71811552009-08-03 16:12:18 +02005114static inline int target_rt_setup_ucontext(struct target_ucontext *uc,
Andreas Färber05390242012-02-25 03:37:53 +01005115 CPUM68KState *env)
Laurent Vivier71811552009-08-03 16:12:18 +02005116{
Aurelien Jarno60e99242010-03-29 02:12:51 +02005117 target_greg_t *gregs = uc->tuc_mcontext.gregs;
Laurent Vivier71811552009-08-03 16:12:18 +02005118
Riku Voipio1d8b5122014-04-23 10:26:05 +03005119 __put_user(TARGET_MCONTEXT_VERSION, &uc->tuc_mcontext.version);
5120 __put_user(env->dregs[0], &gregs[0]);
5121 __put_user(env->dregs[1], &gregs[1]);
5122 __put_user(env->dregs[2], &gregs[2]);
5123 __put_user(env->dregs[3], &gregs[3]);
5124 __put_user(env->dregs[4], &gregs[4]);
5125 __put_user(env->dregs[5], &gregs[5]);
5126 __put_user(env->dregs[6], &gregs[6]);
5127 __put_user(env->dregs[7], &gregs[7]);
5128 __put_user(env->aregs[0], &gregs[8]);
5129 __put_user(env->aregs[1], &gregs[9]);
5130 __put_user(env->aregs[2], &gregs[10]);
5131 __put_user(env->aregs[3], &gregs[11]);
5132 __put_user(env->aregs[4], &gregs[12]);
5133 __put_user(env->aregs[5], &gregs[13]);
5134 __put_user(env->aregs[6], &gregs[14]);
5135 __put_user(env->aregs[7], &gregs[15]);
5136 __put_user(env->pc, &gregs[16]);
5137 __put_user(env->sr, &gregs[17]);
Laurent Vivier71811552009-08-03 16:12:18 +02005138
Riku Voipio1d8b5122014-04-23 10:26:05 +03005139 return 0;
Laurent Vivier71811552009-08-03 16:12:18 +02005140}
5141
Andreas Färber05390242012-02-25 03:37:53 +01005142static inline int target_rt_restore_ucontext(CPUM68KState *env,
Laurent Vivier71811552009-08-03 16:12:18 +02005143 struct target_ucontext *uc,
5144 int *pd0)
5145{
5146 int temp;
Aurelien Jarno60e99242010-03-29 02:12:51 +02005147 target_greg_t *gregs = uc->tuc_mcontext.gregs;
Laurent Vivier71811552009-08-03 16:12:18 +02005148
Riku Voipio1d8b5122014-04-23 10:26:05 +03005149 __get_user(temp, &uc->tuc_mcontext.version);
Laurent Vivier71811552009-08-03 16:12:18 +02005150 if (temp != TARGET_MCONTEXT_VERSION)
5151 goto badframe;
5152
5153 /* restore passed registers */
Riku Voipio1d8b5122014-04-23 10:26:05 +03005154 __get_user(env->dregs[0], &gregs[0]);
5155 __get_user(env->dregs[1], &gregs[1]);
5156 __get_user(env->dregs[2], &gregs[2]);
5157 __get_user(env->dregs[3], &gregs[3]);
5158 __get_user(env->dregs[4], &gregs[4]);
5159 __get_user(env->dregs[5], &gregs[5]);
5160 __get_user(env->dregs[6], &gregs[6]);
5161 __get_user(env->dregs[7], &gregs[7]);
5162 __get_user(env->aregs[0], &gregs[8]);
5163 __get_user(env->aregs[1], &gregs[9]);
5164 __get_user(env->aregs[2], &gregs[10]);
5165 __get_user(env->aregs[3], &gregs[11]);
5166 __get_user(env->aregs[4], &gregs[12]);
5167 __get_user(env->aregs[5], &gregs[13]);
5168 __get_user(env->aregs[6], &gregs[14]);
5169 __get_user(env->aregs[7], &gregs[15]);
5170 __get_user(env->pc, &gregs[16]);
5171 __get_user(temp, &gregs[17]);
Laurent Vivier71811552009-08-03 16:12:18 +02005172 env->sr = (env->sr & 0xff00) | (temp & 0xff);
5173
5174 *pd0 = env->dregs[0];
Riku Voipio1d8b5122014-04-23 10:26:05 +03005175 return 0;
Laurent Vivier71811552009-08-03 16:12:18 +02005176
5177badframe:
5178 return 1;
5179}
5180
Laurent Vivier492a8742009-08-03 16:12:17 +02005181static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05005182 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01005183 target_sigset_t *set, CPUM68KState *env)
Laurent Vivier492a8742009-08-03 16:12:17 +02005184{
Laurent Vivier71811552009-08-03 16:12:18 +02005185 struct target_rt_sigframe *frame;
5186 abi_ulong frame_addr;
5187 abi_ulong retcode_addr;
5188 abi_ulong info_addr;
5189 abi_ulong uc_addr;
5190 int err = 0;
5191 int i;
5192
5193 frame_addr = get_sigframe(ka, env, sizeof *frame);
5194 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
5195 goto give_sigsegv;
5196
Riku Voipio1d8b5122014-04-23 10:26:05 +03005197 __put_user(sig, &frame->sig);
Laurent Vivier71811552009-08-03 16:12:18 +02005198
5199 info_addr = frame_addr + offsetof(struct target_rt_sigframe, info);
Riku Voipio1d8b5122014-04-23 10:26:05 +03005200 __put_user(info_addr, &frame->pinfo);
Laurent Vivier71811552009-08-03 16:12:18 +02005201
5202 uc_addr = frame_addr + offsetof(struct target_rt_sigframe, uc);
Riku Voipio1d8b5122014-04-23 10:26:05 +03005203 __put_user(uc_addr, &frame->puc);
Laurent Vivier71811552009-08-03 16:12:18 +02005204
Riku Voipiob0fd8d12014-04-23 10:46:13 +03005205 copy_siginfo_to_user(&frame->info, info);
Laurent Vivier71811552009-08-03 16:12:18 +02005206
5207 /* Create the ucontext */
5208
Riku Voipio1d8b5122014-04-23 10:26:05 +03005209 __put_user(0, &frame->uc.tuc_flags);
5210 __put_user(0, &frame->uc.tuc_link);
5211 __put_user(target_sigaltstack_used.ss_sp,
5212 &frame->uc.tuc_stack.ss_sp);
5213 __put_user(sas_ss_flags(env->aregs[7]),
5214 &frame->uc.tuc_stack.ss_flags);
5215 __put_user(target_sigaltstack_used.ss_size,
5216 &frame->uc.tuc_stack.ss_size);
Laurent Vivier71811552009-08-03 16:12:18 +02005217 err |= target_rt_setup_ucontext(&frame->uc, env);
5218
5219 if (err)
5220 goto give_sigsegv;
5221
5222 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
Aurelien Jarno60e99242010-03-29 02:12:51 +02005223 if (__put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]))
Laurent Vivier71811552009-08-03 16:12:18 +02005224 goto give_sigsegv;
5225 }
5226
5227 /* Set up to return from userspace. */
5228
5229 retcode_addr = frame_addr + offsetof(struct target_sigframe, retcode);
Riku Voipio1d8b5122014-04-23 10:26:05 +03005230 __put_user(retcode_addr, &frame->pretcode);
Laurent Vivier71811552009-08-03 16:12:18 +02005231
5232 /* moveq #,d0; notb d0; trap #0 */
5233
Riku Voipio1d8b5122014-04-23 10:26:05 +03005234 __put_user(0x70004600 + ((TARGET_NR_rt_sigreturn ^ 0xff) << 16),
5235 (long *)(frame->retcode + 0));
5236 __put_user(0x4e40, (short *)(frame->retcode + 4));
Laurent Vivier71811552009-08-03 16:12:18 +02005237
5238 if (err)
5239 goto give_sigsegv;
5240
5241 /* Set up to return from userspace */
5242
5243 env->aregs[7] = frame_addr;
5244 env->pc = ka->_sa_handler;
5245
5246 unlock_user_struct(frame, frame_addr, 1);
5247 return;
5248
5249give_sigsegv:
5250 unlock_user_struct(frame, frame_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02005251 force_sig(TARGET_SIGSEGV);
Laurent Vivier492a8742009-08-03 16:12:17 +02005252}
5253
Andreas Färber05390242012-02-25 03:37:53 +01005254long do_sigreturn(CPUM68KState *env)
Laurent Vivier492a8742009-08-03 16:12:17 +02005255{
5256 struct target_sigframe *frame;
5257 abi_ulong frame_addr = env->aregs[7] - 4;
Anthony Liguoric227f092009-10-01 16:12:16 -05005258 target_sigset_t target_set;
Laurent Vivier492a8742009-08-03 16:12:17 +02005259 sigset_t set;
5260 int d0, i;
5261
5262 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
5263 goto badframe;
5264
5265 /* set blocked signals */
5266
Riku Voipiof5f601a2014-04-23 13:00:17 +03005267 __get_user(target_set.sig[0], &frame->sc.sc_mask);
Laurent Vivier492a8742009-08-03 16:12:17 +02005268
5269 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
Riku Voipiof5f601a2014-04-23 13:00:17 +03005270 __get_user(target_set.sig[i], &frame->extramask[i - 1]);
Laurent Vivier492a8742009-08-03 16:12:17 +02005271 }
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 Vivier492a8742009-08-03 16:12:17 +02005275
5276 /* restore registers */
5277
Riku Voipio016d2e12014-04-23 11:19:48 +03005278 restore_sigcontext(env, &frame->sc, &d0);
Laurent Vivier492a8742009-08-03 16:12:17 +02005279
5280 unlock_user_struct(frame, frame_addr, 0);
5281 return d0;
5282
5283badframe:
Laurent Vivier492a8742009-08-03 16:12:17 +02005284 force_sig(TARGET_SIGSEGV);
5285 return 0;
5286}
5287
Andreas Färber05390242012-02-25 03:37:53 +01005288long do_rt_sigreturn(CPUM68KState *env)
Laurent Vivier492a8742009-08-03 16:12:17 +02005289{
Laurent Vivier71811552009-08-03 16:12:18 +02005290 struct target_rt_sigframe *frame;
5291 abi_ulong frame_addr = env->aregs[7] - 4;
Anthony Liguoric227f092009-10-01 16:12:16 -05005292 target_sigset_t target_set;
Laurent Vivier71811552009-08-03 16:12:18 +02005293 sigset_t set;
5294 int d0;
5295
5296 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
5297 goto badframe;
5298
5299 target_to_host_sigset_internal(&set, &target_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00005300 do_sigprocmask(SIG_SETMASK, &set, NULL);
Laurent Vivier71811552009-08-03 16:12:18 +02005301
5302 /* restore registers */
5303
5304 if (target_rt_restore_ucontext(env, &frame->uc, &d0))
5305 goto badframe;
5306
5307 if (do_sigaltstack(frame_addr +
Aurelien Jarno60e99242010-03-29 02:12:51 +02005308 offsetof(struct target_rt_sigframe, uc.tuc_stack),
Laurent Vivier71811552009-08-03 16:12:18 +02005309 0, get_sp_from_cpustate(env)) == -EFAULT)
5310 goto badframe;
5311
5312 unlock_user_struct(frame, frame_addr, 0);
5313 return d0;
5314
5315badframe:
5316 unlock_user_struct(frame, frame_addr, 0);
5317 force_sig(TARGET_SIGSEGV);
5318 return 0;
Laurent Vivier492a8742009-08-03 16:12:17 +02005319}
5320
Richard Henderson6049f4f2009-12-27 18:30:03 -08005321#elif defined(TARGET_ALPHA)
5322
5323struct target_sigcontext {
5324 abi_long sc_onstack;
5325 abi_long sc_mask;
5326 abi_long sc_pc;
5327 abi_long sc_ps;
5328 abi_long sc_regs[32];
5329 abi_long sc_ownedfp;
5330 abi_long sc_fpregs[32];
5331 abi_ulong sc_fpcr;
5332 abi_ulong sc_fp_control;
5333 abi_ulong sc_reserved1;
5334 abi_ulong sc_reserved2;
5335 abi_ulong sc_ssize;
5336 abi_ulong sc_sbase;
5337 abi_ulong sc_traparg_a0;
5338 abi_ulong sc_traparg_a1;
5339 abi_ulong sc_traparg_a2;
5340 abi_ulong sc_fp_trap_pc;
5341 abi_ulong sc_fp_trigger_sum;
5342 abi_ulong sc_fp_trigger_inst;
5343};
5344
5345struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02005346 abi_ulong tuc_flags;
5347 abi_ulong tuc_link;
5348 abi_ulong tuc_osf_sigmask;
5349 target_stack_t tuc_stack;
5350 struct target_sigcontext tuc_mcontext;
5351 target_sigset_t tuc_sigmask;
Richard Henderson6049f4f2009-12-27 18:30:03 -08005352};
5353
5354struct target_sigframe {
5355 struct target_sigcontext sc;
5356 unsigned int retcode[3];
5357};
5358
5359struct target_rt_sigframe {
5360 target_siginfo_t info;
5361 struct target_ucontext uc;
5362 unsigned int retcode[3];
5363};
5364
5365#define INSN_MOV_R30_R16 0x47fe0410
5366#define INSN_LDI_R0 0x201f0000
5367#define INSN_CALLSYS 0x00000083
5368
Riku Voipio41ecc722014-04-23 11:01:00 +03005369static void setup_sigcontext(struct target_sigcontext *sc, CPUAlphaState *env,
Richard Henderson6049f4f2009-12-27 18:30:03 -08005370 abi_ulong frame_addr, target_sigset_t *set)
5371{
Riku Voipio41ecc722014-04-23 11:01:00 +03005372 int i;
Richard Henderson6049f4f2009-12-27 18:30:03 -08005373
Riku Voipio1d8b5122014-04-23 10:26:05 +03005374 __put_user(on_sig_stack(frame_addr), &sc->sc_onstack);
5375 __put_user(set->sig[0], &sc->sc_mask);
5376 __put_user(env->pc, &sc->sc_pc);
5377 __put_user(8, &sc->sc_ps);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005378
5379 for (i = 0; i < 31; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03005380 __put_user(env->ir[i], &sc->sc_regs[i]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005381 }
Riku Voipio1d8b5122014-04-23 10:26:05 +03005382 __put_user(0, &sc->sc_regs[31]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005383
5384 for (i = 0; i < 31; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03005385 __put_user(env->fir[i], &sc->sc_fpregs[i]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005386 }
Riku Voipio1d8b5122014-04-23 10:26:05 +03005387 __put_user(0, &sc->sc_fpregs[31]);
5388 __put_user(cpu_alpha_load_fpcr(env), &sc->sc_fpcr);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005389
Riku Voipio1d8b5122014-04-23 10:26:05 +03005390 __put_user(0, &sc->sc_traparg_a0); /* FIXME */
5391 __put_user(0, &sc->sc_traparg_a1); /* FIXME */
5392 __put_user(0, &sc->sc_traparg_a2); /* FIXME */
Richard Henderson6049f4f2009-12-27 18:30:03 -08005393}
5394
Riku Voipio016d2e12014-04-23 11:19:48 +03005395static void restore_sigcontext(CPUAlphaState *env,
Andreas Färber05390242012-02-25 03:37:53 +01005396 struct target_sigcontext *sc)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005397{
5398 uint64_t fpcr;
Riku Voipio016d2e12014-04-23 11:19:48 +03005399 int i;
Richard Henderson6049f4f2009-12-27 18:30:03 -08005400
Riku Voipio1d8b5122014-04-23 10:26:05 +03005401 __get_user(env->pc, &sc->sc_pc);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005402
5403 for (i = 0; i < 31; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03005404 __get_user(env->ir[i], &sc->sc_regs[i]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005405 }
5406 for (i = 0; i < 31; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03005407 __get_user(env->fir[i], &sc->sc_fpregs[i]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005408 }
5409
Riku Voipio1d8b5122014-04-23 10:26:05 +03005410 __get_user(fpcr, &sc->sc_fpcr);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005411 cpu_alpha_store_fpcr(env, fpcr);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005412}
5413
5414static inline abi_ulong get_sigframe(struct target_sigaction *sa,
Andreas Färber05390242012-02-25 03:37:53 +01005415 CPUAlphaState *env,
5416 unsigned long framesize)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005417{
5418 abi_ulong sp = env->ir[IR_SP];
5419
5420 /* This is the X/Open sanctioned signal stack switching. */
5421 if ((sa->sa_flags & TARGET_SA_ONSTACK) != 0 && !sas_ss_flags(sp)) {
5422 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
5423 }
5424 return (sp - framesize) & -32;
5425}
5426
5427static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01005428 target_sigset_t *set, CPUAlphaState *env)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005429{
5430 abi_ulong frame_addr, r26;
5431 struct target_sigframe *frame;
5432 int err = 0;
5433
5434 frame_addr = get_sigframe(ka, env, sizeof(*frame));
5435 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
5436 goto give_sigsegv;
5437 }
5438
Riku Voipio41ecc722014-04-23 11:01:00 +03005439 setup_sigcontext(&frame->sc, env, frame_addr, set);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005440
5441 if (ka->sa_restorer) {
5442 r26 = ka->sa_restorer;
5443 } else {
Riku Voipio1d8b5122014-04-23 10:26:05 +03005444 __put_user(INSN_MOV_R30_R16, &frame->retcode[0]);
5445 __put_user(INSN_LDI_R0 + TARGET_NR_sigreturn,
5446 &frame->retcode[1]);
5447 __put_user(INSN_CALLSYS, &frame->retcode[2]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005448 /* imb() */
5449 r26 = frame_addr;
5450 }
5451
5452 unlock_user_struct(frame, frame_addr, 1);
5453
5454 if (err) {
5455 give_sigsegv:
5456 if (sig == TARGET_SIGSEGV) {
5457 ka->_sa_handler = TARGET_SIG_DFL;
5458 }
5459 force_sig(TARGET_SIGSEGV);
5460 }
5461
5462 env->ir[IR_RA] = r26;
5463 env->ir[IR_PV] = env->pc = ka->_sa_handler;
5464 env->ir[IR_A0] = sig;
5465 env->ir[IR_A1] = 0;
5466 env->ir[IR_A2] = frame_addr + offsetof(struct target_sigframe, sc);
5467 env->ir[IR_SP] = frame_addr;
5468}
5469
5470static void setup_rt_frame(int sig, struct target_sigaction *ka,
5471 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01005472 target_sigset_t *set, CPUAlphaState *env)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005473{
5474 abi_ulong frame_addr, r26;
5475 struct target_rt_sigframe *frame;
5476 int i, err = 0;
5477
5478 frame_addr = get_sigframe(ka, env, sizeof(*frame));
5479 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
5480 goto give_sigsegv;
5481 }
5482
Riku Voipiob0fd8d12014-04-23 10:46:13 +03005483 copy_siginfo_to_user(&frame->info, info);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005484
Riku Voipio1d8b5122014-04-23 10:26:05 +03005485 __put_user(0, &frame->uc.tuc_flags);
5486 __put_user(0, &frame->uc.tuc_link);
5487 __put_user(set->sig[0], &frame->uc.tuc_osf_sigmask);
5488 __put_user(target_sigaltstack_used.ss_sp,
5489 &frame->uc.tuc_stack.ss_sp);
5490 __put_user(sas_ss_flags(env->ir[IR_SP]),
5491 &frame->uc.tuc_stack.ss_flags);
5492 __put_user(target_sigaltstack_used.ss_size,
5493 &frame->uc.tuc_stack.ss_size);
Riku Voipio41ecc722014-04-23 11:01:00 +03005494 setup_sigcontext(&frame->uc.tuc_mcontext, env, frame_addr, set);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005495 for (i = 0; i < TARGET_NSIG_WORDS; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03005496 __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005497 }
5498
5499 if (ka->sa_restorer) {
5500 r26 = ka->sa_restorer;
5501 } else {
Riku Voipio1d8b5122014-04-23 10:26:05 +03005502 __put_user(INSN_MOV_R30_R16, &frame->retcode[0]);
5503 __put_user(INSN_LDI_R0 + TARGET_NR_rt_sigreturn,
5504 &frame->retcode[1]);
5505 __put_user(INSN_CALLSYS, &frame->retcode[2]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005506 /* imb(); */
5507 r26 = frame_addr;
5508 }
5509
5510 if (err) {
5511 give_sigsegv:
5512 if (sig == TARGET_SIGSEGV) {
5513 ka->_sa_handler = TARGET_SIG_DFL;
5514 }
5515 force_sig(TARGET_SIGSEGV);
5516 }
5517
5518 env->ir[IR_RA] = r26;
5519 env->ir[IR_PV] = env->pc = ka->_sa_handler;
5520 env->ir[IR_A0] = sig;
5521 env->ir[IR_A1] = frame_addr + offsetof(struct target_rt_sigframe, info);
5522 env->ir[IR_A2] = frame_addr + offsetof(struct target_rt_sigframe, uc);
5523 env->ir[IR_SP] = frame_addr;
5524}
5525
Andreas Färber05390242012-02-25 03:37:53 +01005526long do_sigreturn(CPUAlphaState *env)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005527{
5528 struct target_sigcontext *sc;
5529 abi_ulong sc_addr = env->ir[IR_A0];
5530 target_sigset_t target_set;
5531 sigset_t set;
5532
5533 if (!lock_user_struct(VERIFY_READ, sc, sc_addr, 1)) {
5534 goto badframe;
5535 }
5536
5537 target_sigemptyset(&target_set);
Riku Voipiof5f601a2014-04-23 13:00:17 +03005538 __get_user(target_set.sig[0], &sc->sc_mask);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005539
5540 target_to_host_sigset_internal(&set, &target_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00005541 do_sigprocmask(SIG_SETMASK, &set, NULL);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005542
Riku Voipio016d2e12014-04-23 11:19:48 +03005543 restore_sigcontext(env, sc);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005544 unlock_user_struct(sc, sc_addr, 0);
5545 return env->ir[IR_V0];
5546
5547 badframe:
Richard Henderson6049f4f2009-12-27 18:30:03 -08005548 force_sig(TARGET_SIGSEGV);
5549}
5550
Andreas Färber05390242012-02-25 03:37:53 +01005551long do_rt_sigreturn(CPUAlphaState *env)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005552{
5553 abi_ulong frame_addr = env->ir[IR_A0];
5554 struct target_rt_sigframe *frame;
5555 sigset_t set;
5556
5557 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
5558 goto badframe;
5559 }
Aurelien Jarno60e99242010-03-29 02:12:51 +02005560 target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
Alex Barcelo1c275922014-03-14 14:36:55 +00005561 do_sigprocmask(SIG_SETMASK, &set, NULL);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005562
Riku Voipio016d2e12014-04-23 11:19:48 +03005563 restore_sigcontext(env, &frame->uc.tuc_mcontext);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005564 if (do_sigaltstack(frame_addr + offsetof(struct target_rt_sigframe,
Aurelien Jarno60e99242010-03-29 02:12:51 +02005565 uc.tuc_stack),
Richard Henderson6049f4f2009-12-27 18:30:03 -08005566 0, env->ir[IR_SP]) == -EFAULT) {
5567 goto badframe;
5568 }
5569
5570 unlock_user_struct(frame, frame_addr, 0);
5571 return env->ir[IR_V0];
5572
5573
5574 badframe:
5575 unlock_user_struct(frame, frame_addr, 0);
5576 force_sig(TARGET_SIGSEGV);
5577}
5578
bellardb346ff42003-06-15 20:05:50 +00005579#else
5580
pbrook624f7972008-05-31 16:11:38 +00005581static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber9349b4f2012-03-14 01:38:32 +01005582 target_sigset_t *set, CPUArchState *env)
bellardb346ff42003-06-15 20:05:50 +00005583{
5584 fprintf(stderr, "setup_frame: not implemented\n");
5585}
5586
pbrook624f7972008-05-31 16:11:38 +00005587static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05005588 target_siginfo_t *info,
Andreas Färber9349b4f2012-03-14 01:38:32 +01005589 target_sigset_t *set, CPUArchState *env)
bellardb346ff42003-06-15 20:05:50 +00005590{
5591 fprintf(stderr, "setup_rt_frame: not implemented\n");
5592}
5593
Andreas Färber9349b4f2012-03-14 01:38:32 +01005594long do_sigreturn(CPUArchState *env)
bellardb346ff42003-06-15 20:05:50 +00005595{
5596 fprintf(stderr, "do_sigreturn: not implemented\n");
bellardf8b0aa22007-11-11 23:03:42 +00005597 return -TARGET_ENOSYS;
bellardb346ff42003-06-15 20:05:50 +00005598}
5599
Andreas Färber9349b4f2012-03-14 01:38:32 +01005600long do_rt_sigreturn(CPUArchState *env)
bellardb346ff42003-06-15 20:05:50 +00005601{
5602 fprintf(stderr, "do_rt_sigreturn: not implemented\n");
bellardf8b0aa22007-11-11 23:03:42 +00005603 return -TARGET_ENOSYS;
bellardb346ff42003-06-15 20:05:50 +00005604}
5605
bellard66fb9762003-03-23 01:06:05 +00005606#endif
5607
Andreas Färber9349b4f2012-03-14 01:38:32 +01005608void process_pending_signals(CPUArchState *cpu_env)
bellard66fb9762003-03-23 01:06:05 +00005609{
Andreas Färberdb6b81d2013-06-27 19:49:31 +02005610 CPUState *cpu = ENV_GET_CPU(cpu_env);
bellard66fb9762003-03-23 01:06:05 +00005611 int sig;
blueswir1992f48a2007-10-14 16:27:31 +00005612 abi_ulong handler;
bellard9de5e442003-03-23 16:49:39 +00005613 sigset_t set, old_set;
Anthony Liguoric227f092009-10-01 16:12:16 -05005614 target_sigset_t target_old_set;
pbrook624f7972008-05-31 16:11:38 +00005615 struct emulated_sigtable *k;
5616 struct target_sigaction *sa;
bellard66fb9762003-03-23 01:06:05 +00005617 struct sigqueue *q;
Andreas Färber0429a972013-08-26 18:14:44 +02005618 TaskState *ts = cpu->opaque;
ths3b46e622007-09-17 08:09:54 +00005619
pbrook624f7972008-05-31 16:11:38 +00005620 if (!ts->signal_pending)
bellard31e31b82003-02-18 22:55:36 +00005621 return;
5622
pbrook624f7972008-05-31 16:11:38 +00005623 /* FIXME: This is not threadsafe. */
5624 k = ts->sigtab;
bellard66fb9762003-03-23 01:06:05 +00005625 for(sig = 1; sig <= TARGET_NSIG; sig++) {
5626 if (k->pending)
bellard31e31b82003-02-18 22:55:36 +00005627 goto handle_signal;
bellard66fb9762003-03-23 01:06:05 +00005628 k++;
bellard31e31b82003-02-18 22:55:36 +00005629 }
5630 /* if no signal is pending, just return */
pbrook624f7972008-05-31 16:11:38 +00005631 ts->signal_pending = 0;
bellard31e31b82003-02-18 22:55:36 +00005632 return;
bellard66fb9762003-03-23 01:06:05 +00005633
bellard31e31b82003-02-18 22:55:36 +00005634 handle_signal:
bellard66fb9762003-03-23 01:06:05 +00005635#ifdef DEBUG_SIGNAL
bellardbc8a22c2003-03-30 21:02:40 +00005636 fprintf(stderr, "qemu: process signal %d\n", sig);
bellard66fb9762003-03-23 01:06:05 +00005637#endif
5638 /* dequeue signal */
5639 q = k->first;
5640 k->first = q->next;
5641 if (!k->first)
5642 k->pending = 0;
ths3b46e622007-09-17 08:09:54 +00005643
Andreas Färberdb6b81d2013-06-27 19:49:31 +02005644 sig = gdb_handlesig(cpu, sig);
bellard1fddef42005-04-17 19:16:13 +00005645 if (!sig) {
aurel32ca587a82008-12-18 22:44:13 +00005646 sa = NULL;
5647 handler = TARGET_SIG_IGN;
5648 } else {
5649 sa = &sigact_table[sig - 1];
5650 handler = sa->_sa_handler;
bellard1fddef42005-04-17 19:16:13 +00005651 }
bellard66fb9762003-03-23 01:06:05 +00005652
Peter Maydella7ec0f92014-03-14 14:36:56 +00005653 if (ts->sigsegv_blocked && sig == TARGET_SIGSEGV) {
5654 /* Guest has blocked SIGSEGV but we got one anyway. Assume this
5655 * is a forced SIGSEGV (ie one the kernel handles via force_sig_info
5656 * because it got a real MMU fault), and treat as if default handler.
5657 */
5658 handler = TARGET_SIG_DFL;
5659 }
5660
bellard66fb9762003-03-23 01:06:05 +00005661 if (handler == TARGET_SIG_DFL) {
aurel32ca587a82008-12-18 22:44:13 +00005662 /* default handler : ignore some signal. The other are job control or fatal */
5663 if (sig == TARGET_SIGTSTP || sig == TARGET_SIGTTIN || sig == TARGET_SIGTTOU) {
5664 kill(getpid(),SIGSTOP);
5665 } else if (sig != TARGET_SIGCHLD &&
5666 sig != TARGET_SIGURG &&
5667 sig != TARGET_SIGWINCH &&
5668 sig != TARGET_SIGCONT) {
bellard66fb9762003-03-23 01:06:05 +00005669 force_sig(sig);
5670 }
5671 } else if (handler == TARGET_SIG_IGN) {
5672 /* ignore sig */
5673 } else if (handler == TARGET_SIG_ERR) {
5674 force_sig(sig);
5675 } else {
bellard9de5e442003-03-23 16:49:39 +00005676 /* compute the blocked signals during the handler execution */
pbrook624f7972008-05-31 16:11:38 +00005677 target_to_host_sigset(&set, &sa->sa_mask);
bellard9de5e442003-03-23 16:49:39 +00005678 /* SA_NODEFER indicates that the current signal should not be
5679 blocked during the handler */
pbrook624f7972008-05-31 16:11:38 +00005680 if (!(sa->sa_flags & TARGET_SA_NODEFER))
bellard9de5e442003-03-23 16:49:39 +00005681 sigaddset(&set, target_to_host_signal(sig));
ths3b46e622007-09-17 08:09:54 +00005682
bellard9de5e442003-03-23 16:49:39 +00005683 /* block signals in the handler using Linux */
Alex Barcelo1c275922014-03-14 14:36:55 +00005684 do_sigprocmask(SIG_BLOCK, &set, &old_set);
bellard9de5e442003-03-23 16:49:39 +00005685 /* save the previous blocked signal state to restore it at the
5686 end of the signal execution (see do_sigreturn) */
bellard92319442004-06-19 16:58:13 +00005687 host_to_target_sigset_internal(&target_old_set, &old_set);
bellard9de5e442003-03-23 16:49:39 +00005688
bellardbc8a22c2003-03-30 21:02:40 +00005689 /* if the CPU is in VM86 mode, we restore the 32 bit values */
j_mayer84409dd2007-04-06 08:56:50 +00005690#if defined(TARGET_I386) && !defined(TARGET_X86_64)
bellardbc8a22c2003-03-30 21:02:40 +00005691 {
5692 CPUX86State *env = cpu_env;
5693 if (env->eflags & VM_MASK)
5694 save_v86_state(env);
5695 }
5696#endif
bellard9de5e442003-03-23 16:49:39 +00005697 /* prepare the stack frame of the virtual CPU */
Richard Hendersonff970902013-02-10 10:30:42 -08005698#if defined(TARGET_ABI_MIPSN32) || defined(TARGET_ABI_MIPSN64)
5699 /* These targets do not have traditional signals. */
5700 setup_rt_frame(sig, sa, &q->info, &target_old_set, cpu_env);
5701#else
pbrook624f7972008-05-31 16:11:38 +00005702 if (sa->sa_flags & TARGET_SA_SIGINFO)
5703 setup_rt_frame(sig, sa, &q->info, &target_old_set, cpu_env);
bellard66fb9762003-03-23 01:06:05 +00005704 else
pbrook624f7972008-05-31 16:11:38 +00005705 setup_frame(sig, sa, &target_old_set, cpu_env);
Richard Hendersonff970902013-02-10 10:30:42 -08005706#endif
pbrook624f7972008-05-31 16:11:38 +00005707 if (sa->sa_flags & TARGET_SA_RESETHAND)
5708 sa->_sa_handler = TARGET_SIG_DFL;
bellard31e31b82003-02-18 22:55:36 +00005709 }
bellard66fb9762003-03-23 01:06:05 +00005710 if (q != &k->info)
pbrook624f7972008-05-31 16:11:38 +00005711 free_sigqueue(cpu_env, q);
bellard31e31b82003-02-18 22:55:36 +00005712}