blob: cf283a8b466574b05e37661d8b5c60a06e3042a3 [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;
bellard579a97f2007-11-11 14:26:47 +0000622 if (!lock_user_struct(VERIFY_READ, uss, uss_addr, 1)
thsa04e1342007-09-27 13:57:58 +0000623 || __get_user(ss.ss_sp, &uss->ss_sp)
624 || __get_user(ss.ss_size, &uss->ss_size)
625 || __get_user(ss.ss_flags, &uss->ss_flags))
626 goto out;
bellard579a97f2007-11-11 14:26:47 +0000627 unlock_user_struct(uss, uss_addr, 0);
thsa04e1342007-09-27 13:57:58 +0000628
ths0da46a62007-10-20 20:23:07 +0000629 ret = -TARGET_EPERM;
thsa04e1342007-09-27 13:57:58 +0000630 if (on_sig_stack(sp))
631 goto out;
632
ths0da46a62007-10-20 20:23:07 +0000633 ret = -TARGET_EINVAL;
thsa04e1342007-09-27 13:57:58 +0000634 if (ss.ss_flags != TARGET_SS_DISABLE
635 && ss.ss_flags != TARGET_SS_ONSTACK
636 && ss.ss_flags != 0)
637 goto out;
638
639 if (ss.ss_flags == TARGET_SS_DISABLE) {
640 ss.ss_size = 0;
641 ss.ss_sp = 0;
642 } else {
ths0da46a62007-10-20 20:23:07 +0000643 ret = -TARGET_ENOMEM;
thsa04e1342007-09-27 13:57:58 +0000644 if (ss.ss_size < MINSIGSTKSZ)
645 goto out;
646 }
647
648 target_sigaltstack_used.ss_sp = ss.ss_sp;
649 target_sigaltstack_used.ss_size = ss.ss_size;
650 }
651
bellard579a97f2007-11-11 14:26:47 +0000652 if (uoss_addr) {
ths0da46a62007-10-20 20:23:07 +0000653 ret = -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +0000654 if (copy_to_user(uoss_addr, &oss, sizeof(oss)))
thsa04e1342007-09-27 13:57:58 +0000655 goto out;
thsa04e1342007-09-27 13:57:58 +0000656 }
657
658 ret = 0;
659out:
660 return ret;
661}
662
ths0da46a62007-10-20 20:23:07 +0000663/* do_sigaction() return host values and errnos */
bellard66fb9762003-03-23 01:06:05 +0000664int do_sigaction(int sig, const struct target_sigaction *act,
665 struct target_sigaction *oact)
bellard31e31b82003-02-18 22:55:36 +0000666{
pbrook624f7972008-05-31 16:11:38 +0000667 struct target_sigaction *k;
bellard773b93e2004-01-04 17:15:59 +0000668 struct sigaction act1;
669 int host_sig;
ths0da46a62007-10-20 20:23:07 +0000670 int ret = 0;
bellard31e31b82003-02-18 22:55:36 +0000671
ths2a913eb2008-11-27 15:46:25 +0000672 if (sig < 1 || sig > TARGET_NSIG || sig == TARGET_SIGKILL || sig == TARGET_SIGSTOP)
bellard66fb9762003-03-23 01:06:05 +0000673 return -EINVAL;
674 k = &sigact_table[sig - 1];
bellard773b93e2004-01-04 17:15:59 +0000675#if defined(DEBUG_SIGNAL)
Blue Swirl0bf9e312009-07-20 17:19:25 +0000676 fprintf(stderr, "sigaction sig=%d act=0x%p, oact=0x%p\n",
677 sig, act, oact);
bellard66fb9762003-03-23 01:06:05 +0000678#endif
679 if (oact) {
Richard Hendersond2565872013-01-04 16:39:32 -0800680 __put_user(k->_sa_handler, &oact->_sa_handler);
681 __put_user(k->sa_flags, &oact->sa_flags);
ths388bb212007-05-13 13:58:00 +0000682#if !defined(TARGET_MIPS)
Richard Hendersond2565872013-01-04 16:39:32 -0800683 __put_user(k->sa_restorer, &oact->sa_restorer);
ths388bb212007-05-13 13:58:00 +0000684#endif
Richard Hendersond2565872013-01-04 16:39:32 -0800685 /* Not swapped. */
pbrook624f7972008-05-31 16:11:38 +0000686 oact->sa_mask = k->sa_mask;
bellard66fb9762003-03-23 01:06:05 +0000687 }
688 if (act) {
pbrook624f7972008-05-31 16:11:38 +0000689 /* FIXME: This is not threadsafe. */
Richard Hendersond2565872013-01-04 16:39:32 -0800690 __get_user(k->_sa_handler, &act->_sa_handler);
691 __get_user(k->sa_flags, &act->sa_flags);
ths388bb212007-05-13 13:58:00 +0000692#if !defined(TARGET_MIPS)
Richard Hendersond2565872013-01-04 16:39:32 -0800693 __get_user(k->sa_restorer, &act->sa_restorer);
ths388bb212007-05-13 13:58:00 +0000694#endif
Richard Hendersond2565872013-01-04 16:39:32 -0800695 /* To be swapped in target_to_host_sigset. */
pbrook624f7972008-05-31 16:11:38 +0000696 k->sa_mask = act->sa_mask;
bellard773b93e2004-01-04 17:15:59 +0000697
698 /* we update the host linux signal state */
699 host_sig = target_to_host_signal(sig);
700 if (host_sig != SIGSEGV && host_sig != SIGBUS) {
701 sigfillset(&act1.sa_mask);
702 act1.sa_flags = SA_SIGINFO;
pbrook624f7972008-05-31 16:11:38 +0000703 if (k->sa_flags & TARGET_SA_RESTART)
bellard773b93e2004-01-04 17:15:59 +0000704 act1.sa_flags |= SA_RESTART;
705 /* NOTE: it is important to update the host kernel signal
706 ignore state to avoid getting unexpected interrupted
707 syscalls */
pbrook624f7972008-05-31 16:11:38 +0000708 if (k->_sa_handler == TARGET_SIG_IGN) {
bellard773b93e2004-01-04 17:15:59 +0000709 act1.sa_sigaction = (void *)SIG_IGN;
pbrook624f7972008-05-31 16:11:38 +0000710 } else if (k->_sa_handler == TARGET_SIG_DFL) {
aurel32ca587a82008-12-18 22:44:13 +0000711 if (fatal_signal (sig))
712 act1.sa_sigaction = host_signal_handler;
713 else
714 act1.sa_sigaction = (void *)SIG_DFL;
bellard773b93e2004-01-04 17:15:59 +0000715 } else {
716 act1.sa_sigaction = host_signal_handler;
717 }
ths0da46a62007-10-20 20:23:07 +0000718 ret = sigaction(host_sig, &act1, NULL);
bellard773b93e2004-01-04 17:15:59 +0000719 }
bellard66fb9762003-03-23 01:06:05 +0000720 }
ths0da46a62007-10-20 20:23:07 +0000721 return ret;
bellard66fb9762003-03-23 01:06:05 +0000722}
bellard31e31b82003-02-18 22:55:36 +0000723
Anthony Liguoric227f092009-10-01 16:12:16 -0500724static inline int copy_siginfo_to_user(target_siginfo_t *tinfo,
725 const target_siginfo_t *info)
bellard43fff232003-07-09 19:31:39 +0000726{
727 tswap_siginfo(tinfo, info);
728 return 0;
729}
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 */
840static int
841setup_sigcontext(struct target_sigcontext *sc, struct target_fpstate *fpstate,
bellard28be6232007-11-11 22:23:38 +0000842 CPUX86State *env, abi_ulong mask, 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));
845 int err = 0;
846 uint16_t magic;
bellard66fb9762003-03-23 01:06:05 +0000847
bellard579a97f2007-11-11 14:26:47 +0000848 /* already locked in setup_frame() */
Riku Voipio1d8b5122014-04-23 10:26:05 +0300849 __put_user(env->segs[R_GS].selector, (unsigned int *)&sc->gs);
850 __put_user(env->segs[R_FS].selector, (unsigned int *)&sc->fs);
851 __put_user(env->segs[R_ES].selector, (unsigned int *)&sc->es);
852 __put_user(env->segs[R_DS].selector, (unsigned int *)&sc->ds);
853 __put_user(env->regs[R_EDI], &sc->edi);
854 __put_user(env->regs[R_ESI], &sc->esi);
855 __put_user(env->regs[R_EBP], &sc->ebp);
856 __put_user(env->regs[R_ESP], &sc->esp);
857 __put_user(env->regs[R_EBX], &sc->ebx);
858 __put_user(env->regs[R_EDX], &sc->edx);
859 __put_user(env->regs[R_ECX], &sc->ecx);
860 __put_user(env->regs[R_EAX], &sc->eax);
861 __put_user(cs->exception_index, &sc->trapno);
862 __put_user(env->error_code, &sc->err);
863 __put_user(env->eip, &sc->eip);
864 __put_user(env->segs[R_CS].selector, (unsigned int *)&sc->cs);
865 __put_user(env->eflags, &sc->eflags);
866 __put_user(env->regs[R_ESP], &sc->esp_at_signal);
867 __put_user(env->segs[R_SS].selector, (unsigned int *)&sc->ss);
bellarded2dcdf2003-05-29 20:06:27 +0000868
bellard28be6232007-11-11 22:23:38 +0000869 cpu_x86_fsave(env, fpstate_addr, 1);
bellarded2dcdf2003-05-29 20:06:27 +0000870 fpstate->status = fpstate->sw;
bellard775b58d2007-11-11 16:22:17 +0000871 magic = 0xffff;
Riku Voipio1d8b5122014-04-23 10:26:05 +0300872 __put_user(magic, &fpstate->magic);
873 __put_user(fpstate_addr, &sc->fpstate);
bellarded2dcdf2003-05-29 20:06:27 +0000874
bellard66fb9762003-03-23 01:06:05 +0000875 /* non-iBCS2 extensions.. */
Riku Voipio1d8b5122014-04-23 10:26:05 +0300876 __put_user(mask, &sc->oldmask);
877 __put_user(env->cr[2], &sc->cr2);
bellard66fb9762003-03-23 01:06:05 +0000878 return err;
879}
880
881/*
882 * Determine which stack to use..
883 */
884
bellard579a97f2007-11-11 14:26:47 +0000885static inline abi_ulong
pbrook624f7972008-05-31 16:11:38 +0000886get_sigframe(struct target_sigaction *ka, CPUX86State *env, size_t frame_size)
bellard66fb9762003-03-23 01:06:05 +0000887{
888 unsigned long esp;
889
890 /* Default to using normal stack */
891 esp = env->regs[R_ESP];
bellard66fb9762003-03-23 01:06:05 +0000892 /* This is the X/Open sanctioned signal stack switching. */
pbrook624f7972008-05-31 16:11:38 +0000893 if (ka->sa_flags & TARGET_SA_ONSTACK) {
thsa04e1342007-09-27 13:57:58 +0000894 if (sas_ss_flags(esp) == 0)
895 esp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
896 }
bellard66fb9762003-03-23 01:06:05 +0000897
898 /* This is the legacy signal stack switching. */
ths5fafdf22007-09-16 21:08:06 +0000899 else
bellarda52c7572003-06-21 13:14:12 +0000900 if ((env->segs[R_SS].selector & 0xffff) != __USER_DS &&
pbrook624f7972008-05-31 16:11:38 +0000901 !(ka->sa_flags & TARGET_SA_RESTORER) &&
902 ka->sa_restorer) {
903 esp = (unsigned long) ka->sa_restorer;
bellarda52c7572003-06-21 13:14:12 +0000904 }
bellard579a97f2007-11-11 14:26:47 +0000905 return (esp - frame_size) & -8ul;
bellard66fb9762003-03-23 01:06:05 +0000906}
907
bellard579a97f2007-11-11 14:26:47 +0000908/* compare linux/arch/i386/kernel/signal.c:setup_frame() */
pbrook624f7972008-05-31 16:11:38 +0000909static void setup_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -0500910 target_sigset_t *set, CPUX86State *env)
bellard66fb9762003-03-23 01:06:05 +0000911{
bellard579a97f2007-11-11 14:26:47 +0000912 abi_ulong frame_addr;
bellard66fb9762003-03-23 01:06:05 +0000913 struct sigframe *frame;
Riku Voipio7df2fa32014-04-23 10:34:53 +0300914 int i;
bellard66fb9762003-03-23 01:06:05 +0000915
bellard579a97f2007-11-11 14:26:47 +0000916 frame_addr = get_sigframe(ka, env, sizeof(*frame));
bellard66fb9762003-03-23 01:06:05 +0000917
bellard579a97f2007-11-11 14:26:47 +0000918 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
bellard66fb9762003-03-23 01:06:05 +0000919 goto give_sigsegv;
bellard579a97f2007-11-11 14:26:47 +0000920
Riku Voipio1d8b5122014-04-23 10:26:05 +0300921 __put_user(current_exec_domain_sig(sig),
922 &frame->sig);
bellard66fb9762003-03-23 01:06:05 +0000923
bellard28be6232007-11-11 22:23:38 +0000924 setup_sigcontext(&frame->sc, &frame->fpstate, env, set->sig[0],
925 frame_addr + offsetof(struct sigframe, fpstate));
bellard66fb9762003-03-23 01:06:05 +0000926
Riku Voipio7df2fa32014-04-23 10:34:53 +0300927 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
928 __put_user(set->sig[i], &frame->extramask[i - 1]);
929 }
bellard66fb9762003-03-23 01:06:05 +0000930
931 /* Set up to return from userspace. If provided, use a stub
932 already in userspace. */
pbrook624f7972008-05-31 16:11:38 +0000933 if (ka->sa_flags & TARGET_SA_RESTORER) {
Riku Voipio1d8b5122014-04-23 10:26:05 +0300934 __put_user(ka->sa_restorer, &frame->pretcode);
bellard66fb9762003-03-23 01:06:05 +0000935 } else {
bellard775b58d2007-11-11 16:22:17 +0000936 uint16_t val16;
bellard28be6232007-11-11 22:23:38 +0000937 abi_ulong retcode_addr;
938 retcode_addr = frame_addr + offsetof(struct sigframe, retcode);
Riku Voipio1d8b5122014-04-23 10:26:05 +0300939 __put_user(retcode_addr, &frame->pretcode);
bellard66fb9762003-03-23 01:06:05 +0000940 /* This is popl %eax ; movl $,%eax ; int $0x80 */
bellard775b58d2007-11-11 16:22:17 +0000941 val16 = 0xb858;
Riku Voipio1d8b5122014-04-23 10:26:05 +0300942 __put_user(val16, (uint16_t *)(frame->retcode+0));
943 __put_user(TARGET_NR_sigreturn, (int *)(frame->retcode+2));
bellard775b58d2007-11-11 16:22:17 +0000944 val16 = 0x80cd;
Riku Voipio1d8b5122014-04-23 10:26:05 +0300945 __put_user(val16, (uint16_t *)(frame->retcode+6));
bellard66fb9762003-03-23 01:06:05 +0000946 }
947
bellard66fb9762003-03-23 01:06:05 +0000948
949 /* Set up registers for signal handler */
bellard28be6232007-11-11 22:23:38 +0000950 env->regs[R_ESP] = frame_addr;
pbrook624f7972008-05-31 16:11:38 +0000951 env->eip = ka->_sa_handler;
bellard66fb9762003-03-23 01:06:05 +0000952
953 cpu_x86_load_seg(env, R_DS, __USER_DS);
954 cpu_x86_load_seg(env, R_ES, __USER_DS);
955 cpu_x86_load_seg(env, R_SS, __USER_DS);
956 cpu_x86_load_seg(env, R_CS, __USER_CS);
957 env->eflags &= ~TF_MASK;
958
bellard579a97f2007-11-11 14:26:47 +0000959 unlock_user_struct(frame, frame_addr, 1);
960
bellard66fb9762003-03-23 01:06:05 +0000961 return;
962
963give_sigsegv:
964 if (sig == TARGET_SIGSEGV)
pbrook624f7972008-05-31 16:11:38 +0000965 ka->_sa_handler = TARGET_SIG_DFL;
bellard66fb9762003-03-23 01:06:05 +0000966 force_sig(TARGET_SIGSEGV /* , current */);
967}
968
bellard579a97f2007-11-11 14:26:47 +0000969/* compare linux/arch/i386/kernel/signal.c:setup_rt_frame() */
pbrook624f7972008-05-31 16:11:38 +0000970static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -0500971 target_siginfo_t *info,
972 target_sigset_t *set, CPUX86State *env)
bellard66fb9762003-03-23 01:06:05 +0000973{
bellard28be6232007-11-11 22:23:38 +0000974 abi_ulong frame_addr, addr;
bellard66fb9762003-03-23 01:06:05 +0000975 struct rt_sigframe *frame;
bellard92319442004-06-19 16:58:13 +0000976 int i, err = 0;
bellard66fb9762003-03-23 01:06:05 +0000977
bellard579a97f2007-11-11 14:26:47 +0000978 frame_addr = get_sigframe(ka, env, sizeof(*frame));
bellard66fb9762003-03-23 01:06:05 +0000979
bellard579a97f2007-11-11 14:26:47 +0000980 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
bellard66fb9762003-03-23 01:06:05 +0000981 goto give_sigsegv;
bellard66fb9762003-03-23 01:06:05 +0000982
Riku Voipio1d8b5122014-04-23 10:26:05 +0300983 __put_user(current_exec_domain_sig(sig), &frame->sig);
bellard28be6232007-11-11 22:23:38 +0000984 addr = frame_addr + offsetof(struct rt_sigframe, info);
Riku Voipio1d8b5122014-04-23 10:26:05 +0300985 __put_user(addr, &frame->pinfo);
bellard28be6232007-11-11 22:23:38 +0000986 addr = frame_addr + offsetof(struct rt_sigframe, uc);
Riku Voipio1d8b5122014-04-23 10:26:05 +0300987 __put_user(addr, &frame->puc);
bellard66fb9762003-03-23 01:06:05 +0000988 err |= copy_siginfo_to_user(&frame->info, info);
989 if (err)
990 goto give_sigsegv;
991
992 /* Create the ucontext. */
Riku Voipio1d8b5122014-04-23 10:26:05 +0300993 __put_user(0, &frame->uc.tuc_flags);
994 __put_user(0, &frame->uc.tuc_link);
995 __put_user(target_sigaltstack_used.ss_sp, &frame->uc.tuc_stack.ss_sp);
996 __put_user(sas_ss_flags(get_sp_from_cpustate(env)),
997 &frame->uc.tuc_stack.ss_flags);
998 __put_user(target_sigaltstack_used.ss_size,
999 &frame->uc.tuc_stack.ss_size);
bellardb8076a72005-04-07 22:20:31 +00001000 err |= setup_sigcontext(&frame->uc.tuc_mcontext, &frame->fpstate,
bellard28be6232007-11-11 22:23:38 +00001001 env, set->sig[0],
1002 frame_addr + offsetof(struct rt_sigframe, fpstate));
bellard92319442004-06-19 16:58:13 +00001003 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
bellardb8076a72005-04-07 22:20:31 +00001004 if (__put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]))
bellard92319442004-06-19 16:58:13 +00001005 goto give_sigsegv;
1006 }
bellard66fb9762003-03-23 01:06:05 +00001007
1008 /* Set up to return from userspace. If provided, use a stub
1009 already in userspace. */
pbrook624f7972008-05-31 16:11:38 +00001010 if (ka->sa_flags & TARGET_SA_RESTORER) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03001011 __put_user(ka->sa_restorer, &frame->pretcode);
bellard66fb9762003-03-23 01:06:05 +00001012 } else {
bellard775b58d2007-11-11 16:22:17 +00001013 uint16_t val16;
bellard28be6232007-11-11 22:23:38 +00001014 addr = frame_addr + offsetof(struct rt_sigframe, retcode);
Riku Voipio1d8b5122014-04-23 10:26:05 +03001015 __put_user(addr, &frame->pretcode);
bellard66fb9762003-03-23 01:06:05 +00001016 /* This is movl $,%eax ; int $0x80 */
Riku Voipio1d8b5122014-04-23 10:26:05 +03001017 __put_user(0xb8, (char *)(frame->retcode+0));
1018 __put_user(TARGET_NR_rt_sigreturn, (int *)(frame->retcode+1));
bellard775b58d2007-11-11 16:22:17 +00001019 val16 = 0x80cd;
Riku Voipio1d8b5122014-04-23 10:26:05 +03001020 __put_user(val16, (uint16_t *)(frame->retcode+5));
bellard66fb9762003-03-23 01:06:05 +00001021 }
1022
1023 if (err)
1024 goto give_sigsegv;
1025
1026 /* Set up registers for signal handler */
bellard28be6232007-11-11 22:23:38 +00001027 env->regs[R_ESP] = frame_addr;
pbrook624f7972008-05-31 16:11:38 +00001028 env->eip = ka->_sa_handler;
bellard66fb9762003-03-23 01:06:05 +00001029
1030 cpu_x86_load_seg(env, R_DS, __USER_DS);
1031 cpu_x86_load_seg(env, R_ES, __USER_DS);
1032 cpu_x86_load_seg(env, R_SS, __USER_DS);
1033 cpu_x86_load_seg(env, R_CS, __USER_CS);
1034 env->eflags &= ~TF_MASK;
1035
bellard579a97f2007-11-11 14:26:47 +00001036 unlock_user_struct(frame, frame_addr, 1);
1037
bellard66fb9762003-03-23 01:06:05 +00001038 return;
1039
1040give_sigsegv:
bellard579a97f2007-11-11 14:26:47 +00001041 unlock_user_struct(frame, frame_addr, 1);
bellard66fb9762003-03-23 01:06:05 +00001042 if (sig == TARGET_SIGSEGV)
pbrook624f7972008-05-31 16:11:38 +00001043 ka->_sa_handler = TARGET_SIG_DFL;
bellard66fb9762003-03-23 01:06:05 +00001044 force_sig(TARGET_SIGSEGV /* , current */);
1045}
1046
1047static int
1048restore_sigcontext(CPUX86State *env, struct target_sigcontext *sc, int *peax)
1049{
1050 unsigned int err = 0;
bellard28be6232007-11-11 22:23:38 +00001051 abi_ulong fpstate_addr;
1052 unsigned int tmpflags;
bellard66fb9762003-03-23 01:06:05 +00001053
bellard28be6232007-11-11 22:23:38 +00001054 cpu_x86_load_seg(env, R_GS, tswap16(sc->gs));
1055 cpu_x86_load_seg(env, R_FS, tswap16(sc->fs));
1056 cpu_x86_load_seg(env, R_ES, tswap16(sc->es));
1057 cpu_x86_load_seg(env, R_DS, tswap16(sc->ds));
bellard66fb9762003-03-23 01:06:05 +00001058
bellard28be6232007-11-11 22:23:38 +00001059 env->regs[R_EDI] = tswapl(sc->edi);
1060 env->regs[R_ESI] = tswapl(sc->esi);
1061 env->regs[R_EBP] = tswapl(sc->ebp);
1062 env->regs[R_ESP] = tswapl(sc->esp);
1063 env->regs[R_EBX] = tswapl(sc->ebx);
1064 env->regs[R_EDX] = tswapl(sc->edx);
1065 env->regs[R_ECX] = tswapl(sc->ecx);
1066 env->eip = tswapl(sc->eip);
bellard66fb9762003-03-23 01:06:05 +00001067
Mike McCormack9a826d72011-06-01 15:14:37 +09001068 cpu_x86_load_seg(env, R_CS, lduw_p(&sc->cs) | 3);
1069 cpu_x86_load_seg(env, R_SS, lduw_p(&sc->ss) | 3);
ths5fafdf22007-09-16 21:08:06 +00001070
bellard28be6232007-11-11 22:23:38 +00001071 tmpflags = tswapl(sc->eflags);
1072 env->eflags = (env->eflags & ~0x40DD5) | (tmpflags & 0x40DD5);
1073 // regs->orig_eax = -1; /* disable syscall checks */
1074
1075 fpstate_addr = tswapl(sc->fpstate);
1076 if (fpstate_addr != 0) {
1077 if (!access_ok(VERIFY_READ, fpstate_addr,
1078 sizeof(struct target_fpstate)))
1079 goto badframe;
1080 cpu_x86_frstor(env, fpstate_addr, 1);
bellard66fb9762003-03-23 01:06:05 +00001081 }
1082
bellard28be6232007-11-11 22:23:38 +00001083 *peax = tswapl(sc->eax);
bellard66fb9762003-03-23 01:06:05 +00001084 return err;
bellard66fb9762003-03-23 01:06:05 +00001085badframe:
1086 return 1;
bellard66fb9762003-03-23 01:06:05 +00001087}
1088
1089long do_sigreturn(CPUX86State *env)
1090{
bellard579a97f2007-11-11 14:26:47 +00001091 struct sigframe *frame;
1092 abi_ulong frame_addr = env->regs[R_ESP] - 8;
Anthony Liguoric227f092009-10-01 16:12:16 -05001093 target_sigset_t target_set;
bellard66fb9762003-03-23 01:06:05 +00001094 sigset_t set;
1095 int eax, i;
1096
bellard447db212003-05-10 15:10:36 +00001097#if defined(DEBUG_SIGNAL)
1098 fprintf(stderr, "do_sigreturn\n");
1099#endif
bellard579a97f2007-11-11 14:26:47 +00001100 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
1101 goto badframe;
bellard66fb9762003-03-23 01:06:05 +00001102 /* set blocked signals */
bellard92319442004-06-19 16:58:13 +00001103 if (__get_user(target_set.sig[0], &frame->sc.oldmask))
1104 goto badframe;
1105 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
1106 if (__get_user(target_set.sig[i], &frame->extramask[i - 1]))
1107 goto badframe;
1108 }
bellard66fb9762003-03-23 01:06:05 +00001109
bellard92319442004-06-19 16:58:13 +00001110 target_to_host_sigset_internal(&set, &target_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00001111 do_sigprocmask(SIG_SETMASK, &set, NULL);
ths3b46e622007-09-17 08:09:54 +00001112
bellard66fb9762003-03-23 01:06:05 +00001113 /* restore registers */
1114 if (restore_sigcontext(env, &frame->sc, &eax))
1115 goto badframe;
bellard579a97f2007-11-11 14:26:47 +00001116 unlock_user_struct(frame, frame_addr, 0);
bellard66fb9762003-03-23 01:06:05 +00001117 return eax;
1118
1119badframe:
bellard579a97f2007-11-11 14:26:47 +00001120 unlock_user_struct(frame, frame_addr, 0);
bellard66fb9762003-03-23 01:06:05 +00001121 force_sig(TARGET_SIGSEGV);
1122 return 0;
1123}
1124
1125long do_rt_sigreturn(CPUX86State *env)
1126{
bellard28be6232007-11-11 22:23:38 +00001127 abi_ulong frame_addr;
1128 struct rt_sigframe *frame;
bellard66fb9762003-03-23 01:06:05 +00001129 sigset_t set;
bellard66fb9762003-03-23 01:06:05 +00001130 int eax;
1131
bellard28be6232007-11-11 22:23:38 +00001132 frame_addr = env->regs[R_ESP] - 4;
1133 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
1134 goto badframe;
bellardb8076a72005-04-07 22:20:31 +00001135 target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
Alex Barcelo1c275922014-03-14 14:36:55 +00001136 do_sigprocmask(SIG_SETMASK, &set, NULL);
ths5fafdf22007-09-16 21:08:06 +00001137
bellardb8076a72005-04-07 22:20:31 +00001138 if (restore_sigcontext(env, &frame->uc.tuc_mcontext, &eax))
bellard66fb9762003-03-23 01:06:05 +00001139 goto badframe;
1140
bellard28be6232007-11-11 22:23:38 +00001141 if (do_sigaltstack(frame_addr + offsetof(struct rt_sigframe, uc.tuc_stack), 0,
1142 get_sp_from_cpustate(env)) == -EFAULT)
bellard66fb9762003-03-23 01:06:05 +00001143 goto badframe;
thsa04e1342007-09-27 13:57:58 +00001144
bellard28be6232007-11-11 22:23:38 +00001145 unlock_user_struct(frame, frame_addr, 0);
bellard66fb9762003-03-23 01:06:05 +00001146 return eax;
1147
1148badframe:
bellard28be6232007-11-11 22:23:38 +00001149 unlock_user_struct(frame, frame_addr, 0);
1150 force_sig(TARGET_SIGSEGV);
bellard66fb9762003-03-23 01:06:05 +00001151 return 0;
1152}
1153
Andreas Schwab1744aea2013-09-03 20:12:16 +01001154#elif defined(TARGET_AARCH64)
1155
1156struct target_sigcontext {
1157 uint64_t fault_address;
1158 /* AArch64 registers */
1159 uint64_t regs[31];
1160 uint64_t sp;
1161 uint64_t pc;
1162 uint64_t pstate;
1163 /* 4K reserved for FP/SIMD state and future expansion */
1164 char __reserved[4096] __attribute__((__aligned__(16)));
1165};
1166
1167struct target_ucontext {
1168 abi_ulong tuc_flags;
1169 abi_ulong tuc_link;
1170 target_stack_t tuc_stack;
1171 target_sigset_t tuc_sigmask;
1172 /* glibc uses a 1024-bit sigset_t */
1173 char __unused[1024 / 8 - sizeof(target_sigset_t)];
1174 /* last for future expansion */
1175 struct target_sigcontext tuc_mcontext;
1176};
1177
1178/*
1179 * Header to be used at the beginning of structures extending the user
1180 * context. Such structures must be placed after the rt_sigframe on the stack
1181 * and be 16-byte aligned. The last structure must be a dummy one with the
1182 * magic and size set to 0.
1183 */
1184struct target_aarch64_ctx {
1185 uint32_t magic;
1186 uint32_t size;
1187};
1188
1189#define TARGET_FPSIMD_MAGIC 0x46508001
1190
1191struct target_fpsimd_context {
1192 struct target_aarch64_ctx head;
1193 uint32_t fpsr;
1194 uint32_t fpcr;
1195 uint64_t vregs[32 * 2]; /* really uint128_t vregs[32] */
1196};
1197
1198/*
1199 * Auxiliary context saved in the sigcontext.__reserved array. Not exported to
1200 * user space as it will change with the addition of new context. User space
1201 * should check the magic/size information.
1202 */
1203struct target_aux_context {
1204 struct target_fpsimd_context fpsimd;
1205 /* additional context to be added before "end" */
1206 struct target_aarch64_ctx end;
1207};
1208
1209struct target_rt_sigframe {
1210 struct target_siginfo info;
1211 struct target_ucontext uc;
1212 uint64_t fp;
1213 uint64_t lr;
1214 uint32_t tramp[2];
1215};
1216
1217static int target_setup_sigframe(struct target_rt_sigframe *sf,
1218 CPUARMState *env, target_sigset_t *set)
1219{
1220 int i;
1221 struct target_aux_context *aux =
1222 (struct target_aux_context *)sf->uc.tuc_mcontext.__reserved;
1223
1224 /* set up the stack frame for unwinding */
1225 __put_user(env->xregs[29], &sf->fp);
1226 __put_user(env->xregs[30], &sf->lr);
1227
1228 for (i = 0; i < 31; i++) {
1229 __put_user(env->xregs[i], &sf->uc.tuc_mcontext.regs[i]);
1230 }
1231 __put_user(env->xregs[31], &sf->uc.tuc_mcontext.sp);
1232 __put_user(env->pc, &sf->uc.tuc_mcontext.pc);
Peter Maydelld3563122013-12-17 19:42:30 +00001233 __put_user(pstate_read(env), &sf->uc.tuc_mcontext.pstate);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001234
Peter Maydell7af03922014-05-01 18:36:17 +01001235 __put_user(env->exception.vaddress, &sf->uc.tuc_mcontext.fault_address);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001236
1237 for (i = 0; i < TARGET_NSIG_WORDS; i++) {
1238 __put_user(set->sig[i], &sf->uc.tuc_sigmask.sig[i]);
1239 }
1240
1241 for (i = 0; i < 32; i++) {
1242#ifdef TARGET_WORDS_BIGENDIAN
1243 __put_user(env->vfp.regs[i * 2], &aux->fpsimd.vregs[i * 2 + 1]);
1244 __put_user(env->vfp.regs[i * 2 + 1], &aux->fpsimd.vregs[i * 2]);
1245#else
1246 __put_user(env->vfp.regs[i * 2], &aux->fpsimd.vregs[i * 2]);
1247 __put_user(env->vfp.regs[i * 2 + 1], &aux->fpsimd.vregs[i * 2 + 1]);
1248#endif
1249 }
Will Newtone0ee1382014-01-04 22:15:48 +00001250 __put_user(vfp_get_fpsr(env), &aux->fpsimd.fpsr);
1251 __put_user(vfp_get_fpcr(env), &aux->fpsimd.fpcr);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001252 __put_user(TARGET_FPSIMD_MAGIC, &aux->fpsimd.head.magic);
1253 __put_user(sizeof(struct target_fpsimd_context),
1254 &aux->fpsimd.head.size);
1255
1256 /* set the "end" magic */
1257 __put_user(0, &aux->end.magic);
1258 __put_user(0, &aux->end.size);
1259
1260 return 0;
1261}
1262
1263static int target_restore_sigframe(CPUARMState *env,
1264 struct target_rt_sigframe *sf)
1265{
1266 sigset_t set;
1267 int i;
1268 struct target_aux_context *aux =
1269 (struct target_aux_context *)sf->uc.tuc_mcontext.__reserved;
Will Newtone0ee1382014-01-04 22:15:48 +00001270 uint32_t magic, size, fpsr, fpcr;
Peter Maydelld3563122013-12-17 19:42:30 +00001271 uint64_t pstate;
Andreas Schwab1744aea2013-09-03 20:12:16 +01001272
1273 target_to_host_sigset(&set, &sf->uc.tuc_sigmask);
Alex Barcelo1c275922014-03-14 14:36:55 +00001274 do_sigprocmask(SIG_SETMASK, &set, NULL);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001275
1276 for (i = 0; i < 31; i++) {
1277 __get_user(env->xregs[i], &sf->uc.tuc_mcontext.regs[i]);
1278 }
1279
1280 __get_user(env->xregs[31], &sf->uc.tuc_mcontext.sp);
1281 __get_user(env->pc, &sf->uc.tuc_mcontext.pc);
Peter Maydelld3563122013-12-17 19:42:30 +00001282 __get_user(pstate, &sf->uc.tuc_mcontext.pstate);
1283 pstate_write(env, pstate);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001284
1285 __get_user(magic, &aux->fpsimd.head.magic);
1286 __get_user(size, &aux->fpsimd.head.size);
1287
1288 if (magic != TARGET_FPSIMD_MAGIC
1289 || size != sizeof(struct target_fpsimd_context)) {
1290 return 1;
1291 }
1292
Peter Maydell4cf23482014-03-02 19:36:38 +00001293 for (i = 0; i < 32; i++) {
1294#ifdef TARGET_WORDS_BIGENDIAN
1295 __get_user(env->vfp.regs[i * 2], &aux->fpsimd.vregs[i * 2 + 1]);
1296 __get_user(env->vfp.regs[i * 2 + 1], &aux->fpsimd.vregs[i * 2]);
1297#else
1298 __get_user(env->vfp.regs[i * 2], &aux->fpsimd.vregs[i * 2]);
1299 __get_user(env->vfp.regs[i * 2 + 1], &aux->fpsimd.vregs[i * 2 + 1]);
1300#endif
Andreas Schwab1744aea2013-09-03 20:12:16 +01001301 }
Will Newtone0ee1382014-01-04 22:15:48 +00001302 __get_user(fpsr, &aux->fpsimd.fpsr);
1303 vfp_set_fpsr(env, fpsr);
1304 __get_user(fpcr, &aux->fpsimd.fpcr);
1305 vfp_set_fpcr(env, fpcr);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001306
1307 return 0;
1308}
1309
1310static abi_ulong get_sigframe(struct target_sigaction *ka, CPUARMState *env)
1311{
1312 abi_ulong sp;
1313
1314 sp = env->xregs[31];
1315
1316 /*
1317 * This is the X/Open sanctioned signal stack switching.
1318 */
1319 if ((ka->sa_flags & SA_ONSTACK) && !sas_ss_flags(sp)) {
1320 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
1321 }
1322
1323 sp = (sp - sizeof(struct target_rt_sigframe)) & ~15;
1324
1325 return sp;
1326}
1327
1328static void target_setup_frame(int usig, struct target_sigaction *ka,
1329 target_siginfo_t *info, target_sigset_t *set,
1330 CPUARMState *env)
1331{
1332 struct target_rt_sigframe *frame;
Michael Matz8a3ae912014-03-02 19:36:39 +00001333 abi_ulong frame_addr, return_addr;
Andreas Schwab1744aea2013-09-03 20:12:16 +01001334
1335 frame_addr = get_sigframe(ka, env);
1336 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
1337 goto give_sigsegv;
1338 }
1339
1340 __put_user(0, &frame->uc.tuc_flags);
1341 __put_user(0, &frame->uc.tuc_link);
1342
1343 __put_user(target_sigaltstack_used.ss_sp,
1344 &frame->uc.tuc_stack.ss_sp);
1345 __put_user(sas_ss_flags(env->xregs[31]),
1346 &frame->uc.tuc_stack.ss_flags);
1347 __put_user(target_sigaltstack_used.ss_size,
1348 &frame->uc.tuc_stack.ss_size);
1349 target_setup_sigframe(frame, env, set);
Michael Matz8a3ae912014-03-02 19:36:39 +00001350 if (ka->sa_flags & TARGET_SA_RESTORER) {
1351 return_addr = ka->sa_restorer;
1352 } else {
1353 /* mov x8,#__NR_rt_sigreturn; svc #0 */
1354 __put_user(0xd2801168, &frame->tramp[0]);
1355 __put_user(0xd4000001, &frame->tramp[1]);
1356 return_addr = frame_addr + offsetof(struct target_rt_sigframe, tramp);
1357 }
Andreas Schwab1744aea2013-09-03 20:12:16 +01001358 env->xregs[0] = usig;
1359 env->xregs[31] = frame_addr;
1360 env->xregs[29] = env->xregs[31] + offsetof(struct target_rt_sigframe, fp);
1361 env->pc = ka->_sa_handler;
Michael Matz8a3ae912014-03-02 19:36:39 +00001362 env->xregs[30] = return_addr;
Andreas Schwab1744aea2013-09-03 20:12:16 +01001363 if (info) {
1364 if (copy_siginfo_to_user(&frame->info, info)) {
1365 goto give_sigsegv;
1366 }
1367 env->xregs[1] = frame_addr + offsetof(struct target_rt_sigframe, info);
1368 env->xregs[2] = frame_addr + offsetof(struct target_rt_sigframe, uc);
1369 }
1370
1371 unlock_user_struct(frame, frame_addr, 1);
1372 return;
1373
1374 give_sigsegv:
1375 unlock_user_struct(frame, frame_addr, 1);
1376 force_sig(TARGET_SIGSEGV);
1377}
1378
1379static void setup_rt_frame(int sig, struct target_sigaction *ka,
1380 target_siginfo_t *info, target_sigset_t *set,
1381 CPUARMState *env)
1382{
1383 target_setup_frame(sig, ka, info, set, env);
1384}
1385
1386static void setup_frame(int sig, struct target_sigaction *ka,
1387 target_sigset_t *set, CPUARMState *env)
1388{
1389 target_setup_frame(sig, ka, 0, set, env);
1390}
1391
1392long do_rt_sigreturn(CPUARMState *env)
1393{
Peter Maydell7f72cd22014-03-12 13:06:00 +00001394 struct target_rt_sigframe *frame = NULL;
Andreas Schwab1744aea2013-09-03 20:12:16 +01001395 abi_ulong frame_addr = env->xregs[31];
1396
1397 if (frame_addr & 15) {
1398 goto badframe;
1399 }
1400
1401 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
1402 goto badframe;
1403 }
1404
1405 if (target_restore_sigframe(env, frame)) {
1406 goto badframe;
1407 }
1408
1409 if (do_sigaltstack(frame_addr +
1410 offsetof(struct target_rt_sigframe, uc.tuc_stack),
1411 0, get_sp_from_cpustate(env)) == -EFAULT) {
1412 goto badframe;
1413 }
1414
1415 unlock_user_struct(frame, frame_addr, 0);
1416 return env->xregs[0];
1417
1418 badframe:
1419 unlock_user_struct(frame, frame_addr, 0);
1420 force_sig(TARGET_SIGSEGV);
1421 return 0;
1422}
1423
1424long do_sigreturn(CPUARMState *env)
1425{
1426 return do_rt_sigreturn(env);
1427}
1428
bellard43fff232003-07-09 19:31:39 +00001429#elif defined(TARGET_ARM)
1430
1431struct target_sigcontext {
blueswir1992f48a2007-10-14 16:27:31 +00001432 abi_ulong trap_no;
1433 abi_ulong error_code;
1434 abi_ulong oldmask;
1435 abi_ulong arm_r0;
1436 abi_ulong arm_r1;
1437 abi_ulong arm_r2;
1438 abi_ulong arm_r3;
1439 abi_ulong arm_r4;
1440 abi_ulong arm_r5;
1441 abi_ulong arm_r6;
1442 abi_ulong arm_r7;
1443 abi_ulong arm_r8;
1444 abi_ulong arm_r9;
1445 abi_ulong arm_r10;
1446 abi_ulong arm_fp;
1447 abi_ulong arm_ip;
1448 abi_ulong arm_sp;
1449 abi_ulong arm_lr;
1450 abi_ulong arm_pc;
1451 abi_ulong arm_cpsr;
1452 abi_ulong fault_address;
bellard43fff232003-07-09 19:31:39 +00001453};
1454
pbrooka745ec62008-05-06 15:36:17 +00001455struct target_ucontext_v1 {
blueswir1992f48a2007-10-14 16:27:31 +00001456 abi_ulong tuc_flags;
1457 abi_ulong tuc_link;
Anthony Liguoric227f092009-10-01 16:12:16 -05001458 target_stack_t tuc_stack;
bellardb8076a72005-04-07 22:20:31 +00001459 struct target_sigcontext tuc_mcontext;
Anthony Liguoric227f092009-10-01 16:12:16 -05001460 target_sigset_t tuc_sigmask; /* mask last for extensibility */
bellard43fff232003-07-09 19:31:39 +00001461};
1462
pbrooka745ec62008-05-06 15:36:17 +00001463struct target_ucontext_v2 {
1464 abi_ulong tuc_flags;
1465 abi_ulong tuc_link;
Anthony Liguoric227f092009-10-01 16:12:16 -05001466 target_stack_t tuc_stack;
pbrooka745ec62008-05-06 15:36:17 +00001467 struct target_sigcontext tuc_mcontext;
Anthony Liguoric227f092009-10-01 16:12:16 -05001468 target_sigset_t tuc_sigmask; /* mask last for extensibility */
Peter Maydell5f0b7c82010-11-24 15:20:03 +00001469 char __unused[128 - sizeof(target_sigset_t)];
pbrooka745ec62008-05-06 15:36:17 +00001470 abi_ulong tuc_regspace[128] __attribute__((__aligned__(8)));
1471};
1472
Peter Maydell0d871bd2010-11-24 15:20:05 +00001473struct target_user_vfp {
1474 uint64_t fpregs[32];
1475 abi_ulong fpscr;
1476};
1477
1478struct target_user_vfp_exc {
1479 abi_ulong fpexc;
1480 abi_ulong fpinst;
1481 abi_ulong fpinst2;
1482};
1483
1484struct target_vfp_sigframe {
1485 abi_ulong magic;
1486 abi_ulong size;
1487 struct target_user_vfp ufp;
1488 struct target_user_vfp_exc ufp_exc;
1489} __attribute__((__aligned__(8)));
1490
Peter Maydell08e11252010-11-24 15:20:07 +00001491struct target_iwmmxt_sigframe {
1492 abi_ulong magic;
1493 abi_ulong size;
1494 uint64_t regs[16];
1495 /* Note that not all the coprocessor control registers are stored here */
1496 uint32_t wcssf;
1497 uint32_t wcasf;
1498 uint32_t wcgr0;
1499 uint32_t wcgr1;
1500 uint32_t wcgr2;
1501 uint32_t wcgr3;
1502} __attribute__((__aligned__(8)));
1503
Peter Maydell0d871bd2010-11-24 15:20:05 +00001504#define TARGET_VFP_MAGIC 0x56465001
Peter Maydell08e11252010-11-24 15:20:07 +00001505#define TARGET_IWMMXT_MAGIC 0x12ef842a
Peter Maydell0d871bd2010-11-24 15:20:05 +00001506
pbrooka8c33202008-05-07 23:22:46 +00001507struct sigframe_v1
bellard43fff232003-07-09 19:31:39 +00001508{
1509 struct target_sigcontext sc;
blueswir1992f48a2007-10-14 16:27:31 +00001510 abi_ulong extramask[TARGET_NSIG_WORDS-1];
1511 abi_ulong retcode;
bellard43fff232003-07-09 19:31:39 +00001512};
1513
pbrooka8c33202008-05-07 23:22:46 +00001514struct sigframe_v2
1515{
1516 struct target_ucontext_v2 uc;
1517 abi_ulong retcode;
1518};
1519
pbrooka745ec62008-05-06 15:36:17 +00001520struct rt_sigframe_v1
bellard43fff232003-07-09 19:31:39 +00001521{
bellardf8b0aa22007-11-11 23:03:42 +00001522 abi_ulong pinfo;
1523 abi_ulong puc;
bellard43fff232003-07-09 19:31:39 +00001524 struct target_siginfo info;
pbrooka745ec62008-05-06 15:36:17 +00001525 struct target_ucontext_v1 uc;
1526 abi_ulong retcode;
1527};
1528
1529struct rt_sigframe_v2
1530{
1531 struct target_siginfo info;
1532 struct target_ucontext_v2 uc;
blueswir1992f48a2007-10-14 16:27:31 +00001533 abi_ulong retcode;
bellard43fff232003-07-09 19:31:39 +00001534};
1535
1536#define TARGET_CONFIG_CPU_32 1
1537
1538/*
1539 * For ARM syscalls, we encode the syscall number into the instruction.
1540 */
1541#define SWI_SYS_SIGRETURN (0xef000000|(TARGET_NR_sigreturn + ARM_SYSCALL_BASE))
1542#define SWI_SYS_RT_SIGRETURN (0xef000000|(TARGET_NR_rt_sigreturn + ARM_SYSCALL_BASE))
1543
1544/*
1545 * For Thumb syscalls, we pass the syscall number via r7. We therefore
1546 * need two 16-bit instructions.
1547 */
1548#define SWI_THUMB_SIGRETURN (0xdf00 << 16 | 0x2700 | (TARGET_NR_sigreturn))
1549#define SWI_THUMB_RT_SIGRETURN (0xdf00 << 16 | 0x2700 | (TARGET_NR_rt_sigreturn))
1550
blueswir1992f48a2007-10-14 16:27:31 +00001551static const abi_ulong retcodes[4] = {
bellard43fff232003-07-09 19:31:39 +00001552 SWI_SYS_SIGRETURN, SWI_THUMB_SIGRETURN,
1553 SWI_SYS_RT_SIGRETURN, SWI_THUMB_RT_SIGRETURN
1554};
1555
1556
Andreas Färber05390242012-02-25 03:37:53 +01001557static inline int valid_user_regs(CPUARMState *regs)
bellard43fff232003-07-09 19:31:39 +00001558{
1559 return 1;
1560}
1561
pbrooka8c33202008-05-07 23:22:46 +00001562static void
bellard43fff232003-07-09 19:31:39 +00001563setup_sigcontext(struct target_sigcontext *sc, /*struct _fpstate *fpstate,*/
Andreas Färber05390242012-02-25 03:37:53 +01001564 CPUARMState *env, abi_ulong mask)
bellard43fff232003-07-09 19:31:39 +00001565{
pbrooka8c33202008-05-07 23:22:46 +00001566 __put_user(env->regs[0], &sc->arm_r0);
1567 __put_user(env->regs[1], &sc->arm_r1);
1568 __put_user(env->regs[2], &sc->arm_r2);
1569 __put_user(env->regs[3], &sc->arm_r3);
1570 __put_user(env->regs[4], &sc->arm_r4);
1571 __put_user(env->regs[5], &sc->arm_r5);
1572 __put_user(env->regs[6], &sc->arm_r6);
1573 __put_user(env->regs[7], &sc->arm_r7);
1574 __put_user(env->regs[8], &sc->arm_r8);
1575 __put_user(env->regs[9], &sc->arm_r9);
1576 __put_user(env->regs[10], &sc->arm_r10);
1577 __put_user(env->regs[11], &sc->arm_fp);
1578 __put_user(env->regs[12], &sc->arm_ip);
1579 __put_user(env->regs[13], &sc->arm_sp);
1580 __put_user(env->regs[14], &sc->arm_lr);
1581 __put_user(env->regs[15], &sc->arm_pc);
bellard43fff232003-07-09 19:31:39 +00001582#ifdef TARGET_CONFIG_CPU_32
pbrooka8c33202008-05-07 23:22:46 +00001583 __put_user(cpsr_read(env), &sc->arm_cpsr);
bellard43fff232003-07-09 19:31:39 +00001584#endif
1585
pbrooka8c33202008-05-07 23:22:46 +00001586 __put_user(/* current->thread.trap_no */ 0, &sc->trap_no);
1587 __put_user(/* current->thread.error_code */ 0, &sc->error_code);
1588 __put_user(/* current->thread.address */ 0, &sc->fault_address);
1589 __put_user(mask, &sc->oldmask);
bellard43fff232003-07-09 19:31:39 +00001590}
1591
bellard579a97f2007-11-11 14:26:47 +00001592static inline abi_ulong
Andreas Färber05390242012-02-25 03:37:53 +01001593get_sigframe(struct target_sigaction *ka, CPUARMState *regs, int framesize)
bellard43fff232003-07-09 19:31:39 +00001594{
1595 unsigned long sp = regs->regs[13];
1596
bellard43fff232003-07-09 19:31:39 +00001597 /*
1598 * This is the X/Open sanctioned signal stack switching.
1599 */
pbrook624f7972008-05-31 16:11:38 +00001600 if ((ka->sa_flags & TARGET_SA_ONSTACK) && !sas_ss_flags(sp))
thsa04e1342007-09-27 13:57:58 +00001601 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
bellard43fff232003-07-09 19:31:39 +00001602 /*
1603 * ATPCS B01 mandates 8-byte alignment
1604 */
bellard579a97f2007-11-11 14:26:47 +00001605 return (sp - framesize) & ~7;
bellard43fff232003-07-09 19:31:39 +00001606}
1607
1608static int
Andreas Färber05390242012-02-25 03:37:53 +01001609setup_return(CPUARMState *env, struct target_sigaction *ka,
bellardf8b0aa22007-11-11 23:03:42 +00001610 abi_ulong *rc, abi_ulong frame_addr, int usig, abi_ulong rc_addr)
bellard43fff232003-07-09 19:31:39 +00001611{
pbrook624f7972008-05-31 16:11:38 +00001612 abi_ulong handler = ka->_sa_handler;
blueswir1992f48a2007-10-14 16:27:31 +00001613 abi_ulong retcode;
pbrook75b680e2008-03-21 16:07:30 +00001614 int thumb = handler & 1;
Peter Maydell964413d2011-01-14 20:39:19 +01001615 uint32_t cpsr = cpsr_read(env);
1616
1617 cpsr &= ~CPSR_IT;
1618 if (thumb) {
1619 cpsr |= CPSR_T;
1620 } else {
1621 cpsr &= ~CPSR_T;
1622 }
bellard43fff232003-07-09 19:31:39 +00001623
pbrook624f7972008-05-31 16:11:38 +00001624 if (ka->sa_flags & TARGET_SA_RESTORER) {
1625 retcode = ka->sa_restorer;
bellard43fff232003-07-09 19:31:39 +00001626 } else {
1627 unsigned int idx = thumb;
1628
pbrook624f7972008-05-31 16:11:38 +00001629 if (ka->sa_flags & TARGET_SA_SIGINFO)
bellard43fff232003-07-09 19:31:39 +00001630 idx += 2;
1631
1632 if (__put_user(retcodes[idx], rc))
1633 return 1;
Stefan Weilca8a2772011-10-03 22:43:19 +02001634
bellardf8b0aa22007-11-11 23:03:42 +00001635 retcode = rc_addr + thumb;
bellard43fff232003-07-09 19:31:39 +00001636 }
1637
1638 env->regs[0] = usig;
bellardf8b0aa22007-11-11 23:03:42 +00001639 env->regs[13] = frame_addr;
bellard43fff232003-07-09 19:31:39 +00001640 env->regs[14] = retcode;
1641 env->regs[15] = handler & (thumb ? ~1 : ~3);
Peter Maydell964413d2011-01-14 20:39:19 +01001642 cpsr_write(env, cpsr, 0xffffffff);
bellard43fff232003-07-09 19:31:39 +00001643
1644 return 0;
1645}
1646
Andreas Färber05390242012-02-25 03:37:53 +01001647static abi_ulong *setup_sigframe_v2_vfp(abi_ulong *regspace, CPUARMState *env)
Peter Maydell0d871bd2010-11-24 15:20:05 +00001648{
1649 int i;
1650 struct target_vfp_sigframe *vfpframe;
1651 vfpframe = (struct target_vfp_sigframe *)regspace;
1652 __put_user(TARGET_VFP_MAGIC, &vfpframe->magic);
1653 __put_user(sizeof(*vfpframe), &vfpframe->size);
1654 for (i = 0; i < 32; i++) {
Peter Maydell005e1a02011-02-10 13:59:35 +00001655 __put_user(float64_val(env->vfp.regs[i]), &vfpframe->ufp.fpregs[i]);
Peter Maydell0d871bd2010-11-24 15:20:05 +00001656 }
1657 __put_user(vfp_get_fpscr(env), &vfpframe->ufp.fpscr);
1658 __put_user(env->vfp.xregs[ARM_VFP_FPEXC], &vfpframe->ufp_exc.fpexc);
1659 __put_user(env->vfp.xregs[ARM_VFP_FPINST], &vfpframe->ufp_exc.fpinst);
1660 __put_user(env->vfp.xregs[ARM_VFP_FPINST2], &vfpframe->ufp_exc.fpinst2);
1661 return (abi_ulong*)(vfpframe+1);
1662}
1663
Andreas Färber05390242012-02-25 03:37:53 +01001664static abi_ulong *setup_sigframe_v2_iwmmxt(abi_ulong *regspace,
1665 CPUARMState *env)
Peter Maydell08e11252010-11-24 15:20:07 +00001666{
1667 int i;
1668 struct target_iwmmxt_sigframe *iwmmxtframe;
1669 iwmmxtframe = (struct target_iwmmxt_sigframe *)regspace;
1670 __put_user(TARGET_IWMMXT_MAGIC, &iwmmxtframe->magic);
1671 __put_user(sizeof(*iwmmxtframe), &iwmmxtframe->size);
1672 for (i = 0; i < 16; i++) {
1673 __put_user(env->iwmmxt.regs[i], &iwmmxtframe->regs[i]);
1674 }
1675 __put_user(env->vfp.xregs[ARM_IWMMXT_wCSSF], &iwmmxtframe->wcssf);
1676 __put_user(env->vfp.xregs[ARM_IWMMXT_wCASF], &iwmmxtframe->wcssf);
1677 __put_user(env->vfp.xregs[ARM_IWMMXT_wCGR0], &iwmmxtframe->wcgr0);
1678 __put_user(env->vfp.xregs[ARM_IWMMXT_wCGR1], &iwmmxtframe->wcgr1);
1679 __put_user(env->vfp.xregs[ARM_IWMMXT_wCGR2], &iwmmxtframe->wcgr2);
1680 __put_user(env->vfp.xregs[ARM_IWMMXT_wCGR3], &iwmmxtframe->wcgr3);
1681 return (abi_ulong*)(iwmmxtframe+1);
1682}
1683
pbrooka8c33202008-05-07 23:22:46 +00001684static void setup_sigframe_v2(struct target_ucontext_v2 *uc,
Andreas Färber05390242012-02-25 03:37:53 +01001685 target_sigset_t *set, CPUARMState *env)
bellard43fff232003-07-09 19:31:39 +00001686{
pbrooka8c33202008-05-07 23:22:46 +00001687 struct target_sigaltstack stack;
1688 int i;
Peter Maydell0d871bd2010-11-24 15:20:05 +00001689 abi_ulong *regspace;
pbrooka8c33202008-05-07 23:22:46 +00001690
1691 /* Clear all the bits of the ucontext we don't use. */
1692 memset(uc, 0, offsetof(struct target_ucontext_v2, tuc_mcontext));
1693
1694 memset(&stack, 0, sizeof(stack));
1695 __put_user(target_sigaltstack_used.ss_sp, &stack.ss_sp);
1696 __put_user(target_sigaltstack_used.ss_size, &stack.ss_size);
1697 __put_user(sas_ss_flags(get_sp_from_cpustate(env)), &stack.ss_flags);
1698 memcpy(&uc->tuc_stack, &stack, sizeof(stack));
1699
1700 setup_sigcontext(&uc->tuc_mcontext, env, set->sig[0]);
Peter Maydell0d871bd2010-11-24 15:20:05 +00001701 /* Save coprocessor signal frame. */
1702 regspace = uc->tuc_regspace;
1703 if (arm_feature(env, ARM_FEATURE_VFP)) {
1704 regspace = setup_sigframe_v2_vfp(regspace, env);
1705 }
Peter Maydell08e11252010-11-24 15:20:07 +00001706 if (arm_feature(env, ARM_FEATURE_IWMMXT)) {
1707 regspace = setup_sigframe_v2_iwmmxt(regspace, env);
1708 }
1709
Peter Maydell0d871bd2010-11-24 15:20:05 +00001710 /* Write terminating magic word */
1711 __put_user(0, regspace);
1712
pbrooka8c33202008-05-07 23:22:46 +00001713 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
1714 __put_user(set->sig[i], &uc->tuc_sigmask.sig[i]);
1715 }
1716}
1717
1718/* compare linux/arch/arm/kernel/signal.c:setup_frame() */
pbrook624f7972008-05-31 16:11:38 +00001719static void setup_frame_v1(int usig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01001720 target_sigset_t *set, CPUARMState *regs)
pbrooka8c33202008-05-07 23:22:46 +00001721{
1722 struct sigframe_v1 *frame;
bellard579a97f2007-11-11 14:26:47 +00001723 abi_ulong frame_addr = get_sigframe(ka, regs, sizeof(*frame));
pbrooka8c33202008-05-07 23:22:46 +00001724 int i;
bellard43fff232003-07-09 19:31:39 +00001725
bellard579a97f2007-11-11 14:26:47 +00001726 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
1727 return;
1728
pbrooka8c33202008-05-07 23:22:46 +00001729 setup_sigcontext(&frame->sc, regs, set->sig[0]);
bellard43fff232003-07-09 19:31:39 +00001730
bellard92319442004-06-19 16:58:13 +00001731 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
1732 if (__put_user(set->sig[i], &frame->extramask[i - 1]))
bellard579a97f2007-11-11 14:26:47 +00001733 goto end;
bellard43fff232003-07-09 19:31:39 +00001734 }
1735
pbrooka8c33202008-05-07 23:22:46 +00001736 setup_return(regs, ka, &frame->retcode, frame_addr, usig,
1737 frame_addr + offsetof(struct sigframe_v1, retcode));
bellard579a97f2007-11-11 14:26:47 +00001738
1739end:
1740 unlock_user_struct(frame, frame_addr, 1);
pbrooka8c33202008-05-07 23:22:46 +00001741}
1742
pbrook624f7972008-05-31 16:11:38 +00001743static void setup_frame_v2(int usig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01001744 target_sigset_t *set, CPUARMState *regs)
pbrooka8c33202008-05-07 23:22:46 +00001745{
1746 struct sigframe_v2 *frame;
1747 abi_ulong frame_addr = get_sigframe(ka, regs, sizeof(*frame));
1748
1749 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
1750 return;
1751
1752 setup_sigframe_v2(&frame->uc, set, regs);
1753
1754 setup_return(regs, ka, &frame->retcode, frame_addr, usig,
1755 frame_addr + offsetof(struct sigframe_v2, retcode));
1756
1757 unlock_user_struct(frame, frame_addr, 1);
1758}
1759
pbrook624f7972008-05-31 16:11:38 +00001760static void setup_frame(int usig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01001761 target_sigset_t *set, CPUARMState *regs)
pbrooka8c33202008-05-07 23:22:46 +00001762{
1763 if (get_osversion() >= 0x020612) {
1764 setup_frame_v2(usig, ka, set, regs);
1765 } else {
1766 setup_frame_v1(usig, ka, set, regs);
1767 }
bellard43fff232003-07-09 19:31:39 +00001768}
1769
bellard579a97f2007-11-11 14:26:47 +00001770/* compare linux/arch/arm/kernel/signal.c:setup_rt_frame() */
pbrook624f7972008-05-31 16:11:38 +00001771static void setup_rt_frame_v1(int usig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05001772 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01001773 target_sigset_t *set, CPUARMState *env)
bellard43fff232003-07-09 19:31:39 +00001774{
pbrooka745ec62008-05-06 15:36:17 +00001775 struct rt_sigframe_v1 *frame;
bellard579a97f2007-11-11 14:26:47 +00001776 abi_ulong frame_addr = get_sigframe(ka, env, sizeof(*frame));
thsa04e1342007-09-27 13:57:58 +00001777 struct target_sigaltstack stack;
pbrooka8c33202008-05-07 23:22:46 +00001778 int i;
bellardf8b0aa22007-11-11 23:03:42 +00001779 abi_ulong info_addr, uc_addr;
bellard43fff232003-07-09 19:31:39 +00001780
bellard579a97f2007-11-11 14:26:47 +00001781 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
bellardedf779f2004-02-22 13:40:13 +00001782 return /* 1 */;
1783
pbrooka745ec62008-05-06 15:36:17 +00001784 info_addr = frame_addr + offsetof(struct rt_sigframe_v1, info);
pbrooka8c33202008-05-07 23:22:46 +00001785 __put_user(info_addr, &frame->pinfo);
pbrooka745ec62008-05-06 15:36:17 +00001786 uc_addr = frame_addr + offsetof(struct rt_sigframe_v1, uc);
pbrooka8c33202008-05-07 23:22:46 +00001787 __put_user(uc_addr, &frame->puc);
1788 copy_siginfo_to_user(&frame->info, info);
bellard43fff232003-07-09 19:31:39 +00001789
1790 /* Clear all the bits of the ucontext we don't use. */
pbrooka745ec62008-05-06 15:36:17 +00001791 memset(&frame->uc, 0, offsetof(struct target_ucontext_v1, tuc_mcontext));
bellard43fff232003-07-09 19:31:39 +00001792
thsa04e1342007-09-27 13:57:58 +00001793 memset(&stack, 0, sizeof(stack));
1794 __put_user(target_sigaltstack_used.ss_sp, &stack.ss_sp);
1795 __put_user(target_sigaltstack_used.ss_size, &stack.ss_size);
1796 __put_user(sas_ss_flags(get_sp_from_cpustate(env)), &stack.ss_flags);
bellard775b58d2007-11-11 16:22:17 +00001797 memcpy(&frame->uc.tuc_stack, &stack, sizeof(stack));
thsa04e1342007-09-27 13:57:58 +00001798
pbrooka8c33202008-05-07 23:22:46 +00001799 setup_sigcontext(&frame->uc.tuc_mcontext, env, set->sig[0]);
bellard92319442004-06-19 16:58:13 +00001800 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
bellardb8076a72005-04-07 22:20:31 +00001801 if (__put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]))
bellard579a97f2007-11-11 14:26:47 +00001802 goto end;
bellard92319442004-06-19 16:58:13 +00001803 }
bellard43fff232003-07-09 19:31:39 +00001804
pbrooka8c33202008-05-07 23:22:46 +00001805 setup_return(env, ka, &frame->retcode, frame_addr, usig,
1806 frame_addr + offsetof(struct rt_sigframe_v1, retcode));
pbrooka745ec62008-05-06 15:36:17 +00001807
pbrooka8c33202008-05-07 23:22:46 +00001808 env->regs[1] = info_addr;
1809 env->regs[2] = uc_addr;
pbrooka745ec62008-05-06 15:36:17 +00001810
1811end:
1812 unlock_user_struct(frame, frame_addr, 1);
pbrooka745ec62008-05-06 15:36:17 +00001813}
1814
pbrook624f7972008-05-31 16:11:38 +00001815static void setup_rt_frame_v2(int usig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05001816 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01001817 target_sigset_t *set, CPUARMState *env)
pbrooka745ec62008-05-06 15:36:17 +00001818{
1819 struct rt_sigframe_v2 *frame;
1820 abi_ulong frame_addr = get_sigframe(ka, env, sizeof(*frame));
pbrooka745ec62008-05-06 15:36:17 +00001821 abi_ulong info_addr, uc_addr;
1822
1823 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
1824 return /* 1 */;
1825
1826 info_addr = frame_addr + offsetof(struct rt_sigframe_v2, info);
1827 uc_addr = frame_addr + offsetof(struct rt_sigframe_v2, uc);
pbrooka8c33202008-05-07 23:22:46 +00001828 copy_siginfo_to_user(&frame->info, info);
pbrooka745ec62008-05-06 15:36:17 +00001829
pbrooka8c33202008-05-07 23:22:46 +00001830 setup_sigframe_v2(&frame->uc, set, env);
pbrooka745ec62008-05-06 15:36:17 +00001831
pbrooka8c33202008-05-07 23:22:46 +00001832 setup_return(env, ka, &frame->retcode, frame_addr, usig,
1833 frame_addr + offsetof(struct rt_sigframe_v2, retcode));
pbrooka745ec62008-05-06 15:36:17 +00001834
pbrooka8c33202008-05-07 23:22:46 +00001835 env->regs[1] = info_addr;
1836 env->regs[2] = uc_addr;
pbrooka745ec62008-05-06 15:36:17 +00001837
bellard579a97f2007-11-11 14:26:47 +00001838 unlock_user_struct(frame, frame_addr, 1);
bellard43fff232003-07-09 19:31:39 +00001839}
1840
pbrook624f7972008-05-31 16:11:38 +00001841static void setup_rt_frame(int usig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05001842 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01001843 target_sigset_t *set, CPUARMState *env)
pbrooka745ec62008-05-06 15:36:17 +00001844{
1845 if (get_osversion() >= 0x020612) {
1846 setup_rt_frame_v2(usig, ka, info, set, env);
1847 } else {
1848 setup_rt_frame_v1(usig, ka, info, set, env);
1849 }
1850}
1851
bellard43fff232003-07-09 19:31:39 +00001852static int
Andreas Färber05390242012-02-25 03:37:53 +01001853restore_sigcontext(CPUARMState *env, struct target_sigcontext *sc)
bellard43fff232003-07-09 19:31:39 +00001854{
1855 int err = 0;
bellardb5ff1b32005-11-26 10:38:39 +00001856 uint32_t cpsr;
bellard43fff232003-07-09 19:31:39 +00001857
Riku Voipio1d8b5122014-04-23 10:26:05 +03001858 __get_user(env->regs[0], &sc->arm_r0);
1859 __get_user(env->regs[1], &sc->arm_r1);
1860 __get_user(env->regs[2], &sc->arm_r2);
1861 __get_user(env->regs[3], &sc->arm_r3);
1862 __get_user(env->regs[4], &sc->arm_r4);
1863 __get_user(env->regs[5], &sc->arm_r5);
1864 __get_user(env->regs[6], &sc->arm_r6);
1865 __get_user(env->regs[7], &sc->arm_r7);
1866 __get_user(env->regs[8], &sc->arm_r8);
1867 __get_user(env->regs[9], &sc->arm_r9);
1868 __get_user(env->regs[10], &sc->arm_r10);
1869 __get_user(env->regs[11], &sc->arm_fp);
1870 __get_user(env->regs[12], &sc->arm_ip);
1871 __get_user(env->regs[13], &sc->arm_sp);
1872 __get_user(env->regs[14], &sc->arm_lr);
1873 __get_user(env->regs[15], &sc->arm_pc);
bellard43fff232003-07-09 19:31:39 +00001874#ifdef TARGET_CONFIG_CPU_32
Riku Voipio1d8b5122014-04-23 10:26:05 +03001875 __get_user(cpsr, &sc->arm_cpsr);
pbrook75b680e2008-03-21 16:07:30 +00001876 cpsr_write(env, cpsr, CPSR_USER | CPSR_EXEC);
bellard43fff232003-07-09 19:31:39 +00001877#endif
1878
1879 err |= !valid_user_regs(env);
1880
1881 return err;
1882}
1883
Andreas Färber05390242012-02-25 03:37:53 +01001884static long do_sigreturn_v1(CPUARMState *env)
bellard43fff232003-07-09 19:31:39 +00001885{
bellardf8b0aa22007-11-11 23:03:42 +00001886 abi_ulong frame_addr;
Peter Maydell978fae92013-07-29 12:00:32 +01001887 struct sigframe_v1 *frame = NULL;
Anthony Liguoric227f092009-10-01 16:12:16 -05001888 target_sigset_t set;
bellard43fff232003-07-09 19:31:39 +00001889 sigset_t host_set;
bellard92319442004-06-19 16:58:13 +00001890 int i;
bellard43fff232003-07-09 19:31:39 +00001891
1892 /*
1893 * Since we stacked the signal on a 64-bit boundary,
1894 * then 'sp' should be word aligned here. If it's
1895 * not, then the user is trying to mess with us.
1896 */
bellardf8b0aa22007-11-11 23:03:42 +00001897 frame_addr = env->regs[13];
Peter Maydell978fae92013-07-29 12:00:32 +01001898 if (frame_addr & 7) {
1899 goto badframe;
1900 }
1901
bellardf8b0aa22007-11-11 23:03:42 +00001902 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
1903 goto badframe;
bellard43fff232003-07-09 19:31:39 +00001904
bellard92319442004-06-19 16:58:13 +00001905 if (__get_user(set.sig[0], &frame->sc.oldmask))
1906 goto badframe;
1907 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
1908 if (__get_user(set.sig[i], &frame->extramask[i - 1]))
1909 goto badframe;
1910 }
bellard43fff232003-07-09 19:31:39 +00001911
bellard92319442004-06-19 16:58:13 +00001912 target_to_host_sigset_internal(&host_set, &set);
Alex Barcelo1c275922014-03-14 14:36:55 +00001913 do_sigprocmask(SIG_SETMASK, &host_set, NULL);
bellard43fff232003-07-09 19:31:39 +00001914
1915 if (restore_sigcontext(env, &frame->sc))
1916 goto badframe;
1917
1918#if 0
1919 /* Send SIGTRAP if we're single-stepping */
1920 if (ptrace_cancel_bpt(current))
1921 send_sig(SIGTRAP, current, 1);
1922#endif
bellardf8b0aa22007-11-11 23:03:42 +00001923 unlock_user_struct(frame, frame_addr, 0);
1924 return env->regs[0];
bellard43fff232003-07-09 19:31:39 +00001925
1926badframe:
bellardf8b0aa22007-11-11 23:03:42 +00001927 unlock_user_struct(frame, frame_addr, 0);
Riku Voipio66393fb2009-12-04 15:16:32 +02001928 force_sig(TARGET_SIGSEGV /* , current */);
bellard43fff232003-07-09 19:31:39 +00001929 return 0;
1930}
1931
Andreas Färber05390242012-02-25 03:37:53 +01001932static abi_ulong *restore_sigframe_v2_vfp(CPUARMState *env, abi_ulong *regspace)
Peter Maydell5f9099d2010-11-24 15:20:06 +00001933{
1934 int i;
1935 abi_ulong magic, sz;
1936 uint32_t fpscr, fpexc;
1937 struct target_vfp_sigframe *vfpframe;
1938 vfpframe = (struct target_vfp_sigframe *)regspace;
1939
1940 __get_user(magic, &vfpframe->magic);
1941 __get_user(sz, &vfpframe->size);
1942 if (magic != TARGET_VFP_MAGIC || sz != sizeof(*vfpframe)) {
1943 return 0;
1944 }
1945 for (i = 0; i < 32; i++) {
Peter Maydell005e1a02011-02-10 13:59:35 +00001946 __get_user(float64_val(env->vfp.regs[i]), &vfpframe->ufp.fpregs[i]);
Peter Maydell5f9099d2010-11-24 15:20:06 +00001947 }
1948 __get_user(fpscr, &vfpframe->ufp.fpscr);
1949 vfp_set_fpscr(env, fpscr);
1950 __get_user(fpexc, &vfpframe->ufp_exc.fpexc);
1951 /* Sanitise FPEXC: ensure VFP is enabled, FPINST2 is invalid
1952 * and the exception flag is cleared
1953 */
1954 fpexc |= (1 << 30);
1955 fpexc &= ~((1 << 31) | (1 << 28));
1956 env->vfp.xregs[ARM_VFP_FPEXC] = fpexc;
1957 __get_user(env->vfp.xregs[ARM_VFP_FPINST], &vfpframe->ufp_exc.fpinst);
1958 __get_user(env->vfp.xregs[ARM_VFP_FPINST2], &vfpframe->ufp_exc.fpinst2);
1959 return (abi_ulong*)(vfpframe + 1);
1960}
1961
Andreas Färber05390242012-02-25 03:37:53 +01001962static abi_ulong *restore_sigframe_v2_iwmmxt(CPUARMState *env,
1963 abi_ulong *regspace)
Peter Maydella59d69d2010-11-24 15:20:08 +00001964{
1965 int i;
1966 abi_ulong magic, sz;
1967 struct target_iwmmxt_sigframe *iwmmxtframe;
1968 iwmmxtframe = (struct target_iwmmxt_sigframe *)regspace;
1969
1970 __get_user(magic, &iwmmxtframe->magic);
1971 __get_user(sz, &iwmmxtframe->size);
1972 if (magic != TARGET_IWMMXT_MAGIC || sz != sizeof(*iwmmxtframe)) {
1973 return 0;
1974 }
1975 for (i = 0; i < 16; i++) {
1976 __get_user(env->iwmmxt.regs[i], &iwmmxtframe->regs[i]);
1977 }
1978 __get_user(env->vfp.xregs[ARM_IWMMXT_wCSSF], &iwmmxtframe->wcssf);
1979 __get_user(env->vfp.xregs[ARM_IWMMXT_wCASF], &iwmmxtframe->wcssf);
1980 __get_user(env->vfp.xregs[ARM_IWMMXT_wCGR0], &iwmmxtframe->wcgr0);
1981 __get_user(env->vfp.xregs[ARM_IWMMXT_wCGR1], &iwmmxtframe->wcgr1);
1982 __get_user(env->vfp.xregs[ARM_IWMMXT_wCGR2], &iwmmxtframe->wcgr2);
1983 __get_user(env->vfp.xregs[ARM_IWMMXT_wCGR3], &iwmmxtframe->wcgr3);
1984 return (abi_ulong*)(iwmmxtframe + 1);
1985}
1986
Andreas Färber05390242012-02-25 03:37:53 +01001987static int do_sigframe_return_v2(CPUARMState *env, target_ulong frame_addr,
pbrooka8c33202008-05-07 23:22:46 +00001988 struct target_ucontext_v2 *uc)
1989{
1990 sigset_t host_set;
Peter Maydell5f9099d2010-11-24 15:20:06 +00001991 abi_ulong *regspace;
pbrooka8c33202008-05-07 23:22:46 +00001992
1993 target_to_host_sigset(&host_set, &uc->tuc_sigmask);
Alex Barcelo1c275922014-03-14 14:36:55 +00001994 do_sigprocmask(SIG_SETMASK, &host_set, NULL);
pbrooka8c33202008-05-07 23:22:46 +00001995
1996 if (restore_sigcontext(env, &uc->tuc_mcontext))
1997 return 1;
1998
Peter Maydell5f9099d2010-11-24 15:20:06 +00001999 /* Restore coprocessor signal frame */
2000 regspace = uc->tuc_regspace;
2001 if (arm_feature(env, ARM_FEATURE_VFP)) {
2002 regspace = restore_sigframe_v2_vfp(env, regspace);
2003 if (!regspace) {
2004 return 1;
2005 }
2006 }
Peter Maydella59d69d2010-11-24 15:20:08 +00002007 if (arm_feature(env, ARM_FEATURE_IWMMXT)) {
2008 regspace = restore_sigframe_v2_iwmmxt(env, regspace);
2009 if (!regspace) {
2010 return 1;
2011 }
2012 }
Peter Maydell5f9099d2010-11-24 15:20:06 +00002013
pbrooka8c33202008-05-07 23:22:46 +00002014 if (do_sigaltstack(frame_addr + offsetof(struct target_ucontext_v2, tuc_stack), 0, get_sp_from_cpustate(env)) == -EFAULT)
2015 return 1;
2016
2017#if 0
2018 /* Send SIGTRAP if we're single-stepping */
2019 if (ptrace_cancel_bpt(current))
2020 send_sig(SIGTRAP, current, 1);
2021#endif
2022
2023 return 0;
2024}
2025
Andreas Färber05390242012-02-25 03:37:53 +01002026static long do_sigreturn_v2(CPUARMState *env)
pbrooka8c33202008-05-07 23:22:46 +00002027{
2028 abi_ulong frame_addr;
Peter Maydell978fae92013-07-29 12:00:32 +01002029 struct sigframe_v2 *frame = NULL;
pbrooka8c33202008-05-07 23:22:46 +00002030
2031 /*
2032 * Since we stacked the signal on a 64-bit boundary,
2033 * then 'sp' should be word aligned here. If it's
2034 * not, then the user is trying to mess with us.
2035 */
pbrooka8c33202008-05-07 23:22:46 +00002036 frame_addr = env->regs[13];
Peter Maydell978fae92013-07-29 12:00:32 +01002037 if (frame_addr & 7) {
2038 goto badframe;
2039 }
2040
pbrooka8c33202008-05-07 23:22:46 +00002041 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
2042 goto badframe;
2043
2044 if (do_sigframe_return_v2(env, frame_addr, &frame->uc))
2045 goto badframe;
2046
2047 unlock_user_struct(frame, frame_addr, 0);
2048 return env->regs[0];
2049
2050badframe:
2051 unlock_user_struct(frame, frame_addr, 0);
Riku Voipio66393fb2009-12-04 15:16:32 +02002052 force_sig(TARGET_SIGSEGV /* , current */);
pbrooka8c33202008-05-07 23:22:46 +00002053 return 0;
2054}
2055
Andreas Färber05390242012-02-25 03:37:53 +01002056long do_sigreturn(CPUARMState *env)
pbrooka8c33202008-05-07 23:22:46 +00002057{
2058 if (get_osversion() >= 0x020612) {
2059 return do_sigreturn_v2(env);
2060 } else {
2061 return do_sigreturn_v1(env);
2062 }
2063}
2064
Andreas Färber05390242012-02-25 03:37:53 +01002065static long do_rt_sigreturn_v1(CPUARMState *env)
bellard43fff232003-07-09 19:31:39 +00002066{
bellardf8b0aa22007-11-11 23:03:42 +00002067 abi_ulong frame_addr;
Peter Maydell978fae92013-07-29 12:00:32 +01002068 struct rt_sigframe_v1 *frame = NULL;
bellard43fff232003-07-09 19:31:39 +00002069 sigset_t host_set;
2070
2071 /*
2072 * Since we stacked the signal on a 64-bit boundary,
2073 * then 'sp' should be word aligned here. If it's
2074 * not, then the user is trying to mess with us.
2075 */
bellardf8b0aa22007-11-11 23:03:42 +00002076 frame_addr = env->regs[13];
Peter Maydell978fae92013-07-29 12:00:32 +01002077 if (frame_addr & 7) {
2078 goto badframe;
2079 }
2080
bellardf8b0aa22007-11-11 23:03:42 +00002081 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
2082 goto badframe;
bellard43fff232003-07-09 19:31:39 +00002083
bellardb8076a72005-04-07 22:20:31 +00002084 target_to_host_sigset(&host_set, &frame->uc.tuc_sigmask);
Alex Barcelo1c275922014-03-14 14:36:55 +00002085 do_sigprocmask(SIG_SETMASK, &host_set, NULL);
bellard43fff232003-07-09 19:31:39 +00002086
bellardb8076a72005-04-07 22:20:31 +00002087 if (restore_sigcontext(env, &frame->uc.tuc_mcontext))
bellard43fff232003-07-09 19:31:39 +00002088 goto badframe;
2089
pbrooka745ec62008-05-06 15:36:17 +00002090 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 +00002091 goto badframe;
2092
bellard43fff232003-07-09 19:31:39 +00002093#if 0
2094 /* Send SIGTRAP if we're single-stepping */
2095 if (ptrace_cancel_bpt(current))
2096 send_sig(SIGTRAP, current, 1);
2097#endif
bellardf8b0aa22007-11-11 23:03:42 +00002098 unlock_user_struct(frame, frame_addr, 0);
bellard43fff232003-07-09 19:31:39 +00002099 return env->regs[0];
2100
2101badframe:
bellardf8b0aa22007-11-11 23:03:42 +00002102 unlock_user_struct(frame, frame_addr, 0);
Riku Voipio66393fb2009-12-04 15:16:32 +02002103 force_sig(TARGET_SIGSEGV /* , current */);
bellard43fff232003-07-09 19:31:39 +00002104 return 0;
2105}
2106
Andreas Färber05390242012-02-25 03:37:53 +01002107static long do_rt_sigreturn_v2(CPUARMState *env)
pbrooka745ec62008-05-06 15:36:17 +00002108{
2109 abi_ulong frame_addr;
Peter Maydell978fae92013-07-29 12:00:32 +01002110 struct rt_sigframe_v2 *frame = NULL;
pbrooka745ec62008-05-06 15:36:17 +00002111
2112 /*
2113 * Since we stacked the signal on a 64-bit boundary,
2114 * then 'sp' should be word aligned here. If it's
2115 * not, then the user is trying to mess with us.
2116 */
pbrooka745ec62008-05-06 15:36:17 +00002117 frame_addr = env->regs[13];
Peter Maydell978fae92013-07-29 12:00:32 +01002118 if (frame_addr & 7) {
2119 goto badframe;
2120 }
2121
pbrooka745ec62008-05-06 15:36:17 +00002122 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
2123 goto badframe;
2124
pbrooka8c33202008-05-07 23:22:46 +00002125 if (do_sigframe_return_v2(env, frame_addr, &frame->uc))
2126 goto badframe;
pbrooka745ec62008-05-06 15:36:17 +00002127
pbrooka745ec62008-05-06 15:36:17 +00002128 unlock_user_struct(frame, frame_addr, 0);
2129 return env->regs[0];
2130
2131badframe:
2132 unlock_user_struct(frame, frame_addr, 0);
Riku Voipio66393fb2009-12-04 15:16:32 +02002133 force_sig(TARGET_SIGSEGV /* , current */);
pbrooka745ec62008-05-06 15:36:17 +00002134 return 0;
2135}
2136
Andreas Färber05390242012-02-25 03:37:53 +01002137long do_rt_sigreturn(CPUARMState *env)
pbrooka745ec62008-05-06 15:36:17 +00002138{
2139 if (get_osversion() >= 0x020612) {
2140 return do_rt_sigreturn_v2(env);
2141 } else {
2142 return do_rt_sigreturn_v1(env);
2143 }
2144}
2145
bellard6d5e2162004-09-30 22:04:13 +00002146#elif defined(TARGET_SPARC)
bellard80a9d032005-01-03 23:31:27 +00002147
bellard6d5e2162004-09-30 22:04:13 +00002148#define __SUNOS_MAXWIN 31
2149
2150/* This is what SunOS does, so shall I. */
2151struct target_sigcontext {
blueswir1992f48a2007-10-14 16:27:31 +00002152 abi_ulong sigc_onstack; /* state to restore */
bellard6d5e2162004-09-30 22:04:13 +00002153
blueswir1992f48a2007-10-14 16:27:31 +00002154 abi_ulong sigc_mask; /* sigmask to restore */
2155 abi_ulong sigc_sp; /* stack pointer */
2156 abi_ulong sigc_pc; /* program counter */
2157 abi_ulong sigc_npc; /* next program counter */
2158 abi_ulong sigc_psr; /* for condition codes etc */
2159 abi_ulong sigc_g1; /* User uses these two registers */
2160 abi_ulong sigc_o0; /* within the trampoline code. */
bellard6d5e2162004-09-30 22:04:13 +00002161
2162 /* Now comes information regarding the users window set
2163 * at the time of the signal.
2164 */
blueswir1992f48a2007-10-14 16:27:31 +00002165 abi_ulong sigc_oswins; /* outstanding windows */
bellard6d5e2162004-09-30 22:04:13 +00002166
2167 /* stack ptrs for each regwin buf */
2168 char *sigc_spbuf[__SUNOS_MAXWIN];
2169
2170 /* Windows to restore after signal */
2171 struct {
blueswir1992f48a2007-10-14 16:27:31 +00002172 abi_ulong locals[8];
2173 abi_ulong ins[8];
bellard6d5e2162004-09-30 22:04:13 +00002174 } sigc_wbuf[__SUNOS_MAXWIN];
2175};
2176/* A Sparc stack frame */
2177struct sparc_stackf {
blueswir1992f48a2007-10-14 16:27:31 +00002178 abi_ulong locals[8];
Peter Maydelle321c342011-02-01 15:54:52 +00002179 abi_ulong ins[8];
2180 /* It's simpler to treat fp and callers_pc as elements of ins[]
2181 * since we never need to access them ourselves.
2182 */
bellard6d5e2162004-09-30 22:04:13 +00002183 char *structptr;
blueswir1992f48a2007-10-14 16:27:31 +00002184 abi_ulong xargs[6];
2185 abi_ulong xxargs[1];
bellard6d5e2162004-09-30 22:04:13 +00002186};
2187
2188typedef struct {
2189 struct {
blueswir1992f48a2007-10-14 16:27:31 +00002190 abi_ulong psr;
2191 abi_ulong pc;
2192 abi_ulong npc;
2193 abi_ulong y;
2194 abi_ulong u_regs[16]; /* globals and ins */
bellard6d5e2162004-09-30 22:04:13 +00002195 } si_regs;
2196 int si_mask;
2197} __siginfo_t;
2198
2199typedef struct {
Blue Swirl8954bae2012-07-30 15:29:11 +00002200 abi_ulong si_float_regs[32];
bellard6d5e2162004-09-30 22:04:13 +00002201 unsigned long si_fsr;
2202 unsigned long si_fpqdepth;
2203 struct {
2204 unsigned long *insn_addr;
2205 unsigned long insn;
2206 } si_fpqueue [16];
Anthony Liguoric227f092009-10-01 16:12:16 -05002207} qemu_siginfo_fpu_t;
bellard6d5e2162004-09-30 22:04:13 +00002208
2209
2210struct target_signal_frame {
2211 struct sparc_stackf ss;
2212 __siginfo_t info;
bellardf8b0aa22007-11-11 23:03:42 +00002213 abi_ulong fpu_save;
blueswir1992f48a2007-10-14 16:27:31 +00002214 abi_ulong insns[2] __attribute__ ((aligned (8)));
2215 abi_ulong extramask[TARGET_NSIG_WORDS - 1];
2216 abi_ulong 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};
2219struct target_rt_signal_frame {
2220 struct sparc_stackf ss;
2221 siginfo_t info;
blueswir1992f48a2007-10-14 16:27:31 +00002222 abi_ulong regs[20];
bellard6d5e2162004-09-30 22:04:13 +00002223 sigset_t mask;
bellardf8b0aa22007-11-11 23:03:42 +00002224 abi_ulong fpu_save;
bellard6d5e2162004-09-30 22:04:13 +00002225 unsigned int insns[2];
2226 stack_t stack;
2227 unsigned int extra_size; /* Should be 0 */
Anthony Liguoric227f092009-10-01 16:12:16 -05002228 qemu_siginfo_fpu_t fpu_state;
bellard6d5e2162004-09-30 22:04:13 +00002229};
2230
bellarde80cfcf2004-12-19 23:18:01 +00002231#define UREG_O0 16
2232#define UREG_O6 22
2233#define UREG_I0 0
2234#define UREG_I1 1
2235#define UREG_I2 2
blueswir15bfb56b2007-10-05 17:01:51 +00002236#define UREG_I3 3
2237#define UREG_I4 4
2238#define UREG_I5 5
bellarde80cfcf2004-12-19 23:18:01 +00002239#define UREG_I6 6
2240#define UREG_I7 7
2241#define UREG_L0 8
bellard6d5e2162004-09-30 22:04:13 +00002242#define UREG_FP UREG_I6
2243#define UREG_SP UREG_O6
2244
pbrook624f7972008-05-31 16:11:38 +00002245static inline abi_ulong get_sigframe(struct target_sigaction *sa,
Andreas Färber05390242012-02-25 03:37:53 +01002246 CPUSPARCState *env,
2247 unsigned long framesize)
bellard6d5e2162004-09-30 22:04:13 +00002248{
bellard459a4012007-11-11 19:45:10 +00002249 abi_ulong sp;
bellard6d5e2162004-09-30 22:04:13 +00002250
2251 sp = env->regwptr[UREG_FP];
bellard6d5e2162004-09-30 22:04:13 +00002252
2253 /* This is the X/Open sanctioned signal stack switching. */
pbrook624f7972008-05-31 16:11:38 +00002254 if (sa->sa_flags & TARGET_SA_ONSTACK) {
thsa04e1342007-09-27 13:57:58 +00002255 if (!on_sig_stack(sp)
2256 && !((target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size) & 7))
2257 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
bellard6d5e2162004-09-30 22:04:13 +00002258 }
bellard459a4012007-11-11 19:45:10 +00002259 return sp - framesize;
bellard6d5e2162004-09-30 22:04:13 +00002260}
2261
2262static int
Andreas Färber05390242012-02-25 03:37:53 +01002263setup___siginfo(__siginfo_t *si, CPUSPARCState *env, abi_ulong mask)
bellard6d5e2162004-09-30 22:04:13 +00002264{
2265 int err = 0, i;
2266
Riku Voipio1d8b5122014-04-23 10:26:05 +03002267 __put_user(env->psr, &si->si_regs.psr);
2268 __put_user(env->pc, &si->si_regs.pc);
2269 __put_user(env->npc, &si->si_regs.npc);
2270 __put_user(env->y, &si->si_regs.y);
bellarda315a142005-01-30 22:59:18 +00002271 for (i=0; i < 8; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002272 __put_user(env->gregs[i], &si->si_regs.u_regs[i]);
bellard6d5e2162004-09-30 22:04:13 +00002273 }
bellarda315a142005-01-30 22:59:18 +00002274 for (i=0; i < 8; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002275 __put_user(env->regwptr[UREG_I0 + i], &si->si_regs.u_regs[i+8]);
bellard6d5e2162004-09-30 22:04:13 +00002276 }
Riku Voipio1d8b5122014-04-23 10:26:05 +03002277 __put_user(mask, &si->si_mask);
bellard6d5e2162004-09-30 22:04:13 +00002278 return err;
2279}
bellarde80cfcf2004-12-19 23:18:01 +00002280
bellard80a9d032005-01-03 23:31:27 +00002281#if 0
bellard6d5e2162004-09-30 22:04:13 +00002282static int
2283setup_sigcontext(struct target_sigcontext *sc, /*struct _fpstate *fpstate,*/
Andreas Färber05390242012-02-25 03:37:53 +01002284 CPUSPARCState *env, unsigned long mask)
bellard6d5e2162004-09-30 22:04:13 +00002285{
2286 int err = 0;
2287
Riku Voipio1d8b5122014-04-23 10:26:05 +03002288 __put_user(mask, &sc->sigc_mask);
2289 __put_user(env->regwptr[UREG_SP], &sc->sigc_sp);
2290 __put_user(env->pc, &sc->sigc_pc);
2291 __put_user(env->npc, &sc->sigc_npc);
2292 __put_user(env->psr, &sc->sigc_psr);
2293 __put_user(env->gregs[1], &sc->sigc_g1);
2294 __put_user(env->regwptr[UREG_O0], &sc->sigc_o0);
bellard6d5e2162004-09-30 22:04:13 +00002295
2296 return err;
2297}
bellard80a9d032005-01-03 23:31:27 +00002298#endif
bellard6d5e2162004-09-30 22:04:13 +00002299#define NF_ALIGNEDSZ (((sizeof(struct target_signal_frame) + 7) & (~7)))
2300
pbrook624f7972008-05-31 16:11:38 +00002301static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01002302 target_sigset_t *set, CPUSPARCState *env)
bellard6d5e2162004-09-30 22:04:13 +00002303{
bellard459a4012007-11-11 19:45:10 +00002304 abi_ulong sf_addr;
bellard6d5e2162004-09-30 22:04:13 +00002305 struct target_signal_frame *sf;
2306 int sigframe_size, err, i;
2307
2308 /* 1. Make sure everything is clean */
2309 //synchronize_user_stack();
2310
2311 sigframe_size = NF_ALIGNEDSZ;
bellard459a4012007-11-11 19:45:10 +00002312 sf_addr = get_sigframe(ka, env, sigframe_size);
bellard6d5e2162004-09-30 22:04:13 +00002313
bellard459a4012007-11-11 19:45:10 +00002314 sf = lock_user(VERIFY_WRITE, sf_addr,
2315 sizeof(struct target_signal_frame), 0);
2316 if (!sf)
2317 goto sigsegv;
2318
bellarde80cfcf2004-12-19 23:18:01 +00002319 //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 +00002320#if 0
2321 if (invalid_frame_pointer(sf, sigframe_size))
2322 goto sigill_and_return;
2323#endif
2324 /* 2. Save the current process state */
2325 err = setup___siginfo(&sf->info, env, set->sig[0]);
Riku Voipio1d8b5122014-04-23 10:26:05 +03002326 __put_user(0, &sf->extra_size);
bellard6d5e2162004-09-30 22:04:13 +00002327
Riku Voipio1d8b5122014-04-23 10:26:05 +03002328 //save_fpu_state(regs, &sf->fpu_state);
2329 //__put_user(&sf->fpu_state, &sf->fpu_save);
bellard6d5e2162004-09-30 22:04:13 +00002330
Riku Voipio1d8b5122014-04-23 10:26:05 +03002331 __put_user(set->sig[0], &sf->info.si_mask);
bellard6d5e2162004-09-30 22:04:13 +00002332 for (i = 0; i < TARGET_NSIG_WORDS - 1; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002333 __put_user(set->sig[i + 1], &sf->extramask[i]);
bellard6d5e2162004-09-30 22:04:13 +00002334 }
2335
bellarda315a142005-01-30 22:59:18 +00002336 for (i = 0; i < 8; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002337 __put_user(env->regwptr[i + UREG_L0], &sf->ss.locals[i]);
bellard6d5e2162004-09-30 22:04:13 +00002338 }
bellarda315a142005-01-30 22:59:18 +00002339 for (i = 0; i < 8; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002340 __put_user(env->regwptr[i + UREG_I0], &sf->ss.ins[i]);
bellard6d5e2162004-09-30 22:04:13 +00002341 }
bellard6d5e2162004-09-30 22:04:13 +00002342 if (err)
2343 goto sigsegv;
2344
2345 /* 3. signal handler back-trampoline and parameters */
bellard459a4012007-11-11 19:45:10 +00002346 env->regwptr[UREG_FP] = sf_addr;
bellard6d5e2162004-09-30 22:04:13 +00002347 env->regwptr[UREG_I0] = sig;
bellard459a4012007-11-11 19:45:10 +00002348 env->regwptr[UREG_I1] = sf_addr +
2349 offsetof(struct target_signal_frame, info);
2350 env->regwptr[UREG_I2] = sf_addr +
2351 offsetof(struct target_signal_frame, info);
bellard6d5e2162004-09-30 22:04:13 +00002352
2353 /* 4. signal handler */
pbrook624f7972008-05-31 16:11:38 +00002354 env->pc = ka->_sa_handler;
bellard6d5e2162004-09-30 22:04:13 +00002355 env->npc = (env->pc + 4);
2356 /* 5. return to kernel instructions */
pbrook624f7972008-05-31 16:11:38 +00002357 if (ka->sa_restorer)
2358 env->regwptr[UREG_I7] = ka->sa_restorer;
bellard6d5e2162004-09-30 22:04:13 +00002359 else {
bellard775b58d2007-11-11 16:22:17 +00002360 uint32_t val32;
bellard459a4012007-11-11 19:45:10 +00002361
2362 env->regwptr[UREG_I7] = sf_addr +
2363 offsetof(struct target_signal_frame, insns) - 2 * 4;
bellard6d5e2162004-09-30 22:04:13 +00002364
2365 /* mov __NR_sigreturn, %g1 */
bellard775b58d2007-11-11 16:22:17 +00002366 val32 = 0x821020d8;
Riku Voipio1d8b5122014-04-23 10:26:05 +03002367 __put_user(val32, &sf->insns[0]);
bellard6d5e2162004-09-30 22:04:13 +00002368
2369 /* t 0x10 */
bellard775b58d2007-11-11 16:22:17 +00002370 val32 = 0x91d02010;
Riku Voipio1d8b5122014-04-23 10:26:05 +03002371 __put_user(val32, &sf->insns[1]);
bellard6d5e2162004-09-30 22:04:13 +00002372 if (err)
2373 goto sigsegv;
2374
2375 /* Flush instruction space. */
2376 //flush_sig_insns(current->mm, (unsigned long) &(sf->insns[0]));
bellard80a9d032005-01-03 23:31:27 +00002377 // tb_flush(env);
bellard6d5e2162004-09-30 22:04:13 +00002378 }
bellard459a4012007-11-11 19:45:10 +00002379 unlock_user(sf, sf_addr, sizeof(struct target_signal_frame));
bellard6d5e2162004-09-30 22:04:13 +00002380 return;
bellard459a4012007-11-11 19:45:10 +00002381#if 0
2382sigill_and_return:
bellard6d5e2162004-09-30 22:04:13 +00002383 force_sig(TARGET_SIGILL);
bellard459a4012007-11-11 19:45:10 +00002384#endif
bellard6d5e2162004-09-30 22:04:13 +00002385sigsegv:
bellarde80cfcf2004-12-19 23:18:01 +00002386 //fprintf(stderr, "force_sig\n");
bellard459a4012007-11-11 19:45:10 +00002387 unlock_user(sf, sf_addr, sizeof(struct target_signal_frame));
bellard6d5e2162004-09-30 22:04:13 +00002388 force_sig(TARGET_SIGSEGV);
2389}
2390static inline int
Andreas Färber05390242012-02-25 03:37:53 +01002391restore_fpu_state(CPUSPARCState *env, qemu_siginfo_fpu_t *fpu)
bellard6d5e2162004-09-30 22:04:13 +00002392{
2393 int err;
2394#if 0
2395#ifdef CONFIG_SMP
2396 if (current->flags & PF_USEDFPU)
2397 regs->psr &= ~PSR_EF;
2398#else
2399 if (current == last_task_used_math) {
2400 last_task_used_math = 0;
2401 regs->psr &= ~PSR_EF;
2402 }
2403#endif
2404 current->used_math = 1;
2405 current->flags &= ~PF_USEDFPU;
2406#endif
2407#if 0
2408 if (verify_area (VERIFY_READ, fpu, sizeof(*fpu)))
2409 return -EFAULT;
2410#endif
2411
bellardfafffae2006-10-28 12:09:16 +00002412 /* XXX: incorrect */
Blue Swirl8954bae2012-07-30 15:29:11 +00002413 err = copy_from_user(&env->fpr[0], fpu->si_float_regs[0],
2414 (sizeof(abi_ulong) * 32));
bellard6d5e2162004-09-30 22:04:13 +00002415 err |= __get_user(env->fsr, &fpu->si_fsr);
2416#if 0
2417 err |= __get_user(current->thread.fpqdepth, &fpu->si_fpqdepth);
2418 if (current->thread.fpqdepth != 0)
2419 err |= __copy_from_user(&current->thread.fpqueue[0],
2420 &fpu->si_fpqueue[0],
2421 ((sizeof(unsigned long) +
2422 (sizeof(unsigned long *)))*16));
2423#endif
2424 return err;
2425}
2426
2427
pbrook624f7972008-05-31 16:11:38 +00002428static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05002429 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01002430 target_sigset_t *set, CPUSPARCState *env)
bellard6d5e2162004-09-30 22:04:13 +00002431{
2432 fprintf(stderr, "setup_rt_frame: not implemented\n");
2433}
2434
Andreas Färber05390242012-02-25 03:37:53 +01002435long do_sigreturn(CPUSPARCState *env)
bellard6d5e2162004-09-30 22:04:13 +00002436{
bellardf8b0aa22007-11-11 23:03:42 +00002437 abi_ulong sf_addr;
bellard6d5e2162004-09-30 22:04:13 +00002438 struct target_signal_frame *sf;
bellarde80cfcf2004-12-19 23:18:01 +00002439 uint32_t up_psr, pc, npc;
Anthony Liguoric227f092009-10-01 16:12:16 -05002440 target_sigset_t set;
bellarde80cfcf2004-12-19 23:18:01 +00002441 sigset_t host_set;
Riku Voipio1d8b5122014-04-23 10:26:05 +03002442 int err=0, i;
bellard6d5e2162004-09-30 22:04:13 +00002443
bellardf8b0aa22007-11-11 23:03:42 +00002444 sf_addr = env->regwptr[UREG_FP];
2445 if (!lock_user_struct(VERIFY_READ, sf, sf_addr, 1))
2446 goto segv_and_exit;
bellard80a9d032005-01-03 23:31:27 +00002447#if 0
bellarde80cfcf2004-12-19 23:18:01 +00002448 fprintf(stderr, "sigreturn\n");
2449 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 +00002450#endif
bellarde80cfcf2004-12-19 23:18:01 +00002451 //cpu_dump_state(env, stderr, fprintf, 0);
bellard6d5e2162004-09-30 22:04:13 +00002452
2453 /* 1. Make sure we are not getting garbage from the user */
bellard6d5e2162004-09-30 22:04:13 +00002454
bellardf8b0aa22007-11-11 23:03:42 +00002455 if (sf_addr & 3)
bellard6d5e2162004-09-30 22:04:13 +00002456 goto segv_and_exit;
2457
Riku Voipio1d8b5122014-04-23 10:26:05 +03002458 __get_user(pc, &sf->info.si_regs.pc);
2459 __get_user(npc, &sf->info.si_regs.npc);
bellard6d5e2162004-09-30 22:04:13 +00002460
bellard6d5e2162004-09-30 22:04:13 +00002461 if ((pc | npc) & 3)
2462 goto segv_and_exit;
2463
2464 /* 2. Restore the state */
Riku Voipio1d8b5122014-04-23 10:26:05 +03002465 __get_user(up_psr, &sf->info.si_regs.psr);
bellarde80cfcf2004-12-19 23:18:01 +00002466
bellard6d5e2162004-09-30 22:04:13 +00002467 /* User can only change condition codes and FPU enabling in %psr. */
bellarda315a142005-01-30 22:59:18 +00002468 env->psr = (up_psr & (PSR_ICC /* | PSR_EF */))
2469 | (env->psr & ~(PSR_ICC /* | PSR_EF */));
2470
2471 env->pc = pc;
2472 env->npc = npc;
Riku Voipio1d8b5122014-04-23 10:26:05 +03002473 __get_user(env->y, &sf->info.si_regs.y);
bellarda315a142005-01-30 22:59:18 +00002474 for (i=0; i < 8; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002475 __get_user(env->gregs[i], &sf->info.si_regs.u_regs[i]);
bellarde80cfcf2004-12-19 23:18:01 +00002476 }
bellarda315a142005-01-30 22:59:18 +00002477 for (i=0; i < 8; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002478 __get_user(env->regwptr[i + UREG_I0], &sf->info.si_regs.u_regs[i+8]);
bellarde80cfcf2004-12-19 23:18:01 +00002479 }
bellard6d5e2162004-09-30 22:04:13 +00002480
Peter Maydell2aec3a22011-06-16 17:37:14 +01002481 /* FIXME: implement FPU save/restore:
2482 * __get_user(fpu_save, &sf->fpu_save);
2483 * if (fpu_save)
2484 * err |= restore_fpu_state(env, fpu_save);
2485 */
bellard6d5e2162004-09-30 22:04:13 +00002486
2487 /* This is pretty much atomic, no amount locking would prevent
2488 * the races which exist anyways.
2489 */
Riku Voipio1d8b5122014-04-23 10:26:05 +03002490 __get_user(set.sig[0], &sf->info.si_mask);
bellarde80cfcf2004-12-19 23:18:01 +00002491 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002492 __get_user(set.sig[i], &sf->extramask[i - 1]);
bellarde80cfcf2004-12-19 23:18:01 +00002493 }
2494
2495 target_to_host_sigset_internal(&host_set, &set);
Alex Barcelo1c275922014-03-14 14:36:55 +00002496 do_sigprocmask(SIG_SETMASK, &host_set, NULL);
bellard6d5e2162004-09-30 22:04:13 +00002497
2498 if (err)
2499 goto segv_and_exit;
bellardf8b0aa22007-11-11 23:03:42 +00002500 unlock_user_struct(sf, sf_addr, 0);
bellard6d5e2162004-09-30 22:04:13 +00002501 return env->regwptr[0];
2502
2503segv_and_exit:
bellardf8b0aa22007-11-11 23:03:42 +00002504 unlock_user_struct(sf, sf_addr, 0);
bellard6d5e2162004-09-30 22:04:13 +00002505 force_sig(TARGET_SIGSEGV);
2506}
2507
Andreas Färber05390242012-02-25 03:37:53 +01002508long do_rt_sigreturn(CPUSPARCState *env)
bellard6d5e2162004-09-30 22:04:13 +00002509{
2510 fprintf(stderr, "do_rt_sigreturn: not implemented\n");
bellardf8b0aa22007-11-11 23:03:42 +00002511 return -TARGET_ENOSYS;
bellard6d5e2162004-09-30 22:04:13 +00002512}
2513
bellard459a4012007-11-11 19:45:10 +00002514#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
blueswir15bfb56b2007-10-05 17:01:51 +00002515#define MC_TSTATE 0
2516#define MC_PC 1
2517#define MC_NPC 2
2518#define MC_Y 3
2519#define MC_G1 4
2520#define MC_G2 5
2521#define MC_G3 6
2522#define MC_G4 7
2523#define MC_G5 8
2524#define MC_G6 9
2525#define MC_G7 10
2526#define MC_O0 11
2527#define MC_O1 12
2528#define MC_O2 13
2529#define MC_O3 14
2530#define MC_O4 15
2531#define MC_O5 16
2532#define MC_O6 17
2533#define MC_O7 18
2534#define MC_NGREG 19
2535
Anthony Liguoric227f092009-10-01 16:12:16 -05002536typedef abi_ulong target_mc_greg_t;
2537typedef target_mc_greg_t target_mc_gregset_t[MC_NGREG];
blueswir15bfb56b2007-10-05 17:01:51 +00002538
2539struct target_mc_fq {
blueswir1992f48a2007-10-14 16:27:31 +00002540 abi_ulong *mcfq_addr;
blueswir15bfb56b2007-10-05 17:01:51 +00002541 uint32_t mcfq_insn;
2542};
2543
2544struct target_mc_fpu {
2545 union {
2546 uint32_t sregs[32];
2547 uint64_t dregs[32];
2548 //uint128_t qregs[16];
2549 } mcfpu_fregs;
blueswir1992f48a2007-10-14 16:27:31 +00002550 abi_ulong mcfpu_fsr;
2551 abi_ulong mcfpu_fprs;
2552 abi_ulong mcfpu_gsr;
blueswir15bfb56b2007-10-05 17:01:51 +00002553 struct target_mc_fq *mcfpu_fq;
2554 unsigned char mcfpu_qcnt;
2555 unsigned char mcfpu_qentsz;
2556 unsigned char mcfpu_enab;
2557};
Anthony Liguoric227f092009-10-01 16:12:16 -05002558typedef struct target_mc_fpu target_mc_fpu_t;
blueswir15bfb56b2007-10-05 17:01:51 +00002559
2560typedef struct {
Anthony Liguoric227f092009-10-01 16:12:16 -05002561 target_mc_gregset_t mc_gregs;
2562 target_mc_greg_t mc_fp;
2563 target_mc_greg_t mc_i7;
2564 target_mc_fpu_t mc_fpregs;
2565} target_mcontext_t;
blueswir15bfb56b2007-10-05 17:01:51 +00002566
2567struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02002568 struct target_ucontext *tuc_link;
2569 abi_ulong tuc_flags;
2570 target_sigset_t tuc_sigmask;
2571 target_mcontext_t tuc_mcontext;
blueswir15bfb56b2007-10-05 17:01:51 +00002572};
2573
2574/* A V9 register window */
2575struct target_reg_window {
blueswir1992f48a2007-10-14 16:27:31 +00002576 abi_ulong locals[8];
2577 abi_ulong ins[8];
blueswir15bfb56b2007-10-05 17:01:51 +00002578};
2579
2580#define TARGET_STACK_BIAS 2047
2581
2582/* {set, get}context() needed for 64-bit SparcLinux userland. */
2583void sparc64_set_context(CPUSPARCState *env)
2584{
bellard459a4012007-11-11 19:45:10 +00002585 abi_ulong ucp_addr;
2586 struct target_ucontext *ucp;
Anthony Liguoric227f092009-10-01 16:12:16 -05002587 target_mc_gregset_t *grp;
blueswir1992f48a2007-10-14 16:27:31 +00002588 abi_ulong pc, npc, tstate;
bellard459a4012007-11-11 19:45:10 +00002589 abi_ulong fp, i7, w_addr;
Riku Voipio1d8b5122014-04-23 10:26:05 +03002590 int err = 0;
blueswir15bfb56b2007-10-05 17:01:51 +00002591 unsigned int i;
blueswir15bfb56b2007-10-05 17:01:51 +00002592
bellard459a4012007-11-11 19:45:10 +00002593 ucp_addr = env->regwptr[UREG_I0];
2594 if (!lock_user_struct(VERIFY_READ, ucp, ucp_addr, 1))
2595 goto do_sigsegv;
Aurelien Jarno60e99242010-03-29 02:12:51 +02002596 grp = &ucp->tuc_mcontext.mc_gregs;
Riku Voipio1d8b5122014-04-23 10:26:05 +03002597 __get_user(pc, &((*grp)[MC_PC]));
2598 __get_user(npc, &((*grp)[MC_NPC]));
blueswir15bfb56b2007-10-05 17:01:51 +00002599 if (err || ((pc | npc) & 3))
2600 goto do_sigsegv;
2601 if (env->regwptr[UREG_I1]) {
Anthony Liguoric227f092009-10-01 16:12:16 -05002602 target_sigset_t target_set;
blueswir15bfb56b2007-10-05 17:01:51 +00002603 sigset_t set;
2604
2605 if (TARGET_NSIG_WORDS == 1) {
Aurelien Jarno60e99242010-03-29 02:12:51 +02002606 if (__get_user(target_set.sig[0], &ucp->tuc_sigmask.sig[0]))
blueswir15bfb56b2007-10-05 17:01:51 +00002607 goto do_sigsegv;
2608 } else {
bellard459a4012007-11-11 19:45:10 +00002609 abi_ulong *src, *dst;
Aurelien Jarno60e99242010-03-29 02:12:51 +02002610 src = ucp->tuc_sigmask.sig;
bellard459a4012007-11-11 19:45:10 +00002611 dst = target_set.sig;
Stefan Weil0d9e61c2013-12-07 14:48:08 +01002612 for (i = 0; i < TARGET_NSIG_WORDS; i++, dst++, src++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002613 __get_user(*dst, src);
Stefan Weil0d9e61c2013-12-07 14:48:08 +01002614 }
blueswir15bfb56b2007-10-05 17:01:51 +00002615 if (err)
2616 goto do_sigsegv;
2617 }
2618 target_to_host_sigset_internal(&set, &target_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00002619 do_sigprocmask(SIG_SETMASK, &set, NULL);
blueswir15bfb56b2007-10-05 17:01:51 +00002620 }
2621 env->pc = pc;
2622 env->npc = npc;
Riku Voipio1d8b5122014-04-23 10:26:05 +03002623 __get_user(env->y, &((*grp)[MC_Y]));
2624 __get_user(tstate, &((*grp)[MC_TSTATE]));
blueswir15bfb56b2007-10-05 17:01:51 +00002625 env->asi = (tstate >> 24) & 0xff;
Blue Swirl5a834bb2010-05-09 20:19:04 +00002626 cpu_put_ccr(env, tstate >> 32);
2627 cpu_put_cwp64(env, tstate & 0x1f);
Riku Voipio1d8b5122014-04-23 10:26:05 +03002628 __get_user(env->gregs[1], (&(*grp)[MC_G1]));
2629 __get_user(env->gregs[2], (&(*grp)[MC_G2]));
2630 __get_user(env->gregs[3], (&(*grp)[MC_G3]));
2631 __get_user(env->gregs[4], (&(*grp)[MC_G4]));
2632 __get_user(env->gregs[5], (&(*grp)[MC_G5]));
2633 __get_user(env->gregs[6], (&(*grp)[MC_G6]));
2634 __get_user(env->gregs[7], (&(*grp)[MC_G7]));
2635 __get_user(env->regwptr[UREG_I0], (&(*grp)[MC_O0]));
2636 __get_user(env->regwptr[UREG_I1], (&(*grp)[MC_O1]));
2637 __get_user(env->regwptr[UREG_I2], (&(*grp)[MC_O2]));
2638 __get_user(env->regwptr[UREG_I3], (&(*grp)[MC_O3]));
2639 __get_user(env->regwptr[UREG_I4], (&(*grp)[MC_O4]));
2640 __get_user(env->regwptr[UREG_I5], (&(*grp)[MC_O5]));
2641 __get_user(env->regwptr[UREG_I6], (&(*grp)[MC_O6]));
2642 __get_user(env->regwptr[UREG_I7], (&(*grp)[MC_O7]));
blueswir15bfb56b2007-10-05 17:01:51 +00002643
Riku Voipio1d8b5122014-04-23 10:26:05 +03002644 __get_user(fp, &(ucp->tuc_mcontext.mc_fp));
2645 __get_user(i7, &(ucp->tuc_mcontext.mc_i7));
blueswir15bfb56b2007-10-05 17:01:51 +00002646
bellard459a4012007-11-11 19:45:10 +00002647 w_addr = TARGET_STACK_BIAS+env->regwptr[UREG_I6];
2648 if (put_user(fp, w_addr + offsetof(struct target_reg_window, ins[6]),
2649 abi_ulong) != 0)
2650 goto do_sigsegv;
2651 if (put_user(i7, w_addr + offsetof(struct target_reg_window, ins[7]),
2652 abi_ulong) != 0)
2653 goto do_sigsegv;
Peter Maydellc7b016b2011-06-16 17:37:15 +01002654 /* FIXME this does not match how the kernel handles the FPU in
2655 * its sparc64_set_context implementation. In particular the FPU
2656 * is only restored if fenab is non-zero in:
2657 * __get_user(fenab, &(ucp->tuc_mcontext.mc_fpregs.mcfpu_enab));
2658 */
Aurelien Jarno60e99242010-03-29 02:12:51 +02002659 err |= __get_user(env->fprs, &(ucp->tuc_mcontext.mc_fpregs.mcfpu_fprs));
bellard459a4012007-11-11 19:45:10 +00002660 {
Richard Henderson30038fd2011-10-17 10:42:49 -07002661 uint32_t *src = ucp->tuc_mcontext.mc_fpregs.mcfpu_fregs.sregs;
2662 for (i = 0; i < 64; i++, src++) {
2663 if (i & 1) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002664 __get_user(env->fpr[i/2].l.lower, src);
Richard Henderson30038fd2011-10-17 10:42:49 -07002665 } else {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002666 __get_user(env->fpr[i/2].l.upper, src);
Richard Henderson30038fd2011-10-17 10:42:49 -07002667 }
2668 }
bellard459a4012007-11-11 19:45:10 +00002669 }
Riku Voipio1d8b5122014-04-23 10:26:05 +03002670 __get_user(env->fsr,
2671 &(ucp->tuc_mcontext.mc_fpregs.mcfpu_fsr));
2672 __get_user(env->gsr,
2673 &(ucp->tuc_mcontext.mc_fpregs.mcfpu_gsr));
blueswir15bfb56b2007-10-05 17:01:51 +00002674 if (err)
2675 goto do_sigsegv;
bellard459a4012007-11-11 19:45:10 +00002676 unlock_user_struct(ucp, ucp_addr, 0);
blueswir15bfb56b2007-10-05 17:01:51 +00002677 return;
2678 do_sigsegv:
bellard459a4012007-11-11 19:45:10 +00002679 unlock_user_struct(ucp, ucp_addr, 0);
Riku Voipio66393fb2009-12-04 15:16:32 +02002680 force_sig(TARGET_SIGSEGV);
blueswir15bfb56b2007-10-05 17:01:51 +00002681}
2682
2683void sparc64_get_context(CPUSPARCState *env)
2684{
bellard459a4012007-11-11 19:45:10 +00002685 abi_ulong ucp_addr;
2686 struct target_ucontext *ucp;
Anthony Liguoric227f092009-10-01 16:12:16 -05002687 target_mc_gregset_t *grp;
2688 target_mcontext_t *mcp;
bellard459a4012007-11-11 19:45:10 +00002689 abi_ulong fp, i7, w_addr;
blueswir15bfb56b2007-10-05 17:01:51 +00002690 int err;
2691 unsigned int i;
Anthony Liguoric227f092009-10-01 16:12:16 -05002692 target_sigset_t target_set;
blueswir15bfb56b2007-10-05 17:01:51 +00002693 sigset_t set;
2694
bellard459a4012007-11-11 19:45:10 +00002695 ucp_addr = env->regwptr[UREG_I0];
2696 if (!lock_user_struct(VERIFY_WRITE, ucp, ucp_addr, 0))
2697 goto do_sigsegv;
2698
Aurelien Jarno60e99242010-03-29 02:12:51 +02002699 mcp = &ucp->tuc_mcontext;
blueswir15bfb56b2007-10-05 17:01:51 +00002700 grp = &mcp->mc_gregs;
2701
2702 /* Skip over the trap instruction, first. */
2703 env->pc = env->npc;
2704 env->npc += 4;
2705
2706 err = 0;
2707
Alex Barcelo1c275922014-03-14 14:36:55 +00002708 do_sigprocmask(0, NULL, &set);
blueswir15bfb56b2007-10-05 17:01:51 +00002709 host_to_target_sigset_internal(&target_set, &set);
bellard459a4012007-11-11 19:45:10 +00002710 if (TARGET_NSIG_WORDS == 1) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002711 __put_user(target_set.sig[0],
2712 (abi_ulong *)&ucp->tuc_sigmask);
bellard459a4012007-11-11 19:45:10 +00002713 } else {
2714 abi_ulong *src, *dst;
2715 src = target_set.sig;
Aurelien Jarno60e99242010-03-29 02:12:51 +02002716 dst = ucp->tuc_sigmask.sig;
Stefan Weil0d9e61c2013-12-07 14:48:08 +01002717 for (i = 0; i < TARGET_NSIG_WORDS; i++, dst++, src++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002718 __put_user(*src, dst);
Stefan Weil0d9e61c2013-12-07 14:48:08 +01002719 }
blueswir15bfb56b2007-10-05 17:01:51 +00002720 if (err)
2721 goto do_sigsegv;
2722 }
2723
bellard459a4012007-11-11 19:45:10 +00002724 /* XXX: tstate must be saved properly */
Riku Voipio1d8b5122014-04-23 10:26:05 +03002725 // __put_user(env->tstate, &((*grp)[MC_TSTATE]));
2726 __put_user(env->pc, &((*grp)[MC_PC]));
2727 __put_user(env->npc, &((*grp)[MC_NPC]));
2728 __put_user(env->y, &((*grp)[MC_Y]));
2729 __put_user(env->gregs[1], &((*grp)[MC_G1]));
2730 __put_user(env->gregs[2], &((*grp)[MC_G2]));
2731 __put_user(env->gregs[3], &((*grp)[MC_G3]));
2732 __put_user(env->gregs[4], &((*grp)[MC_G4]));
2733 __put_user(env->gregs[5], &((*grp)[MC_G5]));
2734 __put_user(env->gregs[6], &((*grp)[MC_G6]));
2735 __put_user(env->gregs[7], &((*grp)[MC_G7]));
2736 __put_user(env->regwptr[UREG_I0], &((*grp)[MC_O0]));
2737 __put_user(env->regwptr[UREG_I1], &((*grp)[MC_O1]));
2738 __put_user(env->regwptr[UREG_I2], &((*grp)[MC_O2]));
2739 __put_user(env->regwptr[UREG_I3], &((*grp)[MC_O3]));
2740 __put_user(env->regwptr[UREG_I4], &((*grp)[MC_O4]));
2741 __put_user(env->regwptr[UREG_I5], &((*grp)[MC_O5]));
2742 __put_user(env->regwptr[UREG_I6], &((*grp)[MC_O6]));
2743 __put_user(env->regwptr[UREG_I7], &((*grp)[MC_O7]));
blueswir15bfb56b2007-10-05 17:01:51 +00002744
bellard459a4012007-11-11 19:45:10 +00002745 w_addr = TARGET_STACK_BIAS+env->regwptr[UREG_I6];
2746 fp = i7 = 0;
2747 if (get_user(fp, w_addr + offsetof(struct target_reg_window, ins[6]),
2748 abi_ulong) != 0)
2749 goto do_sigsegv;
2750 if (get_user(i7, w_addr + offsetof(struct target_reg_window, ins[7]),
2751 abi_ulong) != 0)
2752 goto do_sigsegv;
Riku Voipio1d8b5122014-04-23 10:26:05 +03002753 __put_user(fp, &(mcp->mc_fp));
2754 __put_user(i7, &(mcp->mc_i7));
blueswir15bfb56b2007-10-05 17:01:51 +00002755
bellard459a4012007-11-11 19:45:10 +00002756 {
Richard Henderson30038fd2011-10-17 10:42:49 -07002757 uint32_t *dst = ucp->tuc_mcontext.mc_fpregs.mcfpu_fregs.sregs;
2758 for (i = 0; i < 64; i++, dst++) {
2759 if (i & 1) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002760 __put_user(env->fpr[i/2].l.lower, dst);
Richard Henderson30038fd2011-10-17 10:42:49 -07002761 } else {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002762 __put_user(env->fpr[i/2].l.upper, dst);
Richard Henderson30038fd2011-10-17 10:42:49 -07002763 }
2764 }
bellard459a4012007-11-11 19:45:10 +00002765 }
Riku Voipio1d8b5122014-04-23 10:26:05 +03002766 __put_user(env->fsr, &(mcp->mc_fpregs.mcfpu_fsr));
2767 __put_user(env->gsr, &(mcp->mc_fpregs.mcfpu_gsr));
2768 __put_user(env->fprs, &(mcp->mc_fpregs.mcfpu_fprs));
blueswir15bfb56b2007-10-05 17:01:51 +00002769
2770 if (err)
2771 goto do_sigsegv;
bellard459a4012007-11-11 19:45:10 +00002772 unlock_user_struct(ucp, ucp_addr, 1);
blueswir15bfb56b2007-10-05 17:01:51 +00002773 return;
2774 do_sigsegv:
bellard459a4012007-11-11 19:45:10 +00002775 unlock_user_struct(ucp, ucp_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02002776 force_sig(TARGET_SIGSEGV);
blueswir15bfb56b2007-10-05 17:01:51 +00002777}
2778#endif
Richard Hendersonff970902013-02-10 10:30:42 -08002779#elif defined(TARGET_MIPS) || defined(TARGET_MIPS64)
bellard106ec872006-06-27 21:08:10 +00002780
Richard Hendersonff970902013-02-10 10:30:42 -08002781# if defined(TARGET_ABI_MIPSO32)
bellard106ec872006-06-27 21:08:10 +00002782struct target_sigcontext {
2783 uint32_t sc_regmask; /* Unused */
2784 uint32_t sc_status;
2785 uint64_t sc_pc;
2786 uint64_t sc_regs[32];
2787 uint64_t sc_fpregs[32];
2788 uint32_t sc_ownedfp; /* Unused */
2789 uint32_t sc_fpc_csr;
2790 uint32_t sc_fpc_eir; /* Unused */
2791 uint32_t sc_used_math;
2792 uint32_t sc_dsp; /* dsp status, was sc_ssflags */
Paul Brook94c54952009-07-09 18:40:15 +01002793 uint32_t pad0;
bellard106ec872006-06-27 21:08:10 +00002794 uint64_t sc_mdhi;
2795 uint64_t sc_mdlo;
2796 target_ulong sc_hi1; /* Was sc_cause */
2797 target_ulong sc_lo1; /* Was sc_badvaddr */
2798 target_ulong sc_hi2; /* Was sc_sigset[4] */
2799 target_ulong sc_lo2;
2800 target_ulong sc_hi3;
2801 target_ulong sc_lo3;
2802};
Richard Hendersonff970902013-02-10 10:30:42 -08002803# else /* N32 || N64 */
2804struct target_sigcontext {
2805 uint64_t sc_regs[32];
2806 uint64_t sc_fpregs[32];
2807 uint64_t sc_mdhi;
2808 uint64_t sc_hi1;
2809 uint64_t sc_hi2;
2810 uint64_t sc_hi3;
2811 uint64_t sc_mdlo;
2812 uint64_t sc_lo1;
2813 uint64_t sc_lo2;
2814 uint64_t sc_lo3;
2815 uint64_t sc_pc;
2816 uint32_t sc_fpc_csr;
2817 uint32_t sc_used_math;
2818 uint32_t sc_dsp;
2819 uint32_t sc_reserved;
2820};
2821# endif /* O32 */
bellard106ec872006-06-27 21:08:10 +00002822
2823struct sigframe {
2824 uint32_t sf_ass[4]; /* argument save space for o32 */
2825 uint32_t sf_code[2]; /* signal trampoline */
2826 struct target_sigcontext sf_sc;
Anthony Liguoric227f092009-10-01 16:12:16 -05002827 target_sigset_t sf_mask;
bellard106ec872006-06-27 21:08:10 +00002828};
2829
pbrook0b1bcb02009-04-21 01:41:10 +00002830struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02002831 target_ulong tuc_flags;
2832 target_ulong tuc_link;
2833 target_stack_t tuc_stack;
Paul Brook94c54952009-07-09 18:40:15 +01002834 target_ulong pad0;
Aurelien Jarno60e99242010-03-29 02:12:51 +02002835 struct target_sigcontext tuc_mcontext;
2836 target_sigset_t tuc_sigmask;
pbrook0b1bcb02009-04-21 01:41:10 +00002837};
2838
2839struct target_rt_sigframe {
2840 uint32_t rs_ass[4]; /* argument save space for o32 */
2841 uint32_t rs_code[2]; /* signal trampoline */
2842 struct target_siginfo rs_info;
2843 struct target_ucontext rs_uc;
2844};
2845
bellard106ec872006-06-27 21:08:10 +00002846/* Install trampoline to jump back from signal handler */
2847static inline int install_sigtramp(unsigned int *tramp, unsigned int syscall)
2848{
Richard Henderson084d0492013-02-10 10:30:44 -08002849 int err = 0;
bellard106ec872006-06-27 21:08:10 +00002850
2851 /*
Richard Henderson084d0492013-02-10 10:30:44 -08002852 * Set up the return code ...
2853 *
2854 * li v0, __NR__foo_sigreturn
2855 * syscall
2856 */
bellard106ec872006-06-27 21:08:10 +00002857
Riku Voipio1d8b5122014-04-23 10:26:05 +03002858 __put_user(0x24020000 + syscall, tramp + 0);
2859 __put_user(0x0000000c , tramp + 1);
bellard106ec872006-06-27 21:08:10 +00002860 return err;
2861}
2862
2863static inline int
Andreas Färber05390242012-02-25 03:37:53 +01002864setup_sigcontext(CPUMIPSState *regs, struct target_sigcontext *sc)
bellard106ec872006-06-27 21:08:10 +00002865{
2866 int err = 0;
Richard Henderson084d0492013-02-10 10:30:44 -08002867 int i;
bellard106ec872006-06-27 21:08:10 +00002868
Riku Voipio1d8b5122014-04-23 10:26:05 +03002869 __put_user(exception_resume_pc(regs), &sc->sc_pc);
Kwok Cheung Yeung1239b472013-05-17 14:51:21 -07002870 regs->hflags &= ~MIPS_HFLAG_BMASK;
bellard106ec872006-06-27 21:08:10 +00002871
Richard Henderson084d0492013-02-10 10:30:44 -08002872 __put_user(0, &sc->sc_regs[0]);
2873 for (i = 1; i < 32; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002874 __put_user(regs->active_tc.gpr[i], &sc->sc_regs[i]);
Richard Henderson084d0492013-02-10 10:30:44 -08002875 }
bellard106ec872006-06-27 21:08:10 +00002876
Riku Voipio1d8b5122014-04-23 10:26:05 +03002877 __put_user(regs->active_tc.HI[0], &sc->sc_mdhi);
2878 __put_user(regs->active_tc.LO[0], &sc->sc_mdlo);
bellard106ec872006-06-27 21:08:10 +00002879
Richard Henderson084d0492013-02-10 10:30:44 -08002880 /* Rather than checking for dsp existence, always copy. The storage
2881 would just be garbage otherwise. */
Riku Voipio1d8b5122014-04-23 10:26:05 +03002882 __put_user(regs->active_tc.HI[1], &sc->sc_hi1);
2883 __put_user(regs->active_tc.HI[2], &sc->sc_hi2);
2884 __put_user(regs->active_tc.HI[3], &sc->sc_hi3);
2885 __put_user(regs->active_tc.LO[1], &sc->sc_lo1);
2886 __put_user(regs->active_tc.LO[2], &sc->sc_lo2);
2887 __put_user(regs->active_tc.LO[3], &sc->sc_lo3);
Richard Henderson084d0492013-02-10 10:30:44 -08002888 {
2889 uint32_t dsp = cpu_rddsp(0x3ff, regs);
Riku Voipio1d8b5122014-04-23 10:26:05 +03002890 __put_user(dsp, &sc->sc_dsp);
bellard106ec872006-06-27 21:08:10 +00002891 }
Richard Henderson084d0492013-02-10 10:30:44 -08002892
Riku Voipio1d8b5122014-04-23 10:26:05 +03002893 __put_user(1, &sc->sc_used_math);
Richard Henderson084d0492013-02-10 10:30:44 -08002894
2895 for (i = 0; i < 32; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002896 __put_user(regs->active_fpu.fpr[i].d, &sc->sc_fpregs[i]);
bellard106ec872006-06-27 21:08:10 +00002897 }
bellard106ec872006-06-27 21:08:10 +00002898
bellard106ec872006-06-27 21:08:10 +00002899 return err;
2900}
2901
2902static inline int
Andreas Färber05390242012-02-25 03:37:53 +01002903restore_sigcontext(CPUMIPSState *regs, struct target_sigcontext *sc)
bellard106ec872006-06-27 21:08:10 +00002904{
2905 int err = 0;
Richard Henderson084d0492013-02-10 10:30:44 -08002906 int i;
bellard106ec872006-06-27 21:08:10 +00002907
Riku Voipio1d8b5122014-04-23 10:26:05 +03002908 __get_user(regs->CP0_EPC, &sc->sc_pc);
bellard106ec872006-06-27 21:08:10 +00002909
Riku Voipio1d8b5122014-04-23 10:26:05 +03002910 __get_user(regs->active_tc.HI[0], &sc->sc_mdhi);
2911 __get_user(regs->active_tc.LO[0], &sc->sc_mdlo);
bellard106ec872006-06-27 21:08:10 +00002912
Richard Henderson084d0492013-02-10 10:30:44 -08002913 for (i = 1; i < 32; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002914 __get_user(regs->active_tc.gpr[i], &sc->sc_regs[i]);
bellard106ec872006-06-27 21:08:10 +00002915 }
2916
Riku Voipio1d8b5122014-04-23 10:26:05 +03002917 __get_user(regs->active_tc.HI[1], &sc->sc_hi1);
2918 __get_user(regs->active_tc.HI[2], &sc->sc_hi2);
2919 __get_user(regs->active_tc.HI[3], &sc->sc_hi3);
2920 __get_user(regs->active_tc.LO[1], &sc->sc_lo1);
2921 __get_user(regs->active_tc.LO[2], &sc->sc_lo2);
2922 __get_user(regs->active_tc.LO[3], &sc->sc_lo3);
Richard Henderson084d0492013-02-10 10:30:44 -08002923 {
2924 uint32_t dsp;
Riku Voipio1d8b5122014-04-23 10:26:05 +03002925 __get_user(dsp, &sc->sc_dsp);
Richard Henderson084d0492013-02-10 10:30:44 -08002926 cpu_wrdsp(dsp, 0x3ff, regs);
2927 }
2928
2929 for (i = 0; i < 32; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002930 __get_user(regs->active_fpu.fpr[i].d, &sc->sc_fpregs[i]);
Richard Henderson084d0492013-02-10 10:30:44 -08002931 }
2932
bellard106ec872006-06-27 21:08:10 +00002933 return err;
2934}
Richard Hendersonff970902013-02-10 10:30:42 -08002935
bellard106ec872006-06-27 21:08:10 +00002936/*
2937 * Determine which stack to use..
2938 */
bellard579a97f2007-11-11 14:26:47 +00002939static inline abi_ulong
Andreas Färber05390242012-02-25 03:37:53 +01002940get_sigframe(struct target_sigaction *ka, CPUMIPSState *regs, size_t frame_size)
bellard106ec872006-06-27 21:08:10 +00002941{
2942 unsigned long sp;
2943
2944 /* Default to using normal stack */
thsb5dc7732008-06-27 10:02:35 +00002945 sp = regs->active_tc.gpr[29];
bellard106ec872006-06-27 21:08:10 +00002946
2947 /*
Stefan Weil93148aa2012-02-26 18:46:12 +01002948 * FPU emulator may have its own trampoline active just
bellard106ec872006-06-27 21:08:10 +00002949 * above the user stack, 16-bytes before the next lowest
2950 * 16 byte boundary. Try to avoid trashing it.
2951 */
2952 sp -= 32;
2953
bellard106ec872006-06-27 21:08:10 +00002954 /* This is the X/Open sanctioned signal stack switching. */
pbrook624f7972008-05-31 16:11:38 +00002955 if ((ka->sa_flags & TARGET_SA_ONSTACK) && (sas_ss_flags (sp) == 0)) {
thsa04e1342007-09-27 13:57:58 +00002956 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
2957 }
bellard106ec872006-06-27 21:08:10 +00002958
bellard579a97f2007-11-11 14:26:47 +00002959 return (sp - frame_size) & ~7;
bellard106ec872006-06-27 21:08:10 +00002960}
2961
Kwok Cheung Yeungea3164a2013-05-17 14:51:20 -07002962static void mips_set_hflags_isa_mode_from_pc(CPUMIPSState *env)
2963{
2964 if (env->insn_flags & (ASE_MIPS16 | ASE_MICROMIPS)) {
2965 env->hflags &= ~MIPS_HFLAG_M16;
2966 env->hflags |= (env->active_tc.PC & 1) << MIPS_HFLAG_M16_SHIFT;
2967 env->active_tc.PC &= ~(target_ulong) 1;
2968 }
2969}
2970
Richard Hendersonff970902013-02-10 10:30:42 -08002971# if defined(TARGET_ABI_MIPSO32)
bellard579a97f2007-11-11 14:26:47 +00002972/* compare linux/arch/mips/kernel/signal.c:setup_frame() */
pbrook624f7972008-05-31 16:11:38 +00002973static void setup_frame(int sig, struct target_sigaction * ka,
Andreas Färber05390242012-02-25 03:37:53 +01002974 target_sigset_t *set, CPUMIPSState *regs)
bellard106ec872006-06-27 21:08:10 +00002975{
2976 struct sigframe *frame;
bellard579a97f2007-11-11 14:26:47 +00002977 abi_ulong frame_addr;
bellard106ec872006-06-27 21:08:10 +00002978 int i;
2979
bellard579a97f2007-11-11 14:26:47 +00002980 frame_addr = get_sigframe(ka, regs, sizeof(*frame));
2981 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
bellard106ec872006-06-27 21:08:10 +00002982 goto give_sigsegv;
2983
2984 install_sigtramp(frame->sf_code, TARGET_NR_sigreturn);
2985
2986 if(setup_sigcontext(regs, &frame->sf_sc))
2987 goto give_sigsegv;
2988
2989 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
2990 if(__put_user(set->sig[i], &frame->sf_mask.sig[i]))
2991 goto give_sigsegv;
2992 }
2993
2994 /*
2995 * Arguments to signal handler:
2996 *
2997 * a0 = signal number
2998 * a1 = 0 (should be cause)
2999 * a2 = pointer to struct sigcontext
3000 *
3001 * $25 and PC point to the signal handler, $29 points to the
3002 * struct sigframe.
3003 */
thsb5dc7732008-06-27 10:02:35 +00003004 regs->active_tc.gpr[ 4] = sig;
3005 regs->active_tc.gpr[ 5] = 0;
3006 regs->active_tc.gpr[ 6] = frame_addr + offsetof(struct sigframe, sf_sc);
3007 regs->active_tc.gpr[29] = frame_addr;
3008 regs->active_tc.gpr[31] = frame_addr + offsetof(struct sigframe, sf_code);
bellard106ec872006-06-27 21:08:10 +00003009 /* The original kernel code sets CP0_EPC to the handler
3010 * since it returns to userland using eret
3011 * we cannot do this here, and we must set PC directly */
thsb5dc7732008-06-27 10:02:35 +00003012 regs->active_tc.PC = regs->active_tc.gpr[25] = ka->_sa_handler;
Kwok Cheung Yeungea3164a2013-05-17 14:51:20 -07003013 mips_set_hflags_isa_mode_from_pc(regs);
bellard579a97f2007-11-11 14:26:47 +00003014 unlock_user_struct(frame, frame_addr, 1);
bellard106ec872006-06-27 21:08:10 +00003015 return;
3016
3017give_sigsegv:
bellard579a97f2007-11-11 14:26:47 +00003018 unlock_user_struct(frame, frame_addr, 1);
bellard106ec872006-06-27 21:08:10 +00003019 force_sig(TARGET_SIGSEGV/*, current*/);
bellard106ec872006-06-27 21:08:10 +00003020}
3021
Andreas Färber05390242012-02-25 03:37:53 +01003022long do_sigreturn(CPUMIPSState *regs)
bellard106ec872006-06-27 21:08:10 +00003023{
ths388bb212007-05-13 13:58:00 +00003024 struct sigframe *frame;
bellard579a97f2007-11-11 14:26:47 +00003025 abi_ulong frame_addr;
ths388bb212007-05-13 13:58:00 +00003026 sigset_t blocked;
Anthony Liguoric227f092009-10-01 16:12:16 -05003027 target_sigset_t target_set;
ths388bb212007-05-13 13:58:00 +00003028 int i;
bellard106ec872006-06-27 21:08:10 +00003029
3030#if defined(DEBUG_SIGNAL)
ths388bb212007-05-13 13:58:00 +00003031 fprintf(stderr, "do_sigreturn\n");
bellard106ec872006-06-27 21:08:10 +00003032#endif
thsb5dc7732008-06-27 10:02:35 +00003033 frame_addr = regs->active_tc.gpr[29];
bellard579a97f2007-11-11 14:26:47 +00003034 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
bellard106ec872006-06-27 21:08:10 +00003035 goto badframe;
3036
ths388bb212007-05-13 13:58:00 +00003037 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
bellard106ec872006-06-27 21:08:10 +00003038 if(__get_user(target_set.sig[i], &frame->sf_mask.sig[i]))
3039 goto badframe;
ths388bb212007-05-13 13:58:00 +00003040 }
bellard106ec872006-06-27 21:08:10 +00003041
ths388bb212007-05-13 13:58:00 +00003042 target_to_host_sigset_internal(&blocked, &target_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00003043 do_sigprocmask(SIG_SETMASK, &blocked, NULL);
bellard106ec872006-06-27 21:08:10 +00003044
ths388bb212007-05-13 13:58:00 +00003045 if (restore_sigcontext(regs, &frame->sf_sc))
bellard106ec872006-06-27 21:08:10 +00003046 goto badframe;
3047
3048#if 0
ths388bb212007-05-13 13:58:00 +00003049 /*
3050 * Don't let your children do this ...
3051 */
3052 __asm__ __volatile__(
bellard106ec872006-06-27 21:08:10 +00003053 "move\t$29, %0\n\t"
3054 "j\tsyscall_exit"
3055 :/* no outputs */
3056 :"r" (&regs));
ths388bb212007-05-13 13:58:00 +00003057 /* Unreached */
bellard106ec872006-06-27 21:08:10 +00003058#endif
ths3b46e622007-09-17 08:09:54 +00003059
thsb5dc7732008-06-27 10:02:35 +00003060 regs->active_tc.PC = regs->CP0_EPC;
Kwok Cheung Yeungea3164a2013-05-17 14:51:20 -07003061 mips_set_hflags_isa_mode_from_pc(regs);
ths388bb212007-05-13 13:58:00 +00003062 /* I am not sure this is right, but it seems to work
bellard106ec872006-06-27 21:08:10 +00003063 * maybe a problem with nested signals ? */
3064 regs->CP0_EPC = 0;
pbrook0b1bcb02009-04-21 01:41:10 +00003065 return -TARGET_QEMU_ESIGRETURN;
bellard106ec872006-06-27 21:08:10 +00003066
3067badframe:
ths388bb212007-05-13 13:58:00 +00003068 force_sig(TARGET_SIGSEGV/*, current*/);
3069 return 0;
bellard106ec872006-06-27 21:08:10 +00003070}
Richard Hendersonff970902013-02-10 10:30:42 -08003071# endif /* O32 */
bellard106ec872006-06-27 21:08:10 +00003072
pbrook624f7972008-05-31 16:11:38 +00003073static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05003074 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01003075 target_sigset_t *set, CPUMIPSState *env)
bellard106ec872006-06-27 21:08:10 +00003076{
pbrook0b1bcb02009-04-21 01:41:10 +00003077 struct target_rt_sigframe *frame;
3078 abi_ulong frame_addr;
3079 int i;
3080
3081 frame_addr = get_sigframe(ka, env, sizeof(*frame));
3082 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
3083 goto give_sigsegv;
3084
3085 install_sigtramp(frame->rs_code, TARGET_NR_rt_sigreturn);
3086
3087 copy_siginfo_to_user(&frame->rs_info, info);
3088
Aurelien Jarno60e99242010-03-29 02:12:51 +02003089 __put_user(0, &frame->rs_uc.tuc_flags);
3090 __put_user(0, &frame->rs_uc.tuc_link);
3091 __put_user(target_sigaltstack_used.ss_sp, &frame->rs_uc.tuc_stack.ss_sp);
3092 __put_user(target_sigaltstack_used.ss_size, &frame->rs_uc.tuc_stack.ss_size);
pbrook0b1bcb02009-04-21 01:41:10 +00003093 __put_user(sas_ss_flags(get_sp_from_cpustate(env)),
Aurelien Jarno60e99242010-03-29 02:12:51 +02003094 &frame->rs_uc.tuc_stack.ss_flags);
pbrook0b1bcb02009-04-21 01:41:10 +00003095
Aurelien Jarno60e99242010-03-29 02:12:51 +02003096 setup_sigcontext(env, &frame->rs_uc.tuc_mcontext);
pbrook0b1bcb02009-04-21 01:41:10 +00003097
3098 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
Aurelien Jarno60e99242010-03-29 02:12:51 +02003099 __put_user(set->sig[i], &frame->rs_uc.tuc_sigmask.sig[i]);
pbrook0b1bcb02009-04-21 01:41:10 +00003100 }
3101
3102 /*
3103 * Arguments to signal handler:
3104 *
3105 * a0 = signal number
Richard W.M. Jones02d2bd52012-07-05 03:32:44 +00003106 * a1 = pointer to siginfo_t
pbrook0b1bcb02009-04-21 01:41:10 +00003107 * a2 = pointer to struct ucontext
3108 *
3109 * $25 and PC point to the signal handler, $29 points to the
3110 * struct sigframe.
3111 */
3112 env->active_tc.gpr[ 4] = sig;
3113 env->active_tc.gpr[ 5] = frame_addr
3114 + offsetof(struct target_rt_sigframe, rs_info);
3115 env->active_tc.gpr[ 6] = frame_addr
3116 + offsetof(struct target_rt_sigframe, rs_uc);
3117 env->active_tc.gpr[29] = frame_addr;
3118 env->active_tc.gpr[31] = frame_addr
3119 + offsetof(struct target_rt_sigframe, rs_code);
3120 /* The original kernel code sets CP0_EPC to the handler
3121 * since it returns to userland using eret
3122 * we cannot do this here, and we must set PC directly */
3123 env->active_tc.PC = env->active_tc.gpr[25] = ka->_sa_handler;
Kwok Cheung Yeungea3164a2013-05-17 14:51:20 -07003124 mips_set_hflags_isa_mode_from_pc(env);
pbrook0b1bcb02009-04-21 01:41:10 +00003125 unlock_user_struct(frame, frame_addr, 1);
3126 return;
3127
3128give_sigsegv:
3129 unlock_user_struct(frame, frame_addr, 1);
3130 force_sig(TARGET_SIGSEGV/*, current*/);
bellard106ec872006-06-27 21:08:10 +00003131}
3132
Andreas Färber05390242012-02-25 03:37:53 +01003133long do_rt_sigreturn(CPUMIPSState *env)
bellard106ec872006-06-27 21:08:10 +00003134{
pbrook0b1bcb02009-04-21 01:41:10 +00003135 struct target_rt_sigframe *frame;
3136 abi_ulong frame_addr;
3137 sigset_t blocked;
3138
3139#if defined(DEBUG_SIGNAL)
3140 fprintf(stderr, "do_rt_sigreturn\n");
3141#endif
3142 frame_addr = env->active_tc.gpr[29];
3143 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
3144 goto badframe;
3145
Aurelien Jarno60e99242010-03-29 02:12:51 +02003146 target_to_host_sigset(&blocked, &frame->rs_uc.tuc_sigmask);
Alex Barcelo1c275922014-03-14 14:36:55 +00003147 do_sigprocmask(SIG_SETMASK, &blocked, NULL);
pbrook0b1bcb02009-04-21 01:41:10 +00003148
Aurelien Jarno60e99242010-03-29 02:12:51 +02003149 if (restore_sigcontext(env, &frame->rs_uc.tuc_mcontext))
pbrook0b1bcb02009-04-21 01:41:10 +00003150 goto badframe;
3151
3152 if (do_sigaltstack(frame_addr +
Aurelien Jarno60e99242010-03-29 02:12:51 +02003153 offsetof(struct target_rt_sigframe, rs_uc.tuc_stack),
pbrook0b1bcb02009-04-21 01:41:10 +00003154 0, get_sp_from_cpustate(env)) == -EFAULT)
3155 goto badframe;
3156
3157 env->active_tc.PC = env->CP0_EPC;
Kwok Cheung Yeungea3164a2013-05-17 14:51:20 -07003158 mips_set_hflags_isa_mode_from_pc(env);
pbrook0b1bcb02009-04-21 01:41:10 +00003159 /* I am not sure this is right, but it seems to work
3160 * maybe a problem with nested signals ? */
3161 env->CP0_EPC = 0;
3162 return -TARGET_QEMU_ESIGRETURN;
3163
3164badframe:
3165 force_sig(TARGET_SIGSEGV/*, current*/);
3166 return 0;
bellard106ec872006-06-27 21:08:10 +00003167}
bellard6d5e2162004-09-30 22:04:13 +00003168
thsc3b5bc82007-12-02 06:31:25 +00003169#elif defined(TARGET_SH4)
3170
3171/*
3172 * code and data structures from linux kernel:
3173 * include/asm-sh/sigcontext.h
3174 * arch/sh/kernel/signal.c
3175 */
3176
3177struct target_sigcontext {
3178 target_ulong oldmask;
3179
3180 /* CPU registers */
3181 target_ulong sc_gregs[16];
3182 target_ulong sc_pc;
3183 target_ulong sc_pr;
3184 target_ulong sc_sr;
3185 target_ulong sc_gbr;
3186 target_ulong sc_mach;
3187 target_ulong sc_macl;
3188
3189 /* FPU registers */
3190 target_ulong sc_fpregs[16];
3191 target_ulong sc_xfpregs[16];
3192 unsigned int sc_fpscr;
3193 unsigned int sc_fpul;
3194 unsigned int sc_ownedfp;
3195};
3196
3197struct target_sigframe
3198{
3199 struct target_sigcontext sc;
3200 target_ulong extramask[TARGET_NSIG_WORDS-1];
3201 uint16_t retcode[3];
3202};
3203
3204
3205struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02003206 target_ulong tuc_flags;
3207 struct target_ucontext *tuc_link;
3208 target_stack_t tuc_stack;
3209 struct target_sigcontext tuc_mcontext;
3210 target_sigset_t tuc_sigmask; /* mask last for extensibility */
thsc3b5bc82007-12-02 06:31:25 +00003211};
3212
3213struct target_rt_sigframe
3214{
3215 struct target_siginfo info;
3216 struct target_ucontext uc;
3217 uint16_t retcode[3];
3218};
3219
3220
3221#define MOVW(n) (0x9300|((n)-2)) /* Move mem word at PC+n to R3 */
3222#define TRAP_NOARG 0xc310 /* Syscall w/no args (NR in R3) SH3/4 */
3223
pbrook624f7972008-05-31 16:11:38 +00003224static abi_ulong get_sigframe(struct target_sigaction *ka,
thsc3b5bc82007-12-02 06:31:25 +00003225 unsigned long sp, size_t frame_size)
3226{
pbrook624f7972008-05-31 16:11:38 +00003227 if ((ka->sa_flags & TARGET_SA_ONSTACK) && (sas_ss_flags(sp) == 0)) {
thsc3b5bc82007-12-02 06:31:25 +00003228 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
3229 }
3230
3231 return (sp - frame_size) & -8ul;
3232}
3233
3234static int setup_sigcontext(struct target_sigcontext *sc,
Andreas Färber05390242012-02-25 03:37:53 +01003235 CPUSH4State *regs, unsigned long mask)
thsc3b5bc82007-12-02 06:31:25 +00003236{
3237 int err = 0;
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003238 int i;
thsc3b5bc82007-12-02 06:31:25 +00003239
Riku Voipio1d8b5122014-04-23 10:26:05 +03003240#define COPY(x) __put_user(regs->x, &sc->sc_##x)
thsc3b5bc82007-12-02 06:31:25 +00003241 COPY(gregs[0]); COPY(gregs[1]);
3242 COPY(gregs[2]); COPY(gregs[3]);
3243 COPY(gregs[4]); COPY(gregs[5]);
3244 COPY(gregs[6]); COPY(gregs[7]);
3245 COPY(gregs[8]); COPY(gregs[9]);
3246 COPY(gregs[10]); COPY(gregs[11]);
3247 COPY(gregs[12]); COPY(gregs[13]);
3248 COPY(gregs[14]); COPY(gregs[15]);
3249 COPY(gbr); COPY(mach);
3250 COPY(macl); COPY(pr);
3251 COPY(sr); COPY(pc);
3252#undef COPY
3253
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003254 for (i=0; i<16; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03003255 __put_user(regs->fregs[i], &sc->sc_fpregs[i]);
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003256 }
Riku Voipio1d8b5122014-04-23 10:26:05 +03003257 __put_user(regs->fpscr, &sc->sc_fpscr);
3258 __put_user(regs->fpul, &sc->sc_fpul);
thsc3b5bc82007-12-02 06:31:25 +00003259
3260 /* non-iBCS2 extensions.. */
Riku Voipio1d8b5122014-04-23 10:26:05 +03003261 __put_user(mask, &sc->oldmask);
thsc3b5bc82007-12-02 06:31:25 +00003262
3263 return err;
3264}
3265
Andreas Färber05390242012-02-25 03:37:53 +01003266static int restore_sigcontext(CPUSH4State *regs, struct target_sigcontext *sc,
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003267 target_ulong *r0_p)
thsc3b5bc82007-12-02 06:31:25 +00003268{
3269 unsigned int err = 0;
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003270 int i;
thsc3b5bc82007-12-02 06:31:25 +00003271
Riku Voipio1d8b5122014-04-23 10:26:05 +03003272#define COPY(x) __get_user(regs->x, &sc->sc_##x)
thsc3b5bc82007-12-02 06:31:25 +00003273 COPY(gregs[1]);
3274 COPY(gregs[2]); COPY(gregs[3]);
3275 COPY(gregs[4]); COPY(gregs[5]);
3276 COPY(gregs[6]); COPY(gregs[7]);
3277 COPY(gregs[8]); COPY(gregs[9]);
3278 COPY(gregs[10]); COPY(gregs[11]);
3279 COPY(gregs[12]); COPY(gregs[13]);
3280 COPY(gregs[14]); COPY(gregs[15]);
3281 COPY(gbr); COPY(mach);
3282 COPY(macl); COPY(pr);
3283 COPY(sr); COPY(pc);
3284#undef COPY
3285
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003286 for (i=0; i<16; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03003287 __get_user(regs->fregs[i], &sc->sc_fpregs[i]);
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003288 }
Riku Voipio1d8b5122014-04-23 10:26:05 +03003289 __get_user(regs->fpscr, &sc->sc_fpscr);
3290 __get_user(regs->fpul, &sc->sc_fpul);
thsc3b5bc82007-12-02 06:31:25 +00003291
3292 regs->tra = -1; /* disable syscall checks */
Riku Voipio1d8b5122014-04-23 10:26:05 +03003293 __get_user(*r0_p, &sc->sc_gregs[0]);
thsc3b5bc82007-12-02 06:31:25 +00003294 return err;
3295}
3296
pbrook624f7972008-05-31 16:11:38 +00003297static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01003298 target_sigset_t *set, CPUSH4State *regs)
thsc3b5bc82007-12-02 06:31:25 +00003299{
3300 struct target_sigframe *frame;
3301 abi_ulong frame_addr;
3302 int i;
3303 int err = 0;
3304 int signal;
3305
3306 frame_addr = get_sigframe(ka, regs->gregs[15], sizeof(*frame));
3307 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
3308 goto give_sigsegv;
3309
3310 signal = current_exec_domain_sig(sig);
3311
3312 err |= setup_sigcontext(&frame->sc, regs, set->sig[0]);
3313
3314 for (i = 0; i < TARGET_NSIG_WORDS - 1; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03003315 __put_user(set->sig[i + 1], &frame->extramask[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_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 */
3336 regs->gregs[5] = 0;
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003337 regs->gregs[6] = frame_addr += offsetof(typeof(*frame), sc);
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
pbrook624f7972008-05-31 16:11:38 +00003348static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05003349 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01003350 target_sigset_t *set, CPUSH4State *regs)
thsc3b5bc82007-12-02 06:31:25 +00003351{
3352 struct target_rt_sigframe *frame;
3353 abi_ulong frame_addr;
3354 int i;
3355 int err = 0;
3356 int signal;
3357
3358 frame_addr = get_sigframe(ka, regs->gregs[15], sizeof(*frame));
3359 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
3360 goto give_sigsegv;
3361
3362 signal = current_exec_domain_sig(sig);
3363
3364 err |= copy_siginfo_to_user(&frame->info, info);
3365
3366 /* Create the ucontext. */
Riku Voipio1d8b5122014-04-23 10:26:05 +03003367 __put_user(0, &frame->uc.tuc_flags);
3368 __put_user(0, (unsigned long *)&frame->uc.tuc_link);
3369 __put_user((unsigned long)target_sigaltstack_used.ss_sp,
3370 &frame->uc.tuc_stack.ss_sp);
3371 __put_user(sas_ss_flags(regs->gregs[15]),
3372 &frame->uc.tuc_stack.ss_flags);
3373 __put_user(target_sigaltstack_used.ss_size,
3374 &frame->uc.tuc_stack.ss_size);
3375 setup_sigcontext(&frame->uc.tuc_mcontext,
thsc3b5bc82007-12-02 06:31:25 +00003376 regs, set->sig[0]);
3377 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03003378 __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
thsc3b5bc82007-12-02 06:31:25 +00003379 }
3380
3381 /* Set up to return from userspace. If provided, use a stub
3382 already in userspace. */
pbrook624f7972008-05-31 16:11:38 +00003383 if (ka->sa_flags & TARGET_SA_RESTORER) {
3384 regs->pr = (unsigned long) ka->sa_restorer;
thsc3b5bc82007-12-02 06:31:25 +00003385 } else {
3386 /* Generate return code (system call to sigreturn) */
Riku Voipio1d8b5122014-04-23 10:26:05 +03003387 __put_user(MOVW(2), &frame->retcode[0]);
3388 __put_user(TRAP_NOARG, &frame->retcode[1]);
3389 __put_user((TARGET_NR_rt_sigreturn), &frame->retcode[2]);
thsc3b5bc82007-12-02 06:31:25 +00003390 regs->pr = (unsigned long) frame->retcode;
3391 }
3392
3393 if (err)
3394 goto give_sigsegv;
3395
3396 /* Set up registers for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003397 regs->gregs[15] = frame_addr;
thsc3b5bc82007-12-02 06:31:25 +00003398 regs->gregs[4] = signal; /* Arg for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003399 regs->gregs[5] = frame_addr + offsetof(typeof(*frame), info);
3400 regs->gregs[6] = frame_addr + offsetof(typeof(*frame), uc);
pbrook624f7972008-05-31 16:11:38 +00003401 regs->pc = (unsigned long) ka->_sa_handler;
thsc3b5bc82007-12-02 06:31:25 +00003402
3403 unlock_user_struct(frame, frame_addr, 1);
3404 return;
3405
3406give_sigsegv:
3407 unlock_user_struct(frame, frame_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02003408 force_sig(TARGET_SIGSEGV);
thsc3b5bc82007-12-02 06:31:25 +00003409}
3410
Andreas Färber05390242012-02-25 03:37:53 +01003411long do_sigreturn(CPUSH4State *regs)
thsc3b5bc82007-12-02 06:31:25 +00003412{
3413 struct target_sigframe *frame;
3414 abi_ulong frame_addr;
3415 sigset_t blocked;
Anthony Liguoric227f092009-10-01 16:12:16 -05003416 target_sigset_t target_set;
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003417 target_ulong r0;
thsc3b5bc82007-12-02 06:31:25 +00003418 int i;
3419 int err = 0;
3420
3421#if defined(DEBUG_SIGNAL)
3422 fprintf(stderr, "do_sigreturn\n");
3423#endif
3424 frame_addr = regs->gregs[15];
3425 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
3426 goto badframe;
3427
Riku Voipio1d8b5122014-04-23 10:26:05 +03003428 __get_user(target_set.sig[0], &frame->sc.oldmask);
thsc3b5bc82007-12-02 06:31:25 +00003429 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03003430 __get_user(target_set.sig[i], &frame->extramask[i - 1]);
thsc3b5bc82007-12-02 06:31:25 +00003431 }
3432
3433 if (err)
3434 goto badframe;
3435
3436 target_to_host_sigset_internal(&blocked, &target_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00003437 do_sigprocmask(SIG_SETMASK, &blocked, NULL);
thsc3b5bc82007-12-02 06:31:25 +00003438
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003439 if (restore_sigcontext(regs, &frame->sc, &r0))
thsc3b5bc82007-12-02 06:31:25 +00003440 goto badframe;
3441
3442 unlock_user_struct(frame, frame_addr, 0);
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003443 return r0;
thsc3b5bc82007-12-02 06:31:25 +00003444
3445badframe:
3446 unlock_user_struct(frame, frame_addr, 0);
3447 force_sig(TARGET_SIGSEGV);
3448 return 0;
3449}
3450
Andreas Färber05390242012-02-25 03:37:53 +01003451long do_rt_sigreturn(CPUSH4State *regs)
thsc3b5bc82007-12-02 06:31:25 +00003452{
3453 struct target_rt_sigframe *frame;
3454 abi_ulong frame_addr;
3455 sigset_t blocked;
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003456 target_ulong r0;
thsc3b5bc82007-12-02 06:31:25 +00003457
3458#if defined(DEBUG_SIGNAL)
3459 fprintf(stderr, "do_rt_sigreturn\n");
3460#endif
3461 frame_addr = regs->gregs[15];
3462 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
3463 goto badframe;
3464
Aurelien Jarno60e99242010-03-29 02:12:51 +02003465 target_to_host_sigset(&blocked, &frame->uc.tuc_sigmask);
Alex Barcelo1c275922014-03-14 14:36:55 +00003466 do_sigprocmask(SIG_SETMASK, &blocked, NULL);
thsc3b5bc82007-12-02 06:31:25 +00003467
Aurelien Jarno60e99242010-03-29 02:12:51 +02003468 if (restore_sigcontext(regs, &frame->uc.tuc_mcontext, &r0))
thsc3b5bc82007-12-02 06:31:25 +00003469 goto badframe;
3470
3471 if (do_sigaltstack(frame_addr +
Aurelien Jarno60e99242010-03-29 02:12:51 +02003472 offsetof(struct target_rt_sigframe, uc.tuc_stack),
thsc3b5bc82007-12-02 06:31:25 +00003473 0, get_sp_from_cpustate(regs)) == -EFAULT)
3474 goto badframe;
3475
3476 unlock_user_struct(frame, frame_addr, 0);
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003477 return r0;
thsc3b5bc82007-12-02 06:31:25 +00003478
3479badframe:
3480 unlock_user_struct(frame, frame_addr, 0);
3481 force_sig(TARGET_SIGSEGV);
3482 return 0;
3483}
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003484#elif defined(TARGET_MICROBLAZE)
3485
3486struct target_sigcontext {
3487 struct target_pt_regs regs; /* needs to be first */
3488 uint32_t oldmask;
3489};
3490
Edgar E. Iglesiasb2178702010-07-23 09:30:37 +02003491struct target_stack_t {
3492 abi_ulong ss_sp;
3493 int ss_flags;
3494 unsigned int ss_size;
3495};
3496
3497struct target_ucontext {
Richard Hendersonf711df62010-11-22 14:57:52 -08003498 abi_ulong tuc_flags;
3499 abi_ulong tuc_link;
3500 struct target_stack_t tuc_stack;
3501 struct target_sigcontext tuc_mcontext;
3502 uint32_t tuc_extramask[TARGET_NSIG_WORDS - 1];
Edgar E. Iglesiasb2178702010-07-23 09:30:37 +02003503};
3504
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003505/* Signal frames. */
3506struct target_signal_frame {
Edgar E. Iglesiasb2178702010-07-23 09:30:37 +02003507 struct target_ucontext uc;
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003508 uint32_t extramask[TARGET_NSIG_WORDS - 1];
3509 uint32_t tramp[2];
3510};
3511
3512struct rt_signal_frame {
Richard W.M. Jones02d2bd52012-07-05 03:32:44 +00003513 siginfo_t info;
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003514 struct ucontext uc;
3515 uint32_t tramp[2];
3516};
3517
Andreas Färber05390242012-02-25 03:37:53 +01003518static void setup_sigcontext(struct target_sigcontext *sc, CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003519{
3520 __put_user(env->regs[0], &sc->regs.r0);
3521 __put_user(env->regs[1], &sc->regs.r1);
3522 __put_user(env->regs[2], &sc->regs.r2);
3523 __put_user(env->regs[3], &sc->regs.r3);
3524 __put_user(env->regs[4], &sc->regs.r4);
3525 __put_user(env->regs[5], &sc->regs.r5);
3526 __put_user(env->regs[6], &sc->regs.r6);
3527 __put_user(env->regs[7], &sc->regs.r7);
3528 __put_user(env->regs[8], &sc->regs.r8);
3529 __put_user(env->regs[9], &sc->regs.r9);
3530 __put_user(env->regs[10], &sc->regs.r10);
3531 __put_user(env->regs[11], &sc->regs.r11);
3532 __put_user(env->regs[12], &sc->regs.r12);
3533 __put_user(env->regs[13], &sc->regs.r13);
3534 __put_user(env->regs[14], &sc->regs.r14);
3535 __put_user(env->regs[15], &sc->regs.r15);
3536 __put_user(env->regs[16], &sc->regs.r16);
3537 __put_user(env->regs[17], &sc->regs.r17);
3538 __put_user(env->regs[18], &sc->regs.r18);
3539 __put_user(env->regs[19], &sc->regs.r19);
3540 __put_user(env->regs[20], &sc->regs.r20);
3541 __put_user(env->regs[21], &sc->regs.r21);
3542 __put_user(env->regs[22], &sc->regs.r22);
3543 __put_user(env->regs[23], &sc->regs.r23);
3544 __put_user(env->regs[24], &sc->regs.r24);
3545 __put_user(env->regs[25], &sc->regs.r25);
3546 __put_user(env->regs[26], &sc->regs.r26);
3547 __put_user(env->regs[27], &sc->regs.r27);
3548 __put_user(env->regs[28], &sc->regs.r28);
3549 __put_user(env->regs[29], &sc->regs.r29);
3550 __put_user(env->regs[30], &sc->regs.r30);
3551 __put_user(env->regs[31], &sc->regs.r31);
3552 __put_user(env->sregs[SR_PC], &sc->regs.pc);
3553}
3554
Andreas Färber05390242012-02-25 03:37:53 +01003555static void restore_sigcontext(struct target_sigcontext *sc, CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003556{
3557 __get_user(env->regs[0], &sc->regs.r0);
3558 __get_user(env->regs[1], &sc->regs.r1);
3559 __get_user(env->regs[2], &sc->regs.r2);
3560 __get_user(env->regs[3], &sc->regs.r3);
3561 __get_user(env->regs[4], &sc->regs.r4);
3562 __get_user(env->regs[5], &sc->regs.r5);
3563 __get_user(env->regs[6], &sc->regs.r6);
3564 __get_user(env->regs[7], &sc->regs.r7);
3565 __get_user(env->regs[8], &sc->regs.r8);
3566 __get_user(env->regs[9], &sc->regs.r9);
3567 __get_user(env->regs[10], &sc->regs.r10);
3568 __get_user(env->regs[11], &sc->regs.r11);
3569 __get_user(env->regs[12], &sc->regs.r12);
3570 __get_user(env->regs[13], &sc->regs.r13);
3571 __get_user(env->regs[14], &sc->regs.r14);
3572 __get_user(env->regs[15], &sc->regs.r15);
3573 __get_user(env->regs[16], &sc->regs.r16);
3574 __get_user(env->regs[17], &sc->regs.r17);
3575 __get_user(env->regs[18], &sc->regs.r18);
3576 __get_user(env->regs[19], &sc->regs.r19);
3577 __get_user(env->regs[20], &sc->regs.r20);
3578 __get_user(env->regs[21], &sc->regs.r21);
3579 __get_user(env->regs[22], &sc->regs.r22);
3580 __get_user(env->regs[23], &sc->regs.r23);
3581 __get_user(env->regs[24], &sc->regs.r24);
3582 __get_user(env->regs[25], &sc->regs.r25);
3583 __get_user(env->regs[26], &sc->regs.r26);
3584 __get_user(env->regs[27], &sc->regs.r27);
3585 __get_user(env->regs[28], &sc->regs.r28);
3586 __get_user(env->regs[29], &sc->regs.r29);
3587 __get_user(env->regs[30], &sc->regs.r30);
3588 __get_user(env->regs[31], &sc->regs.r31);
3589 __get_user(env->sregs[SR_PC], &sc->regs.pc);
3590}
3591
3592static abi_ulong get_sigframe(struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01003593 CPUMBState *env, int frame_size)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003594{
3595 abi_ulong sp = env->regs[1];
3596
3597 if ((ka->sa_flags & SA_ONSTACK) != 0 && !on_sig_stack(sp))
3598 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
3599
3600 return ((sp - frame_size) & -8UL);
3601}
3602
3603static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01003604 target_sigset_t *set, CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003605{
3606 struct target_signal_frame *frame;
3607 abi_ulong frame_addr;
3608 int err = 0;
3609 int i;
3610
3611 frame_addr = get_sigframe(ka, env, sizeof *frame);
3612 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
3613 goto badframe;
3614
3615 /* Save the mask. */
Riku Voipio1d8b5122014-04-23 10:26:05 +03003616 __put_user(set->sig[0], &frame->uc.tuc_mcontext.oldmask);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003617 if (err)
3618 goto badframe;
3619
3620 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
3621 if (__put_user(set->sig[i], &frame->extramask[i - 1]))
3622 goto badframe;
3623 }
3624
Richard Hendersonf711df62010-11-22 14:57:52 -08003625 setup_sigcontext(&frame->uc.tuc_mcontext, env);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003626
3627 /* Set up to return from userspace. If provided, use a stub
3628 already in userspace. */
3629 /* minus 8 is offset to cater for "rtsd r15,8" offset */
3630 if (ka->sa_flags & TARGET_SA_RESTORER) {
3631 env->regs[15] = ((unsigned long)ka->sa_restorer)-8;
3632 } else {
3633 uint32_t t;
3634 /* Note, these encodings are _big endian_! */
3635 /* addi r12, r0, __NR_sigreturn */
3636 t = 0x31800000UL | TARGET_NR_sigreturn;
Riku Voipio1d8b5122014-04-23 10:26:05 +03003637 __put_user(t, frame->tramp + 0);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003638 /* brki r14, 0x8 */
3639 t = 0xb9cc0008UL;
Riku Voipio1d8b5122014-04-23 10:26:05 +03003640 __put_user(t, frame->tramp + 1);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003641
3642 /* Return from sighandler will jump to the tramp.
3643 Negative 8 offset because return is rtsd r15, 8 */
3644 env->regs[15] = ((unsigned long)frame->tramp) - 8;
3645 }
3646
3647 if (err)
3648 goto badframe;
3649
3650 /* Set up registers for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003651 env->regs[1] = frame_addr;
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003652 /* Signal handler args: */
3653 env->regs[5] = sig; /* Arg 0: signum */
Edgar E. Iglesias187b4e02010-07-15 15:32:51 +02003654 env->regs[6] = 0;
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003655 /* arg 1: sigcontext */
3656 env->regs[7] = frame_addr += offsetof(typeof(*frame), uc);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003657
3658 /* Offset of 4 to handle microblaze rtid r14, 0 */
3659 env->sregs[SR_PC] = (unsigned long)ka->_sa_handler;
3660
3661 unlock_user_struct(frame, frame_addr, 1);
3662 return;
3663 badframe:
3664 unlock_user_struct(frame, frame_addr, 1);
3665 force_sig(TARGET_SIGSEGV);
3666}
3667
3668static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05003669 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01003670 target_sigset_t *set, CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003671{
3672 fprintf(stderr, "Microblaze setup_rt_frame: not implemented\n");
3673}
3674
Andreas Färber05390242012-02-25 03:37:53 +01003675long do_sigreturn(CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003676{
3677 struct target_signal_frame *frame;
3678 abi_ulong frame_addr;
Anthony Liguoric227f092009-10-01 16:12:16 -05003679 target_sigset_t target_set;
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003680 sigset_t set;
3681 int i;
3682
3683 frame_addr = env->regs[R_SP];
3684 /* Make sure the guest isn't playing games. */
3685 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 1))
3686 goto badframe;
3687
3688 /* Restore blocked signals */
Richard Hendersonf711df62010-11-22 14:57:52 -08003689 if (__get_user(target_set.sig[0], &frame->uc.tuc_mcontext.oldmask))
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003690 goto badframe;
3691 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
3692 if (__get_user(target_set.sig[i], &frame->extramask[i - 1]))
3693 goto badframe;
3694 }
3695 target_to_host_sigset_internal(&set, &target_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00003696 do_sigprocmask(SIG_SETMASK, &set, NULL);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003697
Richard Hendersonf711df62010-11-22 14:57:52 -08003698 restore_sigcontext(&frame->uc.tuc_mcontext, env);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003699 /* We got here through a sigreturn syscall, our path back is via an
3700 rtb insn so setup r14 for that. */
3701 env->regs[14] = env->sregs[SR_PC];
3702
3703 unlock_user_struct(frame, frame_addr, 0);
3704 return env->regs[10];
3705 badframe:
3706 unlock_user_struct(frame, frame_addr, 0);
3707 force_sig(TARGET_SIGSEGV);
3708}
3709
Andreas Färber05390242012-02-25 03:37:53 +01003710long do_rt_sigreturn(CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003711{
3712 fprintf(stderr, "Microblaze do_rt_sigreturn: not implemented\n");
3713 return -TARGET_ENOSYS;
3714}
3715
edgar_iglb6d3abd2008-02-28 11:29:27 +00003716#elif defined(TARGET_CRIS)
3717
3718struct target_sigcontext {
3719 struct target_pt_regs regs; /* needs to be first */
3720 uint32_t oldmask;
3721 uint32_t usp; /* usp before stacking this gunk on it */
3722};
3723
3724/* Signal frames. */
3725struct target_signal_frame {
3726 struct target_sigcontext sc;
3727 uint32_t extramask[TARGET_NSIG_WORDS - 1];
Stefan Weil8cfc1142014-02-01 09:41:09 +01003728 uint16_t retcode[4]; /* Trampoline code. */
edgar_iglb6d3abd2008-02-28 11:29:27 +00003729};
3730
3731struct rt_signal_frame {
Richard W.M. Jones02d2bd52012-07-05 03:32:44 +00003732 siginfo_t *pinfo;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003733 void *puc;
Richard W.M. Jones02d2bd52012-07-05 03:32:44 +00003734 siginfo_t info;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003735 struct ucontext uc;
Stefan Weil8cfc1142014-02-01 09:41:09 +01003736 uint16_t retcode[4]; /* Trampoline code. */
edgar_iglb6d3abd2008-02-28 11:29:27 +00003737};
3738
Andreas Färber05390242012-02-25 03:37:53 +01003739static void setup_sigcontext(struct target_sigcontext *sc, CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003740{
edgar_igl9664d922008-03-03 22:23:53 +00003741 __put_user(env->regs[0], &sc->regs.r0);
3742 __put_user(env->regs[1], &sc->regs.r1);
3743 __put_user(env->regs[2], &sc->regs.r2);
3744 __put_user(env->regs[3], &sc->regs.r3);
3745 __put_user(env->regs[4], &sc->regs.r4);
3746 __put_user(env->regs[5], &sc->regs.r5);
3747 __put_user(env->regs[6], &sc->regs.r6);
3748 __put_user(env->regs[7], &sc->regs.r7);
3749 __put_user(env->regs[8], &sc->regs.r8);
3750 __put_user(env->regs[9], &sc->regs.r9);
3751 __put_user(env->regs[10], &sc->regs.r10);
3752 __put_user(env->regs[11], &sc->regs.r11);
3753 __put_user(env->regs[12], &sc->regs.r12);
3754 __put_user(env->regs[13], &sc->regs.r13);
3755 __put_user(env->regs[14], &sc->usp);
3756 __put_user(env->regs[15], &sc->regs.acr);
3757 __put_user(env->pregs[PR_MOF], &sc->regs.mof);
3758 __put_user(env->pregs[PR_SRP], &sc->regs.srp);
3759 __put_user(env->pc, &sc->regs.erp);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003760}
edgar_igl9664d922008-03-03 22:23:53 +00003761
Andreas Färber05390242012-02-25 03:37:53 +01003762static void restore_sigcontext(struct target_sigcontext *sc, CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003763{
edgar_igl9664d922008-03-03 22:23:53 +00003764 __get_user(env->regs[0], &sc->regs.r0);
3765 __get_user(env->regs[1], &sc->regs.r1);
3766 __get_user(env->regs[2], &sc->regs.r2);
3767 __get_user(env->regs[3], &sc->regs.r3);
3768 __get_user(env->regs[4], &sc->regs.r4);
3769 __get_user(env->regs[5], &sc->regs.r5);
3770 __get_user(env->regs[6], &sc->regs.r6);
3771 __get_user(env->regs[7], &sc->regs.r7);
3772 __get_user(env->regs[8], &sc->regs.r8);
3773 __get_user(env->regs[9], &sc->regs.r9);
3774 __get_user(env->regs[10], &sc->regs.r10);
3775 __get_user(env->regs[11], &sc->regs.r11);
3776 __get_user(env->regs[12], &sc->regs.r12);
3777 __get_user(env->regs[13], &sc->regs.r13);
3778 __get_user(env->regs[14], &sc->usp);
3779 __get_user(env->regs[15], &sc->regs.acr);
3780 __get_user(env->pregs[PR_MOF], &sc->regs.mof);
3781 __get_user(env->pregs[PR_SRP], &sc->regs.srp);
3782 __get_user(env->pc, &sc->regs.erp);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003783}
3784
Andreas Färber05390242012-02-25 03:37:53 +01003785static abi_ulong get_sigframe(CPUCRISState *env, int framesize)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003786{
edgar_igl9664d922008-03-03 22:23:53 +00003787 abi_ulong sp;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003788 /* Align the stack downwards to 4. */
edgar_igl9664d922008-03-03 22:23:53 +00003789 sp = (env->regs[R_SP] & ~3);
3790 return sp - framesize;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003791}
3792
pbrook624f7972008-05-31 16:11:38 +00003793static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01003794 target_sigset_t *set, CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003795{
3796 struct target_signal_frame *frame;
edgar_igl9664d922008-03-03 22:23:53 +00003797 abi_ulong frame_addr;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003798 int err = 0;
3799 int i;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003800
edgar_igl9664d922008-03-03 22:23:53 +00003801 frame_addr = get_sigframe(env, sizeof *frame);
3802 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
edgar_iglb6d3abd2008-02-28 11:29:27 +00003803 goto badframe;
3804
3805 /*
3806 * The CRIS signal return trampoline. A real linux/CRIS kernel doesn't
3807 * use this trampoline anymore but it sets it up for GDB.
3808 * In QEMU, using the trampoline simplifies things a bit so we use it.
3809 *
3810 * This is movu.w __NR_sigreturn, r9; break 13;
3811 */
Riku Voipio1d8b5122014-04-23 10:26:05 +03003812 __put_user(0x9c5f, frame->retcode+0);
3813 __put_user(TARGET_NR_sigreturn,
3814 frame->retcode + 1);
3815 __put_user(0xe93d, frame->retcode + 2);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003816
3817 /* Save the mask. */
Riku Voipio1d8b5122014-04-23 10:26:05 +03003818 __put_user(set->sig[0], &frame->sc.oldmask);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003819 if (err)
3820 goto badframe;
3821
3822 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
3823 if (__put_user(set->sig[i], &frame->extramask[i - 1]))
3824 goto badframe;
3825 }
3826
3827 setup_sigcontext(&frame->sc, env);
3828
3829 /* Move the stack and setup the arguments for the handler. */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003830 env->regs[R_SP] = frame_addr;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003831 env->regs[10] = sig;
pbrook624f7972008-05-31 16:11:38 +00003832 env->pc = (unsigned long) ka->_sa_handler;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003833 /* Link SRP so the guest returns through the trampoline. */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003834 env->pregs[PR_SRP] = frame_addr + offsetof(typeof(*frame), retcode);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003835
edgar_igl9664d922008-03-03 22:23:53 +00003836 unlock_user_struct(frame, frame_addr, 1);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003837 return;
3838 badframe:
edgar_igl9664d922008-03-03 22:23:53 +00003839 unlock_user_struct(frame, frame_addr, 1);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003840 force_sig(TARGET_SIGSEGV);
3841}
3842
pbrook624f7972008-05-31 16:11:38 +00003843static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05003844 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01003845 target_sigset_t *set, CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003846{
3847 fprintf(stderr, "CRIS setup_rt_frame: not implemented\n");
3848}
3849
Andreas Färber05390242012-02-25 03:37:53 +01003850long do_sigreturn(CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003851{
3852 struct target_signal_frame *frame;
edgar_igl9664d922008-03-03 22:23:53 +00003853 abi_ulong frame_addr;
Anthony Liguoric227f092009-10-01 16:12:16 -05003854 target_sigset_t target_set;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003855 sigset_t set;
3856 int i;
3857
edgar_igl9664d922008-03-03 22:23:53 +00003858 frame_addr = env->regs[R_SP];
edgar_iglb6d3abd2008-02-28 11:29:27 +00003859 /* Make sure the guest isn't playing games. */
edgar_igl9664d922008-03-03 22:23:53 +00003860 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 1))
edgar_iglb6d3abd2008-02-28 11:29:27 +00003861 goto badframe;
3862
3863 /* Restore blocked signals */
3864 if (__get_user(target_set.sig[0], &frame->sc.oldmask))
3865 goto badframe;
3866 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
3867 if (__get_user(target_set.sig[i], &frame->extramask[i - 1]))
3868 goto badframe;
3869 }
3870 target_to_host_sigset_internal(&set, &target_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00003871 do_sigprocmask(SIG_SETMASK, &set, NULL);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003872
3873 restore_sigcontext(&frame->sc, env);
edgar_igl9664d922008-03-03 22:23:53 +00003874 unlock_user_struct(frame, frame_addr, 0);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003875 return env->regs[10];
3876 badframe:
edgar_igl9664d922008-03-03 22:23:53 +00003877 unlock_user_struct(frame, frame_addr, 0);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003878 force_sig(TARGET_SIGSEGV);
3879}
3880
Andreas Färber05390242012-02-25 03:37:53 +01003881long do_rt_sigreturn(CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003882{
3883 fprintf(stderr, "CRIS do_rt_sigreturn: not implemented\n");
3884 return -TARGET_ENOSYS;
3885}
thsc3b5bc82007-12-02 06:31:25 +00003886
Jia Liud9627832012-07-20 15:50:52 +08003887#elif defined(TARGET_OPENRISC)
3888
3889struct target_sigcontext {
3890 struct target_pt_regs regs;
3891 abi_ulong oldmask;
3892 abi_ulong usp;
3893};
3894
3895struct target_ucontext {
3896 abi_ulong tuc_flags;
3897 abi_ulong tuc_link;
3898 target_stack_t tuc_stack;
3899 struct target_sigcontext tuc_mcontext;
3900 target_sigset_t tuc_sigmask; /* mask last for extensibility */
3901};
3902
3903struct target_rt_sigframe {
3904 abi_ulong pinfo;
3905 uint64_t puc;
3906 struct target_siginfo info;
3907 struct target_sigcontext sc;
3908 struct target_ucontext uc;
3909 unsigned char retcode[16]; /* trampoline code */
3910};
3911
3912/* This is the asm-generic/ucontext.h version */
3913#if 0
3914static int restore_sigcontext(CPUOpenRISCState *regs,
3915 struct target_sigcontext *sc)
3916{
3917 unsigned int err = 0;
3918 unsigned long old_usp;
3919
3920 /* Alwys make any pending restarted system call return -EINTR */
3921 current_thread_info()->restart_block.fn = do_no_restart_syscall;
3922
3923 /* restore the regs from &sc->regs (same as sc, since regs is first)
3924 * (sc is already checked for VERIFY_READ since the sigframe was
3925 * checked in sys_sigreturn previously)
3926 */
3927
3928 if (copy_from_user(regs, &sc, sizeof(struct target_pt_regs))) {
3929 goto badframe;
3930 }
3931
3932 /* make sure the U-flag is set so user-mode cannot fool us */
3933
3934 regs->sr &= ~SR_SM;
3935
3936 /* restore the old USP as it was before we stacked the sc etc.
3937 * (we cannot just pop the sigcontext since we aligned the sp and
3938 * stuff after pushing it)
3939 */
3940
Riku Voipio1d8b5122014-04-23 10:26:05 +03003941 __get_user(old_usp, &sc->usp);
Jia Liud9627832012-07-20 15:50:52 +08003942 phx_signal("old_usp 0x%lx", old_usp);
3943
3944 __PHX__ REALLY /* ??? */
3945 wrusp(old_usp);
3946 regs->gpr[1] = old_usp;
3947
3948 /* TODO: the other ports use regs->orig_XX to disable syscall checks
3949 * after this completes, but we don't use that mechanism. maybe we can
3950 * use it now ?
3951 */
3952
3953 return err;
3954
3955badframe:
3956 return 1;
3957}
3958#endif
3959
3960/* Set up a signal frame. */
3961
3962static int setup_sigcontext(struct target_sigcontext *sc,
3963 CPUOpenRISCState *regs,
3964 unsigned long mask)
3965{
3966 int err = 0;
3967 unsigned long usp = regs->gpr[1];
3968
3969 /* copy the regs. they are first in sc so we can use sc directly */
3970
Riku Voipio1d8b5122014-04-23 10:26:05 +03003971 /*copy_to_user(&sc, regs, sizeof(struct target_pt_regs));*/
Jia Liud9627832012-07-20 15:50:52 +08003972
3973 /* Set the frametype to CRIS_FRAME_NORMAL for the execution of
3974 the signal handler. The frametype will be restored to its previous
3975 value in restore_sigcontext. */
3976 /*regs->frametype = CRIS_FRAME_NORMAL;*/
3977
3978 /* then some other stuff */
Riku Voipio1d8b5122014-04-23 10:26:05 +03003979 __put_user(mask, &sc->oldmask);
3980 __put_user(usp, &sc->usp); return err;
Jia Liud9627832012-07-20 15:50:52 +08003981}
3982
3983static inline unsigned long align_sigframe(unsigned long sp)
3984{
3985 unsigned long i;
3986 i = sp & ~3UL;
3987 return i;
3988}
3989
3990static inline abi_ulong get_sigframe(struct target_sigaction *ka,
3991 CPUOpenRISCState *regs,
3992 size_t frame_size)
3993{
3994 unsigned long sp = regs->gpr[1];
3995 int onsigstack = on_sig_stack(sp);
3996
3997 /* redzone */
3998 /* This is the X/Open sanctioned signal stack switching. */
3999 if ((ka->sa_flags & SA_ONSTACK) != 0 && !onsigstack) {
4000 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
4001 }
4002
4003 sp = align_sigframe(sp - frame_size);
4004
4005 /*
4006 * If we are on the alternate signal stack and would overflow it, don't.
4007 * Return an always-bogus address instead so we will die with SIGSEGV.
4008 */
4009
4010 if (onsigstack && !likely(on_sig_stack(sp))) {
4011 return -1L;
4012 }
4013
4014 return sp;
4015}
4016
4017static void setup_frame(int sig, struct target_sigaction *ka,
4018 target_sigset_t *set, CPUOpenRISCState *env)
4019{
4020 qemu_log("Not implement.\n");
4021}
4022
4023static void setup_rt_frame(int sig, struct target_sigaction *ka,
4024 target_siginfo_t *info,
4025 target_sigset_t *set, CPUOpenRISCState *env)
4026{
4027 int err = 0;
4028 abi_ulong frame_addr;
4029 unsigned long return_ip;
4030 struct target_rt_sigframe *frame;
4031 abi_ulong info_addr, uc_addr;
4032
Jia Liud9627832012-07-20 15:50:52 +08004033 frame_addr = get_sigframe(ka, env, sizeof(*frame));
4034 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
4035 goto give_sigsegv;
4036 }
4037
4038 info_addr = frame_addr + offsetof(struct target_rt_sigframe, info);
Riku Voipio1d8b5122014-04-23 10:26:05 +03004039 __put_user(info_addr, &frame->pinfo);
Jia Liud9627832012-07-20 15:50:52 +08004040 uc_addr = frame_addr + offsetof(struct target_rt_sigframe, uc);
Riku Voipio1d8b5122014-04-23 10:26:05 +03004041 __put_user(uc_addr, &frame->puc);
Jia Liud9627832012-07-20 15:50:52 +08004042
4043 if (ka->sa_flags & SA_SIGINFO) {
4044 err |= copy_siginfo_to_user(&frame->info, info);
4045 }
4046 if (err) {
4047 goto give_sigsegv;
4048 }
4049
4050 /*err |= __clear_user(&frame->uc, offsetof(struct ucontext, uc_mcontext));*/
Riku Voipio1d8b5122014-04-23 10:26:05 +03004051 __put_user(0, &frame->uc.tuc_flags);
4052 __put_user(0, &frame->uc.tuc_link);
4053 __put_user(target_sigaltstack_used.ss_sp,
4054 &frame->uc.tuc_stack.ss_sp);
4055 __put_user(sas_ss_flags(env->gpr[1]), &frame->uc.tuc_stack.ss_flags);
4056 __put_user(target_sigaltstack_used.ss_size,
4057 &frame->uc.tuc_stack.ss_size);
Jia Liud9627832012-07-20 15:50:52 +08004058 err |= setup_sigcontext(&frame->sc, env, set->sig[0]);
4059
4060 /*err |= copy_to_user(frame->uc.tuc_sigmask, set, sizeof(*set));*/
4061
4062 if (err) {
4063 goto give_sigsegv;
4064 }
4065
4066 /* trampoline - the desired return ip is the retcode itself */
4067 return_ip = (unsigned long)&frame->retcode;
4068 /* This is l.ori r11,r0,__NR_sigreturn, l.sys 1 */
Riku Voipio1d8b5122014-04-23 10:26:05 +03004069 __put_user(0xa960, (short *)(frame->retcode + 0));
4070 __put_user(TARGET_NR_rt_sigreturn, (short *)(frame->retcode + 2));
4071 __put_user(0x20000001, (unsigned long *)(frame->retcode + 4));
4072 __put_user(0x15000000, (unsigned long *)(frame->retcode + 8));
Jia Liud9627832012-07-20 15:50:52 +08004073
4074 if (err) {
4075 goto give_sigsegv;
4076 }
4077
4078 /* TODO what is the current->exec_domain stuff and invmap ? */
4079
4080 /* Set up registers for signal handler */
4081 env->pc = (unsigned long)ka->_sa_handler; /* what we enter NOW */
4082 env->gpr[9] = (unsigned long)return_ip; /* what we enter LATER */
4083 env->gpr[3] = (unsigned long)sig; /* arg 1: signo */
4084 env->gpr[4] = (unsigned long)&frame->info; /* arg 2: (siginfo_t*) */
4085 env->gpr[5] = (unsigned long)&frame->uc; /* arg 3: ucontext */
4086
4087 /* actually move the usp to reflect the stacked frame */
4088 env->gpr[1] = (unsigned long)frame;
4089
4090 return;
4091
4092give_sigsegv:
4093 unlock_user_struct(frame, frame_addr, 1);
4094 if (sig == TARGET_SIGSEGV) {
4095 ka->_sa_handler = TARGET_SIG_DFL;
4096 }
4097 force_sig(TARGET_SIGSEGV);
4098}
4099
4100long do_sigreturn(CPUOpenRISCState *env)
4101{
4102
4103 qemu_log("do_sigreturn: not implemented\n");
4104 return -TARGET_ENOSYS;
4105}
4106
4107long do_rt_sigreturn(CPUOpenRISCState *env)
4108{
4109 qemu_log("do_rt_sigreturn: not implemented\n");
4110 return -TARGET_ENOSYS;
4111}
4112/* TARGET_OPENRISC */
4113
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004114#elif defined(TARGET_S390X)
4115
4116#define __NUM_GPRS 16
4117#define __NUM_FPRS 16
4118#define __NUM_ACRS 16
4119
4120#define S390_SYSCALL_SIZE 2
4121#define __SIGNAL_FRAMESIZE 160 /* FIXME: 31-bit mode -> 96 */
4122
4123#define _SIGCONTEXT_NSIG 64
4124#define _SIGCONTEXT_NSIG_BPW 64 /* FIXME: 31-bit mode -> 32 */
4125#define _SIGCONTEXT_NSIG_WORDS (_SIGCONTEXT_NSIG / _SIGCONTEXT_NSIG_BPW)
4126#define _SIGMASK_COPY_SIZE (sizeof(unsigned long)*_SIGCONTEXT_NSIG_WORDS)
4127#define PSW_ADDR_AMODE 0x0000000000000000UL /* 0x80000000UL for 31-bit */
4128#define S390_SYSCALL_OPCODE ((uint16_t)0x0a00)
4129
4130typedef struct {
4131 target_psw_t psw;
4132 target_ulong gprs[__NUM_GPRS];
4133 unsigned int acrs[__NUM_ACRS];
4134} target_s390_regs_common;
4135
4136typedef struct {
4137 unsigned int fpc;
4138 double fprs[__NUM_FPRS];
4139} target_s390_fp_regs;
4140
4141typedef struct {
4142 target_s390_regs_common regs;
4143 target_s390_fp_regs fpregs;
4144} target_sigregs;
4145
4146struct target_sigcontext {
4147 target_ulong oldmask[_SIGCONTEXT_NSIG_WORDS];
4148 target_sigregs *sregs;
4149};
4150
4151typedef struct {
4152 uint8_t callee_used_stack[__SIGNAL_FRAMESIZE];
4153 struct target_sigcontext sc;
4154 target_sigregs sregs;
4155 int signo;
4156 uint8_t retcode[S390_SYSCALL_SIZE];
4157} sigframe;
4158
4159struct target_ucontext {
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004160 target_ulong tuc_flags;
4161 struct target_ucontext *tuc_link;
4162 target_stack_t tuc_stack;
4163 target_sigregs tuc_mcontext;
4164 target_sigset_t tuc_sigmask; /* mask last for extensibility */
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004165};
4166
4167typedef struct {
4168 uint8_t callee_used_stack[__SIGNAL_FRAMESIZE];
4169 uint8_t retcode[S390_SYSCALL_SIZE];
4170 struct target_siginfo info;
4171 struct target_ucontext uc;
4172} rt_sigframe;
4173
4174static inline abi_ulong
Andreas Färber05390242012-02-25 03:37:53 +01004175get_sigframe(struct target_sigaction *ka, CPUS390XState *env, size_t frame_size)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004176{
4177 abi_ulong sp;
4178
4179 /* Default to using normal stack */
4180 sp = env->regs[15];
4181
4182 /* This is the X/Open sanctioned signal stack switching. */
4183 if (ka->sa_flags & TARGET_SA_ONSTACK) {
4184 if (!sas_ss_flags(sp)) {
4185 sp = target_sigaltstack_used.ss_sp +
4186 target_sigaltstack_used.ss_size;
4187 }
4188 }
4189
4190 /* This is the legacy signal stack switching. */
4191 else if (/* FIXME !user_mode(regs) */ 0 &&
4192 !(ka->sa_flags & TARGET_SA_RESTORER) &&
4193 ka->sa_restorer) {
4194 sp = (abi_ulong) ka->sa_restorer;
4195 }
4196
4197 return (sp - frame_size) & -8ul;
4198}
4199
Andreas Färber05390242012-02-25 03:37:53 +01004200static void save_sigregs(CPUS390XState *env, target_sigregs *sregs)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004201{
4202 int i;
4203 //save_access_regs(current->thread.acrs); FIXME
4204
4205 /* Copy a 'clean' PSW mask to the user to avoid leaking
4206 information about whether PER is currently on. */
4207 __put_user(env->psw.mask, &sregs->regs.psw.mask);
4208 __put_user(env->psw.addr, &sregs->regs.psw.addr);
4209 for (i = 0; i < 16; i++) {
4210 __put_user(env->regs[i], &sregs->regs.gprs[i]);
4211 }
4212 for (i = 0; i < 16; i++) {
4213 __put_user(env->aregs[i], &sregs->regs.acrs[i]);
4214 }
4215 /*
4216 * We have to store the fp registers to current->thread.fp_regs
4217 * to merge them with the emulated registers.
4218 */
4219 //save_fp_regs(&current->thread.fp_regs); FIXME
4220 for (i = 0; i < 16; i++) {
4221 __put_user(env->fregs[i].ll, &sregs->fpregs.fprs[i]);
4222 }
4223}
4224
4225static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01004226 target_sigset_t *set, CPUS390XState *env)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004227{
4228 sigframe *frame;
4229 abi_ulong frame_addr;
4230
4231 frame_addr = get_sigframe(ka, env, sizeof(*frame));
4232 qemu_log("%s: frame_addr 0x%llx\n", __FUNCTION__,
4233 (unsigned long long)frame_addr);
4234 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
4235 goto give_sigsegv;
4236 }
4237
4238 qemu_log("%s: 1\n", __FUNCTION__);
4239 if (__put_user(set->sig[0], &frame->sc.oldmask[0])) {
4240 goto give_sigsegv;
4241 }
4242
4243 save_sigregs(env, &frame->sregs);
4244
4245 __put_user((abi_ulong)(unsigned long)&frame->sregs,
4246 (abi_ulong *)&frame->sc.sregs);
4247
4248 /* Set up to return from userspace. If provided, use a stub
4249 already in userspace. */
4250 if (ka->sa_flags & TARGET_SA_RESTORER) {
4251 env->regs[14] = (unsigned long)
4252 ka->sa_restorer | PSW_ADDR_AMODE;
4253 } else {
4254 env->regs[14] = (unsigned long)
4255 frame->retcode | PSW_ADDR_AMODE;
4256 if (__put_user(S390_SYSCALL_OPCODE | TARGET_NR_sigreturn,
4257 (uint16_t *)(frame->retcode)))
4258 goto give_sigsegv;
4259 }
4260
4261 /* Set up backchain. */
4262 if (__put_user(env->regs[15], (abi_ulong *) frame)) {
4263 goto give_sigsegv;
4264 }
4265
4266 /* Set up registers for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02004267 env->regs[15] = frame_addr;
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004268 env->psw.addr = (target_ulong) ka->_sa_handler | PSW_ADDR_AMODE;
4269
4270 env->regs[2] = sig; //map_signal(sig);
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02004271 env->regs[3] = frame_addr += offsetof(typeof(*frame), sc);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004272
4273 /* We forgot to include these in the sigcontext.
4274 To avoid breaking binary compatibility, they are passed as args. */
4275 env->regs[4] = 0; // FIXME: no clue... current->thread.trap_no;
4276 env->regs[5] = 0; // FIXME: no clue... current->thread.prot_addr;
4277
4278 /* Place signal number on stack to allow backtrace from handler. */
4279 if (__put_user(env->regs[2], (int *) &frame->signo)) {
4280 goto give_sigsegv;
4281 }
4282 unlock_user_struct(frame, frame_addr, 1);
4283 return;
4284
4285give_sigsegv:
4286 qemu_log("%s: give_sigsegv\n", __FUNCTION__);
4287 unlock_user_struct(frame, frame_addr, 1);
4288 force_sig(TARGET_SIGSEGV);
4289}
4290
4291static void setup_rt_frame(int sig, struct target_sigaction *ka,
4292 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01004293 target_sigset_t *set, CPUS390XState *env)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004294{
4295 int i;
4296 rt_sigframe *frame;
4297 abi_ulong frame_addr;
4298
4299 frame_addr = get_sigframe(ka, env, sizeof *frame);
4300 qemu_log("%s: frame_addr 0x%llx\n", __FUNCTION__,
4301 (unsigned long long)frame_addr);
4302 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
4303 goto give_sigsegv;
4304 }
4305
4306 qemu_log("%s: 1\n", __FUNCTION__);
4307 if (copy_siginfo_to_user(&frame->info, info)) {
4308 goto give_sigsegv;
4309 }
4310
4311 /* Create the ucontext. */
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004312 __put_user(0, &frame->uc.tuc_flags);
4313 __put_user((abi_ulong)0, (abi_ulong *)&frame->uc.tuc_link);
4314 __put_user(target_sigaltstack_used.ss_sp, &frame->uc.tuc_stack.ss_sp);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004315 __put_user(sas_ss_flags(get_sp_from_cpustate(env)),
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004316 &frame->uc.tuc_stack.ss_flags);
4317 __put_user(target_sigaltstack_used.ss_size, &frame->uc.tuc_stack.ss_size);
4318 save_sigregs(env, &frame->uc.tuc_mcontext);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004319 for (i = 0; i < TARGET_NSIG_WORDS; i++) {
4320 __put_user((abi_ulong)set->sig[i],
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004321 (abi_ulong *)&frame->uc.tuc_sigmask.sig[i]);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004322 }
4323
4324 /* Set up to return from userspace. If provided, use a stub
4325 already in userspace. */
4326 if (ka->sa_flags & TARGET_SA_RESTORER) {
4327 env->regs[14] = (unsigned long) ka->sa_restorer | PSW_ADDR_AMODE;
4328 } else {
4329 env->regs[14] = (unsigned long) frame->retcode | PSW_ADDR_AMODE;
4330 if (__put_user(S390_SYSCALL_OPCODE | TARGET_NR_rt_sigreturn,
4331 (uint16_t *)(frame->retcode))) {
4332 goto give_sigsegv;
4333 }
4334 }
4335
4336 /* Set up backchain. */
4337 if (__put_user(env->regs[15], (abi_ulong *) frame)) {
4338 goto give_sigsegv;
4339 }
4340
4341 /* Set up registers for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02004342 env->regs[15] = frame_addr;
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004343 env->psw.addr = (target_ulong) ka->_sa_handler | PSW_ADDR_AMODE;
4344
4345 env->regs[2] = sig; //map_signal(sig);
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02004346 env->regs[3] = frame_addr + offsetof(typeof(*frame), info);
4347 env->regs[4] = frame_addr + offsetof(typeof(*frame), uc);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004348 return;
4349
4350give_sigsegv:
4351 qemu_log("%s: give_sigsegv\n", __FUNCTION__);
4352 unlock_user_struct(frame, frame_addr, 1);
4353 force_sig(TARGET_SIGSEGV);
4354}
4355
4356static int
Andreas Färber05390242012-02-25 03:37:53 +01004357restore_sigregs(CPUS390XState *env, target_sigregs *sc)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004358{
4359 int err = 0;
4360 int i;
4361
4362 for (i = 0; i < 16; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03004363 __get_user(env->regs[i], &sc->regs.gprs[i]);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004364 }
4365
Riku Voipio1d8b5122014-04-23 10:26:05 +03004366 __get_user(env->psw.mask, &sc->regs.psw.mask);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004367 qemu_log("%s: sc->regs.psw.addr 0x%llx env->psw.addr 0x%llx\n",
4368 __FUNCTION__, (unsigned long long)sc->regs.psw.addr,
4369 (unsigned long long)env->psw.addr);
Riku Voipio1d8b5122014-04-23 10:26:05 +03004370 __get_user(env->psw.addr, &sc->regs.psw.addr);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004371 /* FIXME: 31-bit -> | PSW_ADDR_AMODE */
4372
4373 for (i = 0; i < 16; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03004374 __get_user(env->aregs[i], &sc->regs.acrs[i]);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004375 }
4376 for (i = 0; i < 16; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03004377 __get_user(env->fregs[i].ll, &sc->fpregs.fprs[i]);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004378 }
4379
4380 return err;
4381}
4382
Andreas Färber05390242012-02-25 03:37:53 +01004383long do_sigreturn(CPUS390XState *env)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004384{
4385 sigframe *frame;
4386 abi_ulong frame_addr = env->regs[15];
4387 qemu_log("%s: frame_addr 0x%llx\n", __FUNCTION__,
4388 (unsigned long long)frame_addr);
4389 target_sigset_t target_set;
4390 sigset_t set;
4391
4392 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
4393 goto badframe;
4394 }
4395 if (__get_user(target_set.sig[0], &frame->sc.oldmask[0])) {
4396 goto badframe;
4397 }
4398
4399 target_to_host_sigset_internal(&set, &target_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00004400 do_sigprocmask(SIG_SETMASK, &set, NULL); /* ~_BLOCKABLE? */
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004401
4402 if (restore_sigregs(env, &frame->sregs)) {
4403 goto badframe;
4404 }
4405
4406 unlock_user_struct(frame, frame_addr, 0);
4407 return env->regs[2];
4408
4409badframe:
4410 unlock_user_struct(frame, frame_addr, 0);
4411 force_sig(TARGET_SIGSEGV);
4412 return 0;
4413}
4414
Andreas Färber05390242012-02-25 03:37:53 +01004415long do_rt_sigreturn(CPUS390XState *env)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004416{
4417 rt_sigframe *frame;
4418 abi_ulong frame_addr = env->regs[15];
4419 qemu_log("%s: frame_addr 0x%llx\n", __FUNCTION__,
4420 (unsigned long long)frame_addr);
4421 sigset_t set;
4422
4423 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
4424 goto badframe;
4425 }
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004426 target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004427
Alex Barcelo1c275922014-03-14 14:36:55 +00004428 do_sigprocmask(SIG_SETMASK, &set, NULL); /* ~_BLOCKABLE? */
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004429
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004430 if (restore_sigregs(env, &frame->uc.tuc_mcontext)) {
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004431 goto badframe;
4432 }
4433
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004434 if (do_sigaltstack(frame_addr + offsetof(rt_sigframe, uc.tuc_stack), 0,
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004435 get_sp_from_cpustate(env)) == -EFAULT) {
4436 goto badframe;
4437 }
4438 unlock_user_struct(frame, frame_addr, 0);
4439 return env->regs[2];
4440
4441badframe:
4442 unlock_user_struct(frame, frame_addr, 0);
4443 force_sig(TARGET_SIGSEGV);
4444 return 0;
4445}
4446
Nathan Froydbcd49332009-05-12 19:13:18 -07004447#elif defined(TARGET_PPC) && !defined(TARGET_PPC64)
4448
4449/* FIXME: Many of the structures are defined for both PPC and PPC64, but
4450 the signal handling is different enough that we haven't implemented
4451 support for PPC64 yet. Hence the restriction above.
4452
4453 There are various #if'd blocks for code for TARGET_PPC64. These
4454 blocks should go away so that we can successfully run 32-bit and
4455 64-bit binaries on a QEMU configured for PPC64. */
4456
4457/* Size of dummy stack frame allocated when calling signal handler.
4458 See arch/powerpc/include/asm/ptrace.h. */
4459#if defined(TARGET_PPC64)
4460#define SIGNAL_FRAMESIZE 128
4461#else
4462#define SIGNAL_FRAMESIZE 64
4463#endif
4464
4465/* See arch/powerpc/include/asm/sigcontext.h. */
4466struct target_sigcontext {
4467 target_ulong _unused[4];
4468 int32_t signal;
4469#if defined(TARGET_PPC64)
4470 int32_t pad0;
4471#endif
4472 target_ulong handler;
4473 target_ulong oldmask;
4474 target_ulong regs; /* struct pt_regs __user * */
4475 /* TODO: PPC64 includes extra bits here. */
4476};
4477
4478/* Indices for target_mcontext.mc_gregs, below.
4479 See arch/powerpc/include/asm/ptrace.h for details. */
4480enum {
4481 TARGET_PT_R0 = 0,
4482 TARGET_PT_R1 = 1,
4483 TARGET_PT_R2 = 2,
4484 TARGET_PT_R3 = 3,
4485 TARGET_PT_R4 = 4,
4486 TARGET_PT_R5 = 5,
4487 TARGET_PT_R6 = 6,
4488 TARGET_PT_R7 = 7,
4489 TARGET_PT_R8 = 8,
4490 TARGET_PT_R9 = 9,
4491 TARGET_PT_R10 = 10,
4492 TARGET_PT_R11 = 11,
4493 TARGET_PT_R12 = 12,
4494 TARGET_PT_R13 = 13,
4495 TARGET_PT_R14 = 14,
4496 TARGET_PT_R15 = 15,
4497 TARGET_PT_R16 = 16,
4498 TARGET_PT_R17 = 17,
4499 TARGET_PT_R18 = 18,
4500 TARGET_PT_R19 = 19,
4501 TARGET_PT_R20 = 20,
4502 TARGET_PT_R21 = 21,
4503 TARGET_PT_R22 = 22,
4504 TARGET_PT_R23 = 23,
4505 TARGET_PT_R24 = 24,
4506 TARGET_PT_R25 = 25,
4507 TARGET_PT_R26 = 26,
4508 TARGET_PT_R27 = 27,
4509 TARGET_PT_R28 = 28,
4510 TARGET_PT_R29 = 29,
4511 TARGET_PT_R30 = 30,
4512 TARGET_PT_R31 = 31,
4513 TARGET_PT_NIP = 32,
4514 TARGET_PT_MSR = 33,
4515 TARGET_PT_ORIG_R3 = 34,
4516 TARGET_PT_CTR = 35,
4517 TARGET_PT_LNK = 36,
4518 TARGET_PT_XER = 37,
4519 TARGET_PT_CCR = 38,
4520 /* Yes, there are two registers with #39. One is 64-bit only. */
4521 TARGET_PT_MQ = 39,
4522 TARGET_PT_SOFTE = 39,
4523 TARGET_PT_TRAP = 40,
4524 TARGET_PT_DAR = 41,
4525 TARGET_PT_DSISR = 42,
4526 TARGET_PT_RESULT = 43,
4527 TARGET_PT_REGS_COUNT = 44
4528};
4529
4530/* See arch/powerpc/include/asm/ucontext.h. Only used for 32-bit PPC;
4531 on 64-bit PPC, sigcontext and mcontext are one and the same. */
4532struct target_mcontext {
4533 target_ulong mc_gregs[48];
4534 /* Includes fpscr. */
4535 uint64_t mc_fregs[33];
4536 target_ulong mc_pad[2];
4537 /* We need to handle Altivec and SPE at the same time, which no
4538 kernel needs to do. Fortunately, the kernel defines this bit to
4539 be Altivec-register-large all the time, rather than trying to
4540 twiddle it based on the specific platform. */
4541 union {
4542 /* SPE vector registers. One extra for SPEFSCR. */
4543 uint32_t spe[33];
4544 /* Altivec vector registers. The packing of VSCR and VRSAVE
4545 varies depending on whether we're PPC64 or not: PPC64 splits
4546 them apart; PPC32 stuffs them together. */
4547#if defined(TARGET_PPC64)
malc3efa9a62009-07-18 13:10:12 +04004548#define QEMU_NVRREG 34
Nathan Froydbcd49332009-05-12 19:13:18 -07004549#else
malc3efa9a62009-07-18 13:10:12 +04004550#define QEMU_NVRREG 33
Nathan Froydbcd49332009-05-12 19:13:18 -07004551#endif
Anthony Liguoric227f092009-10-01 16:12:16 -05004552 ppc_avr_t altivec[QEMU_NVRREG];
malc3efa9a62009-07-18 13:10:12 +04004553#undef QEMU_NVRREG
Nathan Froydbcd49332009-05-12 19:13:18 -07004554 } mc_vregs __attribute__((__aligned__(16)));
4555};
4556
4557struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02004558 target_ulong tuc_flags;
4559 target_ulong tuc_link; /* struct ucontext __user * */
4560 struct target_sigaltstack tuc_stack;
Nathan Froydbcd49332009-05-12 19:13:18 -07004561#if !defined(TARGET_PPC64)
Aurelien Jarno60e99242010-03-29 02:12:51 +02004562 int32_t tuc_pad[7];
4563 target_ulong tuc_regs; /* struct mcontext __user *
Nathan Froydbcd49332009-05-12 19:13:18 -07004564 points to uc_mcontext field */
4565#endif
Aurelien Jarno60e99242010-03-29 02:12:51 +02004566 target_sigset_t tuc_sigmask;
Nathan Froydbcd49332009-05-12 19:13:18 -07004567#if defined(TARGET_PPC64)
Anthony Liguoric227f092009-10-01 16:12:16 -05004568 target_sigset_t unused[15]; /* Allow for uc_sigmask growth */
Aurelien Jarno60e99242010-03-29 02:12:51 +02004569 struct target_sigcontext tuc_mcontext;
Nathan Froydbcd49332009-05-12 19:13:18 -07004570#else
Aurelien Jarno60e99242010-03-29 02:12:51 +02004571 int32_t tuc_maskext[30];
4572 int32_t tuc_pad2[3];
4573 struct target_mcontext tuc_mcontext;
Nathan Froydbcd49332009-05-12 19:13:18 -07004574#endif
4575};
4576
4577/* See arch/powerpc/kernel/signal_32.c. */
4578struct target_sigframe {
4579 struct target_sigcontext sctx;
4580 struct target_mcontext mctx;
4581 int32_t abigap[56];
4582};
4583
4584struct target_rt_sigframe {
4585 struct target_siginfo info;
4586 struct target_ucontext uc;
4587 int32_t abigap[56];
4588};
4589
4590/* We use the mc_pad field for the signal return trampoline. */
4591#define tramp mc_pad
4592
4593/* See arch/powerpc/kernel/signal.c. */
4594static target_ulong get_sigframe(struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01004595 CPUPPCState *env,
Nathan Froydbcd49332009-05-12 19:13:18 -07004596 int frame_size)
4597{
4598 target_ulong oldsp, newsp;
4599
4600 oldsp = env->gpr[1];
4601
4602 if ((ka->sa_flags & TARGET_SA_ONSTACK) &&
Alex Barcelo32a20032012-02-09 23:55:46 +00004603 (sas_ss_flags(oldsp) == 0)) {
Nathan Froydbcd49332009-05-12 19:13:18 -07004604 oldsp = (target_sigaltstack_used.ss_sp
4605 + target_sigaltstack_used.ss_size);
4606 }
4607
4608 newsp = (oldsp - frame_size) & ~0xFUL;
4609
4610 return newsp;
4611}
4612
Andreas Färber05390242012-02-25 03:37:53 +01004613static int save_user_regs(CPUPPCState *env, struct target_mcontext *frame,
Nathan Froydbcd49332009-05-12 19:13:18 -07004614 int sigret)
4615{
4616 target_ulong msr = env->msr;
4617 int i;
4618 target_ulong ccr = 0;
4619
4620 /* In general, the kernel attempts to be intelligent about what it
4621 needs to save for Altivec/FP/SPE registers. We don't care that
4622 much, so we just go ahead and save everything. */
4623
4624 /* Save general registers. */
4625 for (i = 0; i < ARRAY_SIZE(env->gpr); i++) {
4626 if (__put_user(env->gpr[i], &frame->mc_gregs[i])) {
4627 return 1;
4628 }
4629 }
4630 if (__put_user(env->nip, &frame->mc_gregs[TARGET_PT_NIP])
4631 || __put_user(env->ctr, &frame->mc_gregs[TARGET_PT_CTR])
4632 || __put_user(env->lr, &frame->mc_gregs[TARGET_PT_LNK])
4633 || __put_user(env->xer, &frame->mc_gregs[TARGET_PT_XER]))
4634 return 1;
4635
4636 for (i = 0; i < ARRAY_SIZE(env->crf); i++) {
4637 ccr |= env->crf[i] << (32 - ((i + 1) * 4));
4638 }
4639 if (__put_user(ccr, &frame->mc_gregs[TARGET_PT_CCR]))
4640 return 1;
4641
4642 /* Save Altivec registers if necessary. */
4643 if (env->insns_flags & PPC_ALTIVEC) {
4644 for (i = 0; i < ARRAY_SIZE(env->avr); i++) {
Anthony Liguoric227f092009-10-01 16:12:16 -05004645 ppc_avr_t *avr = &env->avr[i];
4646 ppc_avr_t *vreg = &frame->mc_vregs.altivec[i];
Nathan Froydbcd49332009-05-12 19:13:18 -07004647
4648 if (__put_user(avr->u64[0], &vreg->u64[0]) ||
4649 __put_user(avr->u64[1], &vreg->u64[1])) {
4650 return 1;
4651 }
4652 }
4653 /* Set MSR_VR in the saved MSR value to indicate that
4654 frame->mc_vregs contains valid data. */
4655 msr |= MSR_VR;
4656 if (__put_user((uint32_t)env->spr[SPR_VRSAVE],
4657 &frame->mc_vregs.altivec[32].u32[3]))
4658 return 1;
4659 }
4660
4661 /* Save floating point registers. */
4662 if (env->insns_flags & PPC_FLOAT) {
4663 for (i = 0; i < ARRAY_SIZE(env->fpr); i++) {
4664 if (__put_user(env->fpr[i], &frame->mc_fregs[i])) {
4665 return 1;
4666 }
4667 }
4668 if (__put_user((uint64_t) env->fpscr, &frame->mc_fregs[32]))
4669 return 1;
4670 }
4671
4672 /* Save SPE registers. The kernel only saves the high half. */
4673 if (env->insns_flags & PPC_SPE) {
4674#if defined(TARGET_PPC64)
4675 for (i = 0; i < ARRAY_SIZE(env->gpr); i++) {
4676 if (__put_user(env->gpr[i] >> 32, &frame->mc_vregs.spe[i])) {
4677 return 1;
4678 }
4679 }
4680#else
4681 for (i = 0; i < ARRAY_SIZE(env->gprh); i++) {
4682 if (__put_user(env->gprh[i], &frame->mc_vregs.spe[i])) {
4683 return 1;
4684 }
4685 }
4686#endif
4687 /* Set MSR_SPE in the saved MSR value to indicate that
4688 frame->mc_vregs contains valid data. */
4689 msr |= MSR_SPE;
4690 if (__put_user(env->spe_fscr, &frame->mc_vregs.spe[32]))
4691 return 1;
4692 }
4693
4694 /* Store MSR. */
4695 if (__put_user(msr, &frame->mc_gregs[TARGET_PT_MSR]))
4696 return 1;
4697
4698 /* Set up the sigreturn trampoline: li r0,sigret; sc. */
4699 if (sigret) {
4700 if (__put_user(0x38000000UL | sigret, &frame->tramp[0]) ||
4701 __put_user(0x44000002UL, &frame->tramp[1])) {
4702 return 1;
4703 }
4704 }
4705
4706 return 0;
4707}
4708
Andreas Färber05390242012-02-25 03:37:53 +01004709static int restore_user_regs(CPUPPCState *env,
Nathan Froydbcd49332009-05-12 19:13:18 -07004710 struct target_mcontext *frame, int sig)
4711{
4712 target_ulong save_r2 = 0;
4713 target_ulong msr;
4714 target_ulong ccr;
4715
4716 int i;
4717
4718 if (!sig) {
4719 save_r2 = env->gpr[2];
4720 }
4721
4722 /* Restore general registers. */
4723 for (i = 0; i < ARRAY_SIZE(env->gpr); i++) {
4724 if (__get_user(env->gpr[i], &frame->mc_gregs[i])) {
4725 return 1;
4726 }
4727 }
4728 if (__get_user(env->nip, &frame->mc_gregs[TARGET_PT_NIP])
4729 || __get_user(env->ctr, &frame->mc_gregs[TARGET_PT_CTR])
4730 || __get_user(env->lr, &frame->mc_gregs[TARGET_PT_LNK])
4731 || __get_user(env->xer, &frame->mc_gregs[TARGET_PT_XER]))
4732 return 1;
4733 if (__get_user(ccr, &frame->mc_gregs[TARGET_PT_CCR]))
4734 return 1;
4735
4736 for (i = 0; i < ARRAY_SIZE(env->crf); i++) {
4737 env->crf[i] = (ccr >> (32 - ((i + 1) * 4))) & 0xf;
4738 }
4739
4740 if (!sig) {
4741 env->gpr[2] = save_r2;
4742 }
4743 /* Restore MSR. */
4744 if (__get_user(msr, &frame->mc_gregs[TARGET_PT_MSR]))
4745 return 1;
4746
4747 /* If doing signal return, restore the previous little-endian mode. */
4748 if (sig)
4749 env->msr = (env->msr & ~MSR_LE) | (msr & MSR_LE);
4750
4751 /* Restore Altivec registers if necessary. */
4752 if (env->insns_flags & PPC_ALTIVEC) {
4753 for (i = 0; i < ARRAY_SIZE(env->avr); i++) {
Anthony Liguoric227f092009-10-01 16:12:16 -05004754 ppc_avr_t *avr = &env->avr[i];
4755 ppc_avr_t *vreg = &frame->mc_vregs.altivec[i];
Nathan Froydbcd49332009-05-12 19:13:18 -07004756
4757 if (__get_user(avr->u64[0], &vreg->u64[0]) ||
4758 __get_user(avr->u64[1], &vreg->u64[1])) {
4759 return 1;
4760 }
4761 }
4762 /* Set MSR_VEC in the saved MSR value to indicate that
4763 frame->mc_vregs contains valid data. */
4764 if (__get_user(env->spr[SPR_VRSAVE],
4765 (target_ulong *)(&frame->mc_vregs.altivec[32].u32[3])))
4766 return 1;
4767 }
4768
4769 /* Restore floating point registers. */
4770 if (env->insns_flags & PPC_FLOAT) {
4771 uint64_t fpscr;
4772 for (i = 0; i < ARRAY_SIZE(env->fpr); i++) {
4773 if (__get_user(env->fpr[i], &frame->mc_fregs[i])) {
4774 return 1;
4775 }
4776 }
4777 if (__get_user(fpscr, &frame->mc_fregs[32]))
4778 return 1;
4779 env->fpscr = (uint32_t) fpscr;
4780 }
4781
4782 /* Save SPE registers. The kernel only saves the high half. */
4783 if (env->insns_flags & PPC_SPE) {
4784#if defined(TARGET_PPC64)
4785 for (i = 0; i < ARRAY_SIZE(env->gpr); i++) {
4786 uint32_t hi;
4787
4788 if (__get_user(hi, &frame->mc_vregs.spe[i])) {
4789 return 1;
4790 }
4791 env->gpr[i] = ((uint64_t)hi << 32) | ((uint32_t) env->gpr[i]);
4792 }
4793#else
4794 for (i = 0; i < ARRAY_SIZE(env->gprh); i++) {
4795 if (__get_user(env->gprh[i], &frame->mc_vregs.spe[i])) {
4796 return 1;
4797 }
4798 }
4799#endif
4800 if (__get_user(env->spe_fscr, &frame->mc_vregs.spe[32]))
4801 return 1;
4802 }
4803
4804 return 0;
4805}
4806
4807static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01004808 target_sigset_t *set, CPUPPCState *env)
Nathan Froydbcd49332009-05-12 19:13:18 -07004809{
4810 struct target_sigframe *frame;
4811 struct target_sigcontext *sc;
4812 target_ulong frame_addr, newsp;
4813 int err = 0;
4814 int signal;
4815
4816 frame_addr = get_sigframe(ka, env, sizeof(*frame));
4817 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 1))
4818 goto sigsegv;
4819 sc = &frame->sctx;
4820
4821 signal = current_exec_domain_sig(sig);
4822
Riku Voipio1d8b5122014-04-23 10:26:05 +03004823 __put_user(ka->_sa_handler, &sc->handler);
4824 __put_user(set->sig[0], &sc->oldmask);
Nathan Froydbcd49332009-05-12 19:13:18 -07004825#if defined(TARGET_PPC64)
Riku Voipio1d8b5122014-04-23 10:26:05 +03004826 __put_user(set->sig[0] >> 32, &sc->_unused[3]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004827#else
Riku Voipio1d8b5122014-04-23 10:26:05 +03004828 __put_user(set->sig[1], &sc->_unused[3]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004829#endif
Riku Voipio1d8b5122014-04-23 10:26:05 +03004830 __put_user(h2g(&frame->mctx), &sc->regs);
4831 __put_user(sig, &sc->signal);
Nathan Froydbcd49332009-05-12 19:13:18 -07004832
4833 /* Save user regs. */
4834 err |= save_user_regs(env, &frame->mctx, TARGET_NR_sigreturn);
4835
4836 /* The kernel checks for the presence of a VDSO here. We don't
4837 emulate a vdso, so use a sigreturn system call. */
4838 env->lr = (target_ulong) h2g(frame->mctx.tramp);
4839
4840 /* Turn off all fp exceptions. */
4841 env->fpscr = 0;
4842
4843 /* Create a stack frame for the caller of the handler. */
4844 newsp = frame_addr - SIGNAL_FRAMESIZE;
Samuel Seaybeb526b2013-01-02 10:53:46 +00004845 err |= put_user(env->gpr[1], newsp, target_ulong);
Nathan Froydbcd49332009-05-12 19:13:18 -07004846
4847 if (err)
4848 goto sigsegv;
4849
4850 /* Set up registers for signal handler. */
4851 env->gpr[1] = newsp;
4852 env->gpr[3] = signal;
Samuel Seay61993a62013-01-04 14:35:48 +00004853 env->gpr[4] = frame_addr + offsetof(struct target_sigframe, sctx);
Nathan Froydbcd49332009-05-12 19:13:18 -07004854 env->nip = (target_ulong) ka->_sa_handler;
4855 /* Signal handlers are entered in big-endian mode. */
4856 env->msr &= ~MSR_LE;
4857
4858 unlock_user_struct(frame, frame_addr, 1);
4859 return;
4860
4861sigsegv:
4862 unlock_user_struct(frame, frame_addr, 1);
Blue Swirleeacee42012-06-03 16:35:32 +00004863 qemu_log("segfaulting from setup_frame\n");
Riku Voipio66393fb2009-12-04 15:16:32 +02004864 force_sig(TARGET_SIGSEGV);
Nathan Froydbcd49332009-05-12 19:13:18 -07004865}
4866
4867static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05004868 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01004869 target_sigset_t *set, CPUPPCState *env)
Nathan Froydbcd49332009-05-12 19:13:18 -07004870{
4871 struct target_rt_sigframe *rt_sf;
4872 struct target_mcontext *frame;
4873 target_ulong rt_sf_addr, newsp = 0;
4874 int i, err = 0;
4875 int signal;
4876
4877 rt_sf_addr = get_sigframe(ka, env, sizeof(*rt_sf));
4878 if (!lock_user_struct(VERIFY_WRITE, rt_sf, rt_sf_addr, 1))
4879 goto sigsegv;
4880
4881 signal = current_exec_domain_sig(sig);
4882
4883 err |= copy_siginfo_to_user(&rt_sf->info, info);
4884
Riku Voipio1d8b5122014-04-23 10:26:05 +03004885 __put_user(0, &rt_sf->uc.tuc_flags);
4886 __put_user(0, &rt_sf->uc.tuc_link);
4887 __put_user((target_ulong)target_sigaltstack_used.ss_sp,
4888 &rt_sf->uc.tuc_stack.ss_sp);
4889 __put_user(sas_ss_flags(env->gpr[1]),
4890 &rt_sf->uc.tuc_stack.ss_flags);
4891 __put_user(target_sigaltstack_used.ss_size,
4892 &rt_sf->uc.tuc_stack.ss_size);
4893 __put_user(h2g (&rt_sf->uc.tuc_mcontext),
4894 &rt_sf->uc.tuc_regs);
Nathan Froydbcd49332009-05-12 19:13:18 -07004895 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03004896 __put_user(set->sig[i], &rt_sf->uc.tuc_sigmask.sig[i]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004897 }
4898
Aurelien Jarno60e99242010-03-29 02:12:51 +02004899 frame = &rt_sf->uc.tuc_mcontext;
Nathan Froydbcd49332009-05-12 19:13:18 -07004900 err |= save_user_regs(env, frame, TARGET_NR_rt_sigreturn);
4901
4902 /* The kernel checks for the presence of a VDSO here. We don't
4903 emulate a vdso, so use a sigreturn system call. */
4904 env->lr = (target_ulong) h2g(frame->tramp);
4905
4906 /* Turn off all fp exceptions. */
4907 env->fpscr = 0;
4908
4909 /* Create a stack frame for the caller of the handler. */
4910 newsp = rt_sf_addr - (SIGNAL_FRAMESIZE + 16);
Riku Voipio1d8b5122014-04-23 10:26:05 +03004911 __put_user(env->gpr[1], (target_ulong *)(uintptr_t) newsp);
Nathan Froydbcd49332009-05-12 19:13:18 -07004912
4913 if (err)
4914 goto sigsegv;
4915
4916 /* Set up registers for signal handler. */
4917 env->gpr[1] = newsp;
4918 env->gpr[3] = (target_ulong) signal;
4919 env->gpr[4] = (target_ulong) h2g(&rt_sf->info);
4920 env->gpr[5] = (target_ulong) h2g(&rt_sf->uc);
4921 env->gpr[6] = (target_ulong) h2g(rt_sf);
4922 env->nip = (target_ulong) ka->_sa_handler;
4923 /* Signal handlers are entered in big-endian mode. */
4924 env->msr &= ~MSR_LE;
4925
4926 unlock_user_struct(rt_sf, rt_sf_addr, 1);
4927 return;
4928
4929sigsegv:
4930 unlock_user_struct(rt_sf, rt_sf_addr, 1);
Blue Swirleeacee42012-06-03 16:35:32 +00004931 qemu_log("segfaulting from setup_rt_frame\n");
Riku Voipio66393fb2009-12-04 15:16:32 +02004932 force_sig(TARGET_SIGSEGV);
Nathan Froydbcd49332009-05-12 19:13:18 -07004933
4934}
4935
Andreas Färber05390242012-02-25 03:37:53 +01004936long do_sigreturn(CPUPPCState *env)
Nathan Froydbcd49332009-05-12 19:13:18 -07004937{
4938 struct target_sigcontext *sc = NULL;
4939 struct target_mcontext *sr = NULL;
Peter Maydellb04636f2013-07-29 12:00:31 +01004940 target_ulong sr_addr = 0, sc_addr;
Nathan Froydbcd49332009-05-12 19:13:18 -07004941 sigset_t blocked;
Anthony Liguoric227f092009-10-01 16:12:16 -05004942 target_sigset_t set;
Nathan Froydbcd49332009-05-12 19:13:18 -07004943
4944 sc_addr = env->gpr[1] + SIGNAL_FRAMESIZE;
4945 if (!lock_user_struct(VERIFY_READ, sc, sc_addr, 1))
4946 goto sigsegv;
4947
4948#if defined(TARGET_PPC64)
4949 set.sig[0] = sc->oldmask + ((long)(sc->_unused[3]) << 32);
4950#else
4951 if(__get_user(set.sig[0], &sc->oldmask) ||
4952 __get_user(set.sig[1], &sc->_unused[3]))
4953 goto sigsegv;
4954#endif
4955 target_to_host_sigset_internal(&blocked, &set);
Alex Barcelo1c275922014-03-14 14:36:55 +00004956 do_sigprocmask(SIG_SETMASK, &blocked, NULL);
Nathan Froydbcd49332009-05-12 19:13:18 -07004957
4958 if (__get_user(sr_addr, &sc->regs))
4959 goto sigsegv;
4960 if (!lock_user_struct(VERIFY_READ, sr, sr_addr, 1))
4961 goto sigsegv;
4962 if (restore_user_regs(env, sr, 1))
4963 goto sigsegv;
4964
4965 unlock_user_struct(sr, sr_addr, 1);
4966 unlock_user_struct(sc, sc_addr, 1);
4967 return -TARGET_QEMU_ESIGRETURN;
4968
4969sigsegv:
4970 unlock_user_struct(sr, sr_addr, 1);
4971 unlock_user_struct(sc, sc_addr, 1);
Blue Swirleeacee42012-06-03 16:35:32 +00004972 qemu_log("segfaulting from do_sigreturn\n");
Riku Voipio66393fb2009-12-04 15:16:32 +02004973 force_sig(TARGET_SIGSEGV);
Nathan Froydbcd49332009-05-12 19:13:18 -07004974 return 0;
4975}
4976
4977/* See arch/powerpc/kernel/signal_32.c. */
Andreas Färber05390242012-02-25 03:37:53 +01004978static int do_setcontext(struct target_ucontext *ucp, CPUPPCState *env, int sig)
Nathan Froydbcd49332009-05-12 19:13:18 -07004979{
4980 struct target_mcontext *mcp;
4981 target_ulong mcp_addr;
4982 sigset_t blocked;
Anthony Liguoric227f092009-10-01 16:12:16 -05004983 target_sigset_t set;
Nathan Froydbcd49332009-05-12 19:13:18 -07004984
Aurelien Jarno60e99242010-03-29 02:12:51 +02004985 if (copy_from_user(&set, h2g(ucp) + offsetof(struct target_ucontext, tuc_sigmask),
Nathan Froydbcd49332009-05-12 19:13:18 -07004986 sizeof (set)))
4987 return 1;
4988
4989#if defined(TARGET_PPC64)
4990 fprintf (stderr, "do_setcontext: not implemented\n");
4991 return 0;
4992#else
Aurelien Jarno60e99242010-03-29 02:12:51 +02004993 if (__get_user(mcp_addr, &ucp->tuc_regs))
Nathan Froydbcd49332009-05-12 19:13:18 -07004994 return 1;
4995
4996 if (!lock_user_struct(VERIFY_READ, mcp, mcp_addr, 1))
4997 return 1;
4998
4999 target_to_host_sigset_internal(&blocked, &set);
Alex Barcelo1c275922014-03-14 14:36:55 +00005000 do_sigprocmask(SIG_SETMASK, &blocked, NULL);
Nathan Froydbcd49332009-05-12 19:13:18 -07005001 if (restore_user_regs(env, mcp, sig))
5002 goto sigsegv;
5003
5004 unlock_user_struct(mcp, mcp_addr, 1);
5005 return 0;
5006
5007sigsegv:
5008 unlock_user_struct(mcp, mcp_addr, 1);
5009 return 1;
5010#endif
5011}
5012
Andreas Färber05390242012-02-25 03:37:53 +01005013long do_rt_sigreturn(CPUPPCState *env)
Nathan Froydbcd49332009-05-12 19:13:18 -07005014{
5015 struct target_rt_sigframe *rt_sf = NULL;
5016 target_ulong rt_sf_addr;
5017
5018 rt_sf_addr = env->gpr[1] + SIGNAL_FRAMESIZE + 16;
5019 if (!lock_user_struct(VERIFY_READ, rt_sf, rt_sf_addr, 1))
5020 goto sigsegv;
5021
5022 if (do_setcontext(&rt_sf->uc, env, 1))
5023 goto sigsegv;
5024
5025 do_sigaltstack(rt_sf_addr
Aurelien Jarno60e99242010-03-29 02:12:51 +02005026 + offsetof(struct target_rt_sigframe, uc.tuc_stack),
Nathan Froydbcd49332009-05-12 19:13:18 -07005027 0, env->gpr[1]);
5028
5029 unlock_user_struct(rt_sf, rt_sf_addr, 1);
5030 return -TARGET_QEMU_ESIGRETURN;
5031
5032sigsegv:
5033 unlock_user_struct(rt_sf, rt_sf_addr, 1);
Blue Swirleeacee42012-06-03 16:35:32 +00005034 qemu_log("segfaulting from do_rt_sigreturn\n");
Riku Voipio66393fb2009-12-04 15:16:32 +02005035 force_sig(TARGET_SIGSEGV);
Nathan Froydbcd49332009-05-12 19:13:18 -07005036 return 0;
5037}
5038
Laurent Vivier492a8742009-08-03 16:12:17 +02005039#elif defined(TARGET_M68K)
5040
5041struct target_sigcontext {
5042 abi_ulong sc_mask;
5043 abi_ulong sc_usp;
5044 abi_ulong sc_d0;
5045 abi_ulong sc_d1;
5046 abi_ulong sc_a0;
5047 abi_ulong sc_a1;
5048 unsigned short sc_sr;
5049 abi_ulong sc_pc;
5050};
5051
5052struct target_sigframe
5053{
5054 abi_ulong pretcode;
5055 int sig;
5056 int code;
5057 abi_ulong psc;
5058 char retcode[8];
5059 abi_ulong extramask[TARGET_NSIG_WORDS-1];
5060 struct target_sigcontext sc;
5061};
Laurent Vivier71811552009-08-03 16:12:18 +02005062
Anthony Liguoric227f092009-10-01 16:12:16 -05005063typedef int target_greg_t;
Laurent Vivier71811552009-08-03 16:12:18 +02005064#define TARGET_NGREG 18
Anthony Liguoric227f092009-10-01 16:12:16 -05005065typedef target_greg_t target_gregset_t[TARGET_NGREG];
Laurent Vivier71811552009-08-03 16:12:18 +02005066
5067typedef struct target_fpregset {
5068 int f_fpcntl[3];
5069 int f_fpregs[8*3];
Anthony Liguoric227f092009-10-01 16:12:16 -05005070} target_fpregset_t;
Laurent Vivier71811552009-08-03 16:12:18 +02005071
5072struct target_mcontext {
5073 int version;
Anthony Liguoric227f092009-10-01 16:12:16 -05005074 target_gregset_t gregs;
5075 target_fpregset_t fpregs;
Laurent Vivier71811552009-08-03 16:12:18 +02005076};
5077
5078#define TARGET_MCONTEXT_VERSION 2
5079
5080struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02005081 abi_ulong tuc_flags;
5082 abi_ulong tuc_link;
5083 target_stack_t tuc_stack;
5084 struct target_mcontext tuc_mcontext;
5085 abi_long tuc_filler[80];
5086 target_sigset_t tuc_sigmask;
Laurent Vivier71811552009-08-03 16:12:18 +02005087};
5088
5089struct target_rt_sigframe
5090{
5091 abi_ulong pretcode;
5092 int sig;
5093 abi_ulong pinfo;
5094 abi_ulong puc;
5095 char retcode[8];
5096 struct target_siginfo info;
5097 struct target_ucontext uc;
5098};
Laurent Vivier492a8742009-08-03 16:12:17 +02005099
5100static int
Andreas Färber05390242012-02-25 03:37:53 +01005101setup_sigcontext(struct target_sigcontext *sc, CPUM68KState *env,
5102 abi_ulong mask)
Laurent Vivier492a8742009-08-03 16:12:17 +02005103{
5104 int err = 0;
5105
Riku Voipio1d8b5122014-04-23 10:26:05 +03005106 __put_user(mask, &sc->sc_mask);
5107 __put_user(env->aregs[7], &sc->sc_usp);
5108 __put_user(env->dregs[0], &sc->sc_d0);
5109 __put_user(env->dregs[1], &sc->sc_d1);
5110 __put_user(env->aregs[0], &sc->sc_a0);
5111 __put_user(env->aregs[1], &sc->sc_a1);
5112 __put_user(env->sr, &sc->sc_sr);
5113 __put_user(env->pc, &sc->sc_pc);
Laurent Vivier492a8742009-08-03 16:12:17 +02005114
5115 return err;
5116}
5117
5118static int
Andreas Färber05390242012-02-25 03:37:53 +01005119restore_sigcontext(CPUM68KState *env, struct target_sigcontext *sc, int *pd0)
Laurent Vivier492a8742009-08-03 16:12:17 +02005120{
5121 int err = 0;
5122 int temp;
5123
Riku Voipio1d8b5122014-04-23 10:26:05 +03005124 __get_user(env->aregs[7], &sc->sc_usp);
5125 __get_user(env->dregs[1], &sc->sc_d1);
5126 __get_user(env->aregs[0], &sc->sc_a0);
5127 __get_user(env->aregs[1], &sc->sc_a1);
5128 __get_user(env->pc, &sc->sc_pc);
5129 __get_user(temp, &sc->sc_sr);
Laurent Vivier492a8742009-08-03 16:12:17 +02005130 env->sr = (env->sr & 0xff00) | (temp & 0xff);
5131
5132 *pd0 = tswapl(sc->sc_d0);
5133
5134 return err;
5135}
5136
5137/*
5138 * Determine which stack to use..
5139 */
5140static inline abi_ulong
Andreas Färber05390242012-02-25 03:37:53 +01005141get_sigframe(struct target_sigaction *ka, CPUM68KState *regs,
5142 size_t frame_size)
Laurent Vivier492a8742009-08-03 16:12:17 +02005143{
5144 unsigned long sp;
5145
5146 sp = regs->aregs[7];
5147
5148 /* This is the X/Open sanctioned signal stack switching. */
5149 if ((ka->sa_flags & TARGET_SA_ONSTACK) && (sas_ss_flags (sp) == 0)) {
5150 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
5151 }
5152
5153 return ((sp - frame_size) & -8UL);
5154}
5155
5156static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01005157 target_sigset_t *set, CPUM68KState *env)
Laurent Vivier492a8742009-08-03 16:12:17 +02005158{
5159 struct target_sigframe *frame;
5160 abi_ulong frame_addr;
5161 abi_ulong retcode_addr;
5162 abi_ulong sc_addr;
5163 int err = 0;
5164 int i;
5165
5166 frame_addr = get_sigframe(ka, env, sizeof *frame);
5167 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
5168 goto give_sigsegv;
5169
Riku Voipio1d8b5122014-04-23 10:26:05 +03005170 __put_user(sig, &frame->sig);
Laurent Vivier492a8742009-08-03 16:12:17 +02005171
5172 sc_addr = frame_addr + offsetof(struct target_sigframe, sc);
Riku Voipio1d8b5122014-04-23 10:26:05 +03005173 __put_user(sc_addr, &frame->psc);
Laurent Vivier492a8742009-08-03 16:12:17 +02005174
5175 err |= setup_sigcontext(&frame->sc, env, set->sig[0]);
5176 if (err)
5177 goto give_sigsegv;
5178
5179 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
5180 if (__put_user(set->sig[i], &frame->extramask[i - 1]))
5181 goto give_sigsegv;
5182 }
5183
5184 /* Set up to return from userspace. */
5185
5186 retcode_addr = frame_addr + offsetof(struct target_sigframe, retcode);
Riku Voipio1d8b5122014-04-23 10:26:05 +03005187 __put_user(retcode_addr, &frame->pretcode);
Laurent Vivier492a8742009-08-03 16:12:17 +02005188
5189 /* moveq #,d0; trap #0 */
5190
Riku Voipio1d8b5122014-04-23 10:26:05 +03005191 __put_user(0x70004e40 + (TARGET_NR_sigreturn << 16),
Laurent Vivier492a8742009-08-03 16:12:17 +02005192 (long *)(frame->retcode));
5193
5194 if (err)
5195 goto give_sigsegv;
5196
5197 /* Set up to return from userspace */
5198
5199 env->aregs[7] = frame_addr;
5200 env->pc = ka->_sa_handler;
5201
5202 unlock_user_struct(frame, frame_addr, 1);
5203 return;
5204
5205give_sigsegv:
5206 unlock_user_struct(frame, frame_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02005207 force_sig(TARGET_SIGSEGV);
Laurent Vivier492a8742009-08-03 16:12:17 +02005208}
5209
Laurent Vivier71811552009-08-03 16:12:18 +02005210static inline int target_rt_setup_ucontext(struct target_ucontext *uc,
Andreas Färber05390242012-02-25 03:37:53 +01005211 CPUM68KState *env)
Laurent Vivier71811552009-08-03 16:12:18 +02005212{
Aurelien Jarno60e99242010-03-29 02:12:51 +02005213 target_greg_t *gregs = uc->tuc_mcontext.gregs;
Laurent Vivier71811552009-08-03 16:12:18 +02005214
Riku Voipio1d8b5122014-04-23 10:26:05 +03005215 __put_user(TARGET_MCONTEXT_VERSION, &uc->tuc_mcontext.version);
5216 __put_user(env->dregs[0], &gregs[0]);
5217 __put_user(env->dregs[1], &gregs[1]);
5218 __put_user(env->dregs[2], &gregs[2]);
5219 __put_user(env->dregs[3], &gregs[3]);
5220 __put_user(env->dregs[4], &gregs[4]);
5221 __put_user(env->dregs[5], &gregs[5]);
5222 __put_user(env->dregs[6], &gregs[6]);
5223 __put_user(env->dregs[7], &gregs[7]);
5224 __put_user(env->aregs[0], &gregs[8]);
5225 __put_user(env->aregs[1], &gregs[9]);
5226 __put_user(env->aregs[2], &gregs[10]);
5227 __put_user(env->aregs[3], &gregs[11]);
5228 __put_user(env->aregs[4], &gregs[12]);
5229 __put_user(env->aregs[5], &gregs[13]);
5230 __put_user(env->aregs[6], &gregs[14]);
5231 __put_user(env->aregs[7], &gregs[15]);
5232 __put_user(env->pc, &gregs[16]);
5233 __put_user(env->sr, &gregs[17]);
Laurent Vivier71811552009-08-03 16:12:18 +02005234
Riku Voipio1d8b5122014-04-23 10:26:05 +03005235 return 0;
Laurent Vivier71811552009-08-03 16:12:18 +02005236}
5237
Andreas Färber05390242012-02-25 03:37:53 +01005238static inline int target_rt_restore_ucontext(CPUM68KState *env,
Laurent Vivier71811552009-08-03 16:12:18 +02005239 struct target_ucontext *uc,
5240 int *pd0)
5241{
5242 int temp;
Aurelien Jarno60e99242010-03-29 02:12:51 +02005243 target_greg_t *gregs = uc->tuc_mcontext.gregs;
Laurent Vivier71811552009-08-03 16:12:18 +02005244
Riku Voipio1d8b5122014-04-23 10:26:05 +03005245 __get_user(temp, &uc->tuc_mcontext.version);
Laurent Vivier71811552009-08-03 16:12:18 +02005246 if (temp != TARGET_MCONTEXT_VERSION)
5247 goto badframe;
5248
5249 /* restore passed registers */
Riku Voipio1d8b5122014-04-23 10:26:05 +03005250 __get_user(env->dregs[0], &gregs[0]);
5251 __get_user(env->dregs[1], &gregs[1]);
5252 __get_user(env->dregs[2], &gregs[2]);
5253 __get_user(env->dregs[3], &gregs[3]);
5254 __get_user(env->dregs[4], &gregs[4]);
5255 __get_user(env->dregs[5], &gregs[5]);
5256 __get_user(env->dregs[6], &gregs[6]);
5257 __get_user(env->dregs[7], &gregs[7]);
5258 __get_user(env->aregs[0], &gregs[8]);
5259 __get_user(env->aregs[1], &gregs[9]);
5260 __get_user(env->aregs[2], &gregs[10]);
5261 __get_user(env->aregs[3], &gregs[11]);
5262 __get_user(env->aregs[4], &gregs[12]);
5263 __get_user(env->aregs[5], &gregs[13]);
5264 __get_user(env->aregs[6], &gregs[14]);
5265 __get_user(env->aregs[7], &gregs[15]);
5266 __get_user(env->pc, &gregs[16]);
5267 __get_user(temp, &gregs[17]);
Laurent Vivier71811552009-08-03 16:12:18 +02005268 env->sr = (env->sr & 0xff00) | (temp & 0xff);
5269
5270 *pd0 = env->dregs[0];
Riku Voipio1d8b5122014-04-23 10:26:05 +03005271 return 0;
Laurent Vivier71811552009-08-03 16:12:18 +02005272
5273badframe:
5274 return 1;
5275}
5276
Laurent Vivier492a8742009-08-03 16:12:17 +02005277static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05005278 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01005279 target_sigset_t *set, CPUM68KState *env)
Laurent Vivier492a8742009-08-03 16:12:17 +02005280{
Laurent Vivier71811552009-08-03 16:12:18 +02005281 struct target_rt_sigframe *frame;
5282 abi_ulong frame_addr;
5283 abi_ulong retcode_addr;
5284 abi_ulong info_addr;
5285 abi_ulong uc_addr;
5286 int err = 0;
5287 int i;
5288
5289 frame_addr = get_sigframe(ka, env, sizeof *frame);
5290 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
5291 goto give_sigsegv;
5292
Riku Voipio1d8b5122014-04-23 10:26:05 +03005293 __put_user(sig, &frame->sig);
Laurent Vivier71811552009-08-03 16:12:18 +02005294
5295 info_addr = frame_addr + offsetof(struct target_rt_sigframe, info);
Riku Voipio1d8b5122014-04-23 10:26:05 +03005296 __put_user(info_addr, &frame->pinfo);
Laurent Vivier71811552009-08-03 16:12:18 +02005297
5298 uc_addr = frame_addr + offsetof(struct target_rt_sigframe, uc);
Riku Voipio1d8b5122014-04-23 10:26:05 +03005299 __put_user(uc_addr, &frame->puc);
Laurent Vivier71811552009-08-03 16:12:18 +02005300
5301 err |= copy_siginfo_to_user(&frame->info, info);
5302
5303 /* Create the ucontext */
5304
Riku Voipio1d8b5122014-04-23 10:26:05 +03005305 __put_user(0, &frame->uc.tuc_flags);
5306 __put_user(0, &frame->uc.tuc_link);
5307 __put_user(target_sigaltstack_used.ss_sp,
5308 &frame->uc.tuc_stack.ss_sp);
5309 __put_user(sas_ss_flags(env->aregs[7]),
5310 &frame->uc.tuc_stack.ss_flags);
5311 __put_user(target_sigaltstack_used.ss_size,
5312 &frame->uc.tuc_stack.ss_size);
Laurent Vivier71811552009-08-03 16:12:18 +02005313 err |= target_rt_setup_ucontext(&frame->uc, env);
5314
5315 if (err)
5316 goto give_sigsegv;
5317
5318 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
Aurelien Jarno60e99242010-03-29 02:12:51 +02005319 if (__put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]))
Laurent Vivier71811552009-08-03 16:12:18 +02005320 goto give_sigsegv;
5321 }
5322
5323 /* Set up to return from userspace. */
5324
5325 retcode_addr = frame_addr + offsetof(struct target_sigframe, retcode);
Riku Voipio1d8b5122014-04-23 10:26:05 +03005326 __put_user(retcode_addr, &frame->pretcode);
Laurent Vivier71811552009-08-03 16:12:18 +02005327
5328 /* moveq #,d0; notb d0; trap #0 */
5329
Riku Voipio1d8b5122014-04-23 10:26:05 +03005330 __put_user(0x70004600 + ((TARGET_NR_rt_sigreturn ^ 0xff) << 16),
5331 (long *)(frame->retcode + 0));
5332 __put_user(0x4e40, (short *)(frame->retcode + 4));
Laurent Vivier71811552009-08-03 16:12:18 +02005333
5334 if (err)
5335 goto give_sigsegv;
5336
5337 /* Set up to return from userspace */
5338
5339 env->aregs[7] = frame_addr;
5340 env->pc = ka->_sa_handler;
5341
5342 unlock_user_struct(frame, frame_addr, 1);
5343 return;
5344
5345give_sigsegv:
5346 unlock_user_struct(frame, frame_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02005347 force_sig(TARGET_SIGSEGV);
Laurent Vivier492a8742009-08-03 16:12:17 +02005348}
5349
Andreas Färber05390242012-02-25 03:37:53 +01005350long do_sigreturn(CPUM68KState *env)
Laurent Vivier492a8742009-08-03 16:12:17 +02005351{
5352 struct target_sigframe *frame;
5353 abi_ulong frame_addr = env->aregs[7] - 4;
Anthony Liguoric227f092009-10-01 16:12:16 -05005354 target_sigset_t target_set;
Laurent Vivier492a8742009-08-03 16:12:17 +02005355 sigset_t set;
5356 int d0, i;
5357
5358 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
5359 goto badframe;
5360
5361 /* set blocked signals */
5362
5363 if (__get_user(target_set.sig[0], &frame->sc.sc_mask))
5364 goto badframe;
5365
5366 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
5367 if (__get_user(target_set.sig[i], &frame->extramask[i - 1]))
5368 goto badframe;
5369 }
5370
5371 target_to_host_sigset_internal(&set, &target_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00005372 do_sigprocmask(SIG_SETMASK, &set, NULL);
Laurent Vivier492a8742009-08-03 16:12:17 +02005373
5374 /* restore registers */
5375
5376 if (restore_sigcontext(env, &frame->sc, &d0))
5377 goto badframe;
5378
5379 unlock_user_struct(frame, frame_addr, 0);
5380 return d0;
5381
5382badframe:
5383 unlock_user_struct(frame, frame_addr, 0);
5384 force_sig(TARGET_SIGSEGV);
5385 return 0;
5386}
5387
Andreas Färber05390242012-02-25 03:37:53 +01005388long do_rt_sigreturn(CPUM68KState *env)
Laurent Vivier492a8742009-08-03 16:12:17 +02005389{
Laurent Vivier71811552009-08-03 16:12:18 +02005390 struct target_rt_sigframe *frame;
5391 abi_ulong frame_addr = env->aregs[7] - 4;
Anthony Liguoric227f092009-10-01 16:12:16 -05005392 target_sigset_t target_set;
Laurent Vivier71811552009-08-03 16:12:18 +02005393 sigset_t set;
5394 int d0;
5395
5396 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
5397 goto badframe;
5398
5399 target_to_host_sigset_internal(&set, &target_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00005400 do_sigprocmask(SIG_SETMASK, &set, NULL);
Laurent Vivier71811552009-08-03 16:12:18 +02005401
5402 /* restore registers */
5403
5404 if (target_rt_restore_ucontext(env, &frame->uc, &d0))
5405 goto badframe;
5406
5407 if (do_sigaltstack(frame_addr +
Aurelien Jarno60e99242010-03-29 02:12:51 +02005408 offsetof(struct target_rt_sigframe, uc.tuc_stack),
Laurent Vivier71811552009-08-03 16:12:18 +02005409 0, get_sp_from_cpustate(env)) == -EFAULT)
5410 goto badframe;
5411
5412 unlock_user_struct(frame, frame_addr, 0);
5413 return d0;
5414
5415badframe:
5416 unlock_user_struct(frame, frame_addr, 0);
5417 force_sig(TARGET_SIGSEGV);
5418 return 0;
Laurent Vivier492a8742009-08-03 16:12:17 +02005419}
5420
Richard Henderson6049f4f2009-12-27 18:30:03 -08005421#elif defined(TARGET_ALPHA)
5422
5423struct target_sigcontext {
5424 abi_long sc_onstack;
5425 abi_long sc_mask;
5426 abi_long sc_pc;
5427 abi_long sc_ps;
5428 abi_long sc_regs[32];
5429 abi_long sc_ownedfp;
5430 abi_long sc_fpregs[32];
5431 abi_ulong sc_fpcr;
5432 abi_ulong sc_fp_control;
5433 abi_ulong sc_reserved1;
5434 abi_ulong sc_reserved2;
5435 abi_ulong sc_ssize;
5436 abi_ulong sc_sbase;
5437 abi_ulong sc_traparg_a0;
5438 abi_ulong sc_traparg_a1;
5439 abi_ulong sc_traparg_a2;
5440 abi_ulong sc_fp_trap_pc;
5441 abi_ulong sc_fp_trigger_sum;
5442 abi_ulong sc_fp_trigger_inst;
5443};
5444
5445struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02005446 abi_ulong tuc_flags;
5447 abi_ulong tuc_link;
5448 abi_ulong tuc_osf_sigmask;
5449 target_stack_t tuc_stack;
5450 struct target_sigcontext tuc_mcontext;
5451 target_sigset_t tuc_sigmask;
Richard Henderson6049f4f2009-12-27 18:30:03 -08005452};
5453
5454struct target_sigframe {
5455 struct target_sigcontext sc;
5456 unsigned int retcode[3];
5457};
5458
5459struct target_rt_sigframe {
5460 target_siginfo_t info;
5461 struct target_ucontext uc;
5462 unsigned int retcode[3];
5463};
5464
5465#define INSN_MOV_R30_R16 0x47fe0410
5466#define INSN_LDI_R0 0x201f0000
5467#define INSN_CALLSYS 0x00000083
5468
Andreas Färber05390242012-02-25 03:37:53 +01005469static int setup_sigcontext(struct target_sigcontext *sc, CPUAlphaState *env,
Richard Henderson6049f4f2009-12-27 18:30:03 -08005470 abi_ulong frame_addr, target_sigset_t *set)
5471{
5472 int i, err = 0;
5473
Riku Voipio1d8b5122014-04-23 10:26:05 +03005474 __put_user(on_sig_stack(frame_addr), &sc->sc_onstack);
5475 __put_user(set->sig[0], &sc->sc_mask);
5476 __put_user(env->pc, &sc->sc_pc);
5477 __put_user(8, &sc->sc_ps);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005478
5479 for (i = 0; i < 31; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03005480 __put_user(env->ir[i], &sc->sc_regs[i]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005481 }
Riku Voipio1d8b5122014-04-23 10:26:05 +03005482 __put_user(0, &sc->sc_regs[31]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005483
5484 for (i = 0; i < 31; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03005485 __put_user(env->fir[i], &sc->sc_fpregs[i]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005486 }
Riku Voipio1d8b5122014-04-23 10:26:05 +03005487 __put_user(0, &sc->sc_fpregs[31]);
5488 __put_user(cpu_alpha_load_fpcr(env), &sc->sc_fpcr);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005489
Riku Voipio1d8b5122014-04-23 10:26:05 +03005490 __put_user(0, &sc->sc_traparg_a0); /* FIXME */
5491 __put_user(0, &sc->sc_traparg_a1); /* FIXME */
5492 __put_user(0, &sc->sc_traparg_a2); /* FIXME */
Richard Henderson6049f4f2009-12-27 18:30:03 -08005493
5494 return err;
5495}
5496
Andreas Färber05390242012-02-25 03:37:53 +01005497static int restore_sigcontext(CPUAlphaState *env,
5498 struct target_sigcontext *sc)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005499{
5500 uint64_t fpcr;
5501 int i, err = 0;
5502
Riku Voipio1d8b5122014-04-23 10:26:05 +03005503 __get_user(env->pc, &sc->sc_pc);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005504
5505 for (i = 0; i < 31; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03005506 __get_user(env->ir[i], &sc->sc_regs[i]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005507 }
5508 for (i = 0; i < 31; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03005509 __get_user(env->fir[i], &sc->sc_fpregs[i]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005510 }
5511
Riku Voipio1d8b5122014-04-23 10:26:05 +03005512 __get_user(fpcr, &sc->sc_fpcr);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005513 cpu_alpha_store_fpcr(env, fpcr);
5514
5515 return err;
5516}
5517
5518static inline abi_ulong get_sigframe(struct target_sigaction *sa,
Andreas Färber05390242012-02-25 03:37:53 +01005519 CPUAlphaState *env,
5520 unsigned long framesize)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005521{
5522 abi_ulong sp = env->ir[IR_SP];
5523
5524 /* This is the X/Open sanctioned signal stack switching. */
5525 if ((sa->sa_flags & TARGET_SA_ONSTACK) != 0 && !sas_ss_flags(sp)) {
5526 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
5527 }
5528 return (sp - framesize) & -32;
5529}
5530
5531static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01005532 target_sigset_t *set, CPUAlphaState *env)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005533{
5534 abi_ulong frame_addr, r26;
5535 struct target_sigframe *frame;
5536 int err = 0;
5537
5538 frame_addr = get_sigframe(ka, env, sizeof(*frame));
5539 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
5540 goto give_sigsegv;
5541 }
5542
5543 err |= setup_sigcontext(&frame->sc, env, frame_addr, set);
5544
5545 if (ka->sa_restorer) {
5546 r26 = ka->sa_restorer;
5547 } else {
Riku Voipio1d8b5122014-04-23 10:26:05 +03005548 __put_user(INSN_MOV_R30_R16, &frame->retcode[0]);
5549 __put_user(INSN_LDI_R0 + TARGET_NR_sigreturn,
5550 &frame->retcode[1]);
5551 __put_user(INSN_CALLSYS, &frame->retcode[2]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005552 /* imb() */
5553 r26 = frame_addr;
5554 }
5555
5556 unlock_user_struct(frame, frame_addr, 1);
5557
5558 if (err) {
5559 give_sigsegv:
5560 if (sig == TARGET_SIGSEGV) {
5561 ka->_sa_handler = TARGET_SIG_DFL;
5562 }
5563 force_sig(TARGET_SIGSEGV);
5564 }
5565
5566 env->ir[IR_RA] = r26;
5567 env->ir[IR_PV] = env->pc = ka->_sa_handler;
5568 env->ir[IR_A0] = sig;
5569 env->ir[IR_A1] = 0;
5570 env->ir[IR_A2] = frame_addr + offsetof(struct target_sigframe, sc);
5571 env->ir[IR_SP] = frame_addr;
5572}
5573
5574static void setup_rt_frame(int sig, struct target_sigaction *ka,
5575 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01005576 target_sigset_t *set, CPUAlphaState *env)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005577{
5578 abi_ulong frame_addr, r26;
5579 struct target_rt_sigframe *frame;
5580 int i, err = 0;
5581
5582 frame_addr = get_sigframe(ka, env, sizeof(*frame));
5583 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
5584 goto give_sigsegv;
5585 }
5586
5587 err |= copy_siginfo_to_user(&frame->info, info);
5588
Riku Voipio1d8b5122014-04-23 10:26:05 +03005589 __put_user(0, &frame->uc.tuc_flags);
5590 __put_user(0, &frame->uc.tuc_link);
5591 __put_user(set->sig[0], &frame->uc.tuc_osf_sigmask);
5592 __put_user(target_sigaltstack_used.ss_sp,
5593 &frame->uc.tuc_stack.ss_sp);
5594 __put_user(sas_ss_flags(env->ir[IR_SP]),
5595 &frame->uc.tuc_stack.ss_flags);
5596 __put_user(target_sigaltstack_used.ss_size,
5597 &frame->uc.tuc_stack.ss_size);
Aurelien Jarno60e99242010-03-29 02:12:51 +02005598 err |= setup_sigcontext(&frame->uc.tuc_mcontext, env, frame_addr, set);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005599 for (i = 0; i < TARGET_NSIG_WORDS; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03005600 __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005601 }
5602
5603 if (ka->sa_restorer) {
5604 r26 = ka->sa_restorer;
5605 } else {
Riku Voipio1d8b5122014-04-23 10:26:05 +03005606 __put_user(INSN_MOV_R30_R16, &frame->retcode[0]);
5607 __put_user(INSN_LDI_R0 + TARGET_NR_rt_sigreturn,
5608 &frame->retcode[1]);
5609 __put_user(INSN_CALLSYS, &frame->retcode[2]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005610 /* imb(); */
5611 r26 = frame_addr;
5612 }
5613
5614 if (err) {
5615 give_sigsegv:
5616 if (sig == TARGET_SIGSEGV) {
5617 ka->_sa_handler = TARGET_SIG_DFL;
5618 }
5619 force_sig(TARGET_SIGSEGV);
5620 }
5621
5622 env->ir[IR_RA] = r26;
5623 env->ir[IR_PV] = env->pc = ka->_sa_handler;
5624 env->ir[IR_A0] = sig;
5625 env->ir[IR_A1] = frame_addr + offsetof(struct target_rt_sigframe, info);
5626 env->ir[IR_A2] = frame_addr + offsetof(struct target_rt_sigframe, uc);
5627 env->ir[IR_SP] = frame_addr;
5628}
5629
Andreas Färber05390242012-02-25 03:37:53 +01005630long do_sigreturn(CPUAlphaState *env)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005631{
5632 struct target_sigcontext *sc;
5633 abi_ulong sc_addr = env->ir[IR_A0];
5634 target_sigset_t target_set;
5635 sigset_t set;
5636
5637 if (!lock_user_struct(VERIFY_READ, sc, sc_addr, 1)) {
5638 goto badframe;
5639 }
5640
5641 target_sigemptyset(&target_set);
5642 if (__get_user(target_set.sig[0], &sc->sc_mask)) {
5643 goto badframe;
5644 }
5645
5646 target_to_host_sigset_internal(&set, &target_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00005647 do_sigprocmask(SIG_SETMASK, &set, NULL);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005648
5649 if (restore_sigcontext(env, sc)) {
5650 goto badframe;
5651 }
5652 unlock_user_struct(sc, sc_addr, 0);
5653 return env->ir[IR_V0];
5654
5655 badframe:
5656 unlock_user_struct(sc, sc_addr, 0);
5657 force_sig(TARGET_SIGSEGV);
5658}
5659
Andreas Färber05390242012-02-25 03:37:53 +01005660long do_rt_sigreturn(CPUAlphaState *env)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005661{
5662 abi_ulong frame_addr = env->ir[IR_A0];
5663 struct target_rt_sigframe *frame;
5664 sigset_t set;
5665
5666 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
5667 goto badframe;
5668 }
Aurelien Jarno60e99242010-03-29 02:12:51 +02005669 target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
Alex Barcelo1c275922014-03-14 14:36:55 +00005670 do_sigprocmask(SIG_SETMASK, &set, NULL);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005671
Aurelien Jarno60e99242010-03-29 02:12:51 +02005672 if (restore_sigcontext(env, &frame->uc.tuc_mcontext)) {
Richard Henderson6049f4f2009-12-27 18:30:03 -08005673 goto badframe;
5674 }
5675 if (do_sigaltstack(frame_addr + offsetof(struct target_rt_sigframe,
Aurelien Jarno60e99242010-03-29 02:12:51 +02005676 uc.tuc_stack),
Richard Henderson6049f4f2009-12-27 18:30:03 -08005677 0, env->ir[IR_SP]) == -EFAULT) {
5678 goto badframe;
5679 }
5680
5681 unlock_user_struct(frame, frame_addr, 0);
5682 return env->ir[IR_V0];
5683
5684
5685 badframe:
5686 unlock_user_struct(frame, frame_addr, 0);
5687 force_sig(TARGET_SIGSEGV);
5688}
5689
bellardb346ff42003-06-15 20:05:50 +00005690#else
5691
pbrook624f7972008-05-31 16:11:38 +00005692static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber9349b4f2012-03-14 01:38:32 +01005693 target_sigset_t *set, CPUArchState *env)
bellardb346ff42003-06-15 20:05:50 +00005694{
5695 fprintf(stderr, "setup_frame: not implemented\n");
5696}
5697
pbrook624f7972008-05-31 16:11:38 +00005698static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05005699 target_siginfo_t *info,
Andreas Färber9349b4f2012-03-14 01:38:32 +01005700 target_sigset_t *set, CPUArchState *env)
bellardb346ff42003-06-15 20:05:50 +00005701{
5702 fprintf(stderr, "setup_rt_frame: not implemented\n");
5703}
5704
Andreas Färber9349b4f2012-03-14 01:38:32 +01005705long do_sigreturn(CPUArchState *env)
bellardb346ff42003-06-15 20:05:50 +00005706{
5707 fprintf(stderr, "do_sigreturn: not implemented\n");
bellardf8b0aa22007-11-11 23:03:42 +00005708 return -TARGET_ENOSYS;
bellardb346ff42003-06-15 20:05:50 +00005709}
5710
Andreas Färber9349b4f2012-03-14 01:38:32 +01005711long do_rt_sigreturn(CPUArchState *env)
bellardb346ff42003-06-15 20:05:50 +00005712{
5713 fprintf(stderr, "do_rt_sigreturn: not implemented\n");
bellardf8b0aa22007-11-11 23:03:42 +00005714 return -TARGET_ENOSYS;
bellardb346ff42003-06-15 20:05:50 +00005715}
5716
bellard66fb9762003-03-23 01:06:05 +00005717#endif
5718
Andreas Färber9349b4f2012-03-14 01:38:32 +01005719void process_pending_signals(CPUArchState *cpu_env)
bellard66fb9762003-03-23 01:06:05 +00005720{
Andreas Färberdb6b81d2013-06-27 19:49:31 +02005721 CPUState *cpu = ENV_GET_CPU(cpu_env);
bellard66fb9762003-03-23 01:06:05 +00005722 int sig;
blueswir1992f48a2007-10-14 16:27:31 +00005723 abi_ulong handler;
bellard9de5e442003-03-23 16:49:39 +00005724 sigset_t set, old_set;
Anthony Liguoric227f092009-10-01 16:12:16 -05005725 target_sigset_t target_old_set;
pbrook624f7972008-05-31 16:11:38 +00005726 struct emulated_sigtable *k;
5727 struct target_sigaction *sa;
bellard66fb9762003-03-23 01:06:05 +00005728 struct sigqueue *q;
Andreas Färber0429a972013-08-26 18:14:44 +02005729 TaskState *ts = cpu->opaque;
ths3b46e622007-09-17 08:09:54 +00005730
pbrook624f7972008-05-31 16:11:38 +00005731 if (!ts->signal_pending)
bellard31e31b82003-02-18 22:55:36 +00005732 return;
5733
pbrook624f7972008-05-31 16:11:38 +00005734 /* FIXME: This is not threadsafe. */
5735 k = ts->sigtab;
bellard66fb9762003-03-23 01:06:05 +00005736 for(sig = 1; sig <= TARGET_NSIG; sig++) {
5737 if (k->pending)
bellard31e31b82003-02-18 22:55:36 +00005738 goto handle_signal;
bellard66fb9762003-03-23 01:06:05 +00005739 k++;
bellard31e31b82003-02-18 22:55:36 +00005740 }
5741 /* if no signal is pending, just return */
pbrook624f7972008-05-31 16:11:38 +00005742 ts->signal_pending = 0;
bellard31e31b82003-02-18 22:55:36 +00005743 return;
bellard66fb9762003-03-23 01:06:05 +00005744
bellard31e31b82003-02-18 22:55:36 +00005745 handle_signal:
bellard66fb9762003-03-23 01:06:05 +00005746#ifdef DEBUG_SIGNAL
bellardbc8a22c2003-03-30 21:02:40 +00005747 fprintf(stderr, "qemu: process signal %d\n", sig);
bellard66fb9762003-03-23 01:06:05 +00005748#endif
5749 /* dequeue signal */
5750 q = k->first;
5751 k->first = q->next;
5752 if (!k->first)
5753 k->pending = 0;
ths3b46e622007-09-17 08:09:54 +00005754
Andreas Färberdb6b81d2013-06-27 19:49:31 +02005755 sig = gdb_handlesig(cpu, sig);
bellard1fddef42005-04-17 19:16:13 +00005756 if (!sig) {
aurel32ca587a82008-12-18 22:44:13 +00005757 sa = NULL;
5758 handler = TARGET_SIG_IGN;
5759 } else {
5760 sa = &sigact_table[sig - 1];
5761 handler = sa->_sa_handler;
bellard1fddef42005-04-17 19:16:13 +00005762 }
bellard66fb9762003-03-23 01:06:05 +00005763
Peter Maydella7ec0f92014-03-14 14:36:56 +00005764 if (ts->sigsegv_blocked && sig == TARGET_SIGSEGV) {
5765 /* Guest has blocked SIGSEGV but we got one anyway. Assume this
5766 * is a forced SIGSEGV (ie one the kernel handles via force_sig_info
5767 * because it got a real MMU fault), and treat as if default handler.
5768 */
5769 handler = TARGET_SIG_DFL;
5770 }
5771
bellard66fb9762003-03-23 01:06:05 +00005772 if (handler == TARGET_SIG_DFL) {
aurel32ca587a82008-12-18 22:44:13 +00005773 /* default handler : ignore some signal. The other are job control or fatal */
5774 if (sig == TARGET_SIGTSTP || sig == TARGET_SIGTTIN || sig == TARGET_SIGTTOU) {
5775 kill(getpid(),SIGSTOP);
5776 } else if (sig != TARGET_SIGCHLD &&
5777 sig != TARGET_SIGURG &&
5778 sig != TARGET_SIGWINCH &&
5779 sig != TARGET_SIGCONT) {
bellard66fb9762003-03-23 01:06:05 +00005780 force_sig(sig);
5781 }
5782 } else if (handler == TARGET_SIG_IGN) {
5783 /* ignore sig */
5784 } else if (handler == TARGET_SIG_ERR) {
5785 force_sig(sig);
5786 } else {
bellard9de5e442003-03-23 16:49:39 +00005787 /* compute the blocked signals during the handler execution */
pbrook624f7972008-05-31 16:11:38 +00005788 target_to_host_sigset(&set, &sa->sa_mask);
bellard9de5e442003-03-23 16:49:39 +00005789 /* SA_NODEFER indicates that the current signal should not be
5790 blocked during the handler */
pbrook624f7972008-05-31 16:11:38 +00005791 if (!(sa->sa_flags & TARGET_SA_NODEFER))
bellard9de5e442003-03-23 16:49:39 +00005792 sigaddset(&set, target_to_host_signal(sig));
ths3b46e622007-09-17 08:09:54 +00005793
bellard9de5e442003-03-23 16:49:39 +00005794 /* block signals in the handler using Linux */
Alex Barcelo1c275922014-03-14 14:36:55 +00005795 do_sigprocmask(SIG_BLOCK, &set, &old_set);
bellard9de5e442003-03-23 16:49:39 +00005796 /* save the previous blocked signal state to restore it at the
5797 end of the signal execution (see do_sigreturn) */
bellard92319442004-06-19 16:58:13 +00005798 host_to_target_sigset_internal(&target_old_set, &old_set);
bellard9de5e442003-03-23 16:49:39 +00005799
bellardbc8a22c2003-03-30 21:02:40 +00005800 /* if the CPU is in VM86 mode, we restore the 32 bit values */
j_mayer84409dd2007-04-06 08:56:50 +00005801#if defined(TARGET_I386) && !defined(TARGET_X86_64)
bellardbc8a22c2003-03-30 21:02:40 +00005802 {
5803 CPUX86State *env = cpu_env;
5804 if (env->eflags & VM_MASK)
5805 save_v86_state(env);
5806 }
5807#endif
bellard9de5e442003-03-23 16:49:39 +00005808 /* prepare the stack frame of the virtual CPU */
Richard Hendersonff970902013-02-10 10:30:42 -08005809#if defined(TARGET_ABI_MIPSN32) || defined(TARGET_ABI_MIPSN64)
5810 /* These targets do not have traditional signals. */
5811 setup_rt_frame(sig, sa, &q->info, &target_old_set, cpu_env);
5812#else
pbrook624f7972008-05-31 16:11:38 +00005813 if (sa->sa_flags & TARGET_SA_SIGINFO)
5814 setup_rt_frame(sig, sa, &q->info, &target_old_set, cpu_env);
bellard66fb9762003-03-23 01:06:05 +00005815 else
pbrook624f7972008-05-31 16:11:38 +00005816 setup_frame(sig, sa, &target_old_set, cpu_env);
Richard Hendersonff970902013-02-10 10:30:42 -08005817#endif
pbrook624f7972008-05-31 16:11:38 +00005818 if (sa->sa_flags & TARGET_SA_RESETHAND)
5819 sa->_sa_handler = TARGET_SIG_DFL;
bellard31e31b82003-02-18 22:55:36 +00005820 }
bellard66fb9762003-03-23 01:06:05 +00005821 if (q != &k->info)
pbrook624f7972008-05-31 16:11:38 +00005822 free_sigqueue(cpu_env, q);
bellard31e31b82003-02-18 22:55:36 +00005823}