blob: bc475995cc300ee5c8494cadf69d2e4bedccebf9 [file] [log] [blame]
bellard31e31b82003-02-18 22:55:36 +00001/*
bellard66fb9762003-03-23 01:06:05 +00002 * Emulation of Linux signals
ths5fafdf22007-09-16 21:08:06 +00003 *
bellard31e31b82003-02-18 22:55:36 +00004 * Copyright (c) 2003 Fabrice Bellard
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
Blue Swirl8167ee82009-07-16 20:47:01 +000017 * along with this program; if not, see <http://www.gnu.org/licenses/>.
bellard31e31b82003-02-18 22:55:36 +000018 */
19#include <stdlib.h>
20#include <stdio.h>
bellard66fb9762003-03-23 01:06:05 +000021#include <string.h>
bellard31e31b82003-02-18 22:55:36 +000022#include <stdarg.h>
bellard2677e102003-04-10 00:03:27 +000023#include <unistd.h>
bellard66fb9762003-03-23 01:06:05 +000024#include <errno.h>
aurel32603e4fd2009-04-15 16:18:38 +000025#include <assert.h>
bellard31e31b82003-02-18 22:55:36 +000026#include <sys/ucontext.h>
Mika Westerbergedf8e2a2009-04-07 09:57:11 +030027#include <sys/resource.h>
bellard31e31b82003-02-18 22:55:36 +000028
bellard3ef693a2003-03-23 20:17:16 +000029#include "qemu.h"
blueswir17d99a002009-01-14 19:00:36 +000030#include "qemu-common.h"
blueswir1992f48a2007-10-14 16:27:31 +000031#include "target_signal.h"
bellard66fb9762003-03-23 01:06:05 +000032
33//#define DEBUG_SIGNAL
34
blueswir1249c4c32008-10-05 11:09:37 +000035static struct target_sigaltstack target_sigaltstack_used = {
thsa04e1342007-09-27 13:57:58 +000036 .ss_sp = 0,
37 .ss_size = 0,
38 .ss_flags = TARGET_SS_DISABLE,
39};
40
pbrook624f7972008-05-31 16:11:38 +000041static struct target_sigaction sigact_table[TARGET_NSIG];
bellard31e31b82003-02-18 22:55:36 +000042
ths5fafdf22007-09-16 21:08:06 +000043static void host_signal_handler(int host_signum, siginfo_t *info,
bellard66fb9762003-03-23 01:06:05 +000044 void *puc);
45
Arnaud Patard3ca05582009-03-30 01:18:20 +020046static uint8_t host_to_target_signal_table[_NSIG] = {
bellard9e5f5282003-07-13 17:33:54 +000047 [SIGHUP] = TARGET_SIGHUP,
48 [SIGINT] = TARGET_SIGINT,
49 [SIGQUIT] = TARGET_SIGQUIT,
50 [SIGILL] = TARGET_SIGILL,
51 [SIGTRAP] = TARGET_SIGTRAP,
52 [SIGABRT] = TARGET_SIGABRT,
bellard01e3b762003-09-30 21:10:14 +000053/* [SIGIOT] = TARGET_SIGIOT,*/
bellard9e5f5282003-07-13 17:33:54 +000054 [SIGBUS] = TARGET_SIGBUS,
55 [SIGFPE] = TARGET_SIGFPE,
56 [SIGKILL] = TARGET_SIGKILL,
57 [SIGUSR1] = TARGET_SIGUSR1,
58 [SIGSEGV] = TARGET_SIGSEGV,
59 [SIGUSR2] = TARGET_SIGUSR2,
60 [SIGPIPE] = TARGET_SIGPIPE,
61 [SIGALRM] = TARGET_SIGALRM,
62 [SIGTERM] = TARGET_SIGTERM,
63#ifdef SIGSTKFLT
64 [SIGSTKFLT] = TARGET_SIGSTKFLT,
65#endif
66 [SIGCHLD] = TARGET_SIGCHLD,
67 [SIGCONT] = TARGET_SIGCONT,
68 [SIGSTOP] = TARGET_SIGSTOP,
69 [SIGTSTP] = TARGET_SIGTSTP,
70 [SIGTTIN] = TARGET_SIGTTIN,
71 [SIGTTOU] = TARGET_SIGTTOU,
72 [SIGURG] = TARGET_SIGURG,
73 [SIGXCPU] = TARGET_SIGXCPU,
74 [SIGXFSZ] = TARGET_SIGXFSZ,
75 [SIGVTALRM] = TARGET_SIGVTALRM,
76 [SIGPROF] = TARGET_SIGPROF,
77 [SIGWINCH] = TARGET_SIGWINCH,
78 [SIGIO] = TARGET_SIGIO,
79 [SIGPWR] = TARGET_SIGPWR,
80 [SIGSYS] = TARGET_SIGSYS,
81 /* next signals stay the same */
pbrook624f7972008-05-31 16:11:38 +000082 /* Nasty hack: Reverse SIGRTMIN and SIGRTMAX to avoid overlap with
Dong Xu Wangb4916d72011-11-22 18:06:17 +080083 host libpthread signals. This assumes no one actually uses SIGRTMAX :-/
pbrook624f7972008-05-31 16:11:38 +000084 To fix this properly we need to do manual signal delivery multiplexed
85 over a single host signal. */
86 [__SIGRTMIN] = __SIGRTMAX,
87 [__SIGRTMAX] = __SIGRTMIN,
bellard9e5f5282003-07-13 17:33:54 +000088};
Arnaud Patard3ca05582009-03-30 01:18:20 +020089static uint8_t target_to_host_signal_table[_NSIG];
bellard9e5f5282003-07-13 17:33:54 +000090
thsa04e1342007-09-27 13:57:58 +000091static inline int on_sig_stack(unsigned long sp)
92{
93 return (sp - target_sigaltstack_used.ss_sp
94 < target_sigaltstack_used.ss_size);
95}
96
97static inline int sas_ss_flags(unsigned long sp)
98{
99 return (target_sigaltstack_used.ss_size == 0 ? SS_DISABLE
100 : on_sig_stack(sp) ? SS_ONSTACK : 0);
101}
102
pbrook1d9d8b52009-04-16 15:17:02 +0000103int host_to_target_signal(int sig)
bellard31e31b82003-02-18 22:55:36 +0000104{
Andreas Schwab167c50d2013-07-02 14:04:12 +0100105 if (sig < 0 || sig >= _NSIG)
pbrook4cb05962008-05-30 18:05:19 +0000106 return sig;
bellard9e5f5282003-07-13 17:33:54 +0000107 return host_to_target_signal_table[sig];
bellard31e31b82003-02-18 22:55:36 +0000108}
109
pbrook4cb05962008-05-30 18:05:19 +0000110int target_to_host_signal(int sig)
bellard31e31b82003-02-18 22:55:36 +0000111{
Andreas Schwab167c50d2013-07-02 14:04:12 +0100112 if (sig < 0 || sig >= _NSIG)
pbrook4cb05962008-05-30 18:05:19 +0000113 return sig;
bellard9e5f5282003-07-13 17:33:54 +0000114 return target_to_host_signal_table[sig];
bellard31e31b82003-02-18 22:55:36 +0000115}
116
Anthony Liguoric227f092009-10-01 16:12:16 -0500117static inline void target_sigemptyset(target_sigset_t *set)
pbrookf5545b52008-05-30 22:37:07 +0000118{
119 memset(set, 0, sizeof(*set));
120}
121
Anthony Liguoric227f092009-10-01 16:12:16 -0500122static inline void target_sigaddset(target_sigset_t *set, int signum)
pbrookf5545b52008-05-30 22:37:07 +0000123{
124 signum--;
125 abi_ulong mask = (abi_ulong)1 << (signum % TARGET_NSIG_BPW);
126 set->sig[signum / TARGET_NSIG_BPW] |= mask;
127}
128
Anthony Liguoric227f092009-10-01 16:12:16 -0500129static inline int target_sigismember(const target_sigset_t *set, int signum)
pbrookf5545b52008-05-30 22:37:07 +0000130{
131 signum--;
132 abi_ulong mask = (abi_ulong)1 << (signum % TARGET_NSIG_BPW);
133 return ((set->sig[signum / TARGET_NSIG_BPW] & mask) != 0);
134}
135
Anthony Liguoric227f092009-10-01 16:12:16 -0500136static void host_to_target_sigset_internal(target_sigset_t *d,
bellard92319442004-06-19 16:58:13 +0000137 const sigset_t *s)
bellard66fb9762003-03-23 01:06:05 +0000138{
139 int i;
pbrookf5545b52008-05-30 22:37:07 +0000140 target_sigemptyset(d);
141 for (i = 1; i <= TARGET_NSIG; i++) {
142 if (sigismember(s, i)) {
143 target_sigaddset(d, host_to_target_signal(i));
144 }
bellard9e5f5282003-07-13 17:33:54 +0000145 }
bellard66fb9762003-03-23 01:06:05 +0000146}
147
Anthony Liguoric227f092009-10-01 16:12:16 -0500148void host_to_target_sigset(target_sigset_t *d, const sigset_t *s)
bellard92319442004-06-19 16:58:13 +0000149{
Anthony Liguoric227f092009-10-01 16:12:16 -0500150 target_sigset_t d1;
bellard92319442004-06-19 16:58:13 +0000151 int i;
152
153 host_to_target_sigset_internal(&d1, s);
154 for(i = 0;i < TARGET_NSIG_WORDS; i++)
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200155 d->sig[i] = tswapal(d1.sig[i]);
bellard92319442004-06-19 16:58:13 +0000156}
157
blueswir18fcd3692008-08-17 20:26:25 +0000158static void target_to_host_sigset_internal(sigset_t *d,
Anthony Liguoric227f092009-10-01 16:12:16 -0500159 const target_sigset_t *s)
bellard66fb9762003-03-23 01:06:05 +0000160{
161 int i;
pbrookf5545b52008-05-30 22:37:07 +0000162 sigemptyset(d);
163 for (i = 1; i <= TARGET_NSIG; i++) {
164 if (target_sigismember(s, i)) {
165 sigaddset(d, target_to_host_signal(i));
166 }
167 }
bellard66fb9762003-03-23 01:06:05 +0000168}
169
Anthony Liguoric227f092009-10-01 16:12:16 -0500170void target_to_host_sigset(sigset_t *d, const target_sigset_t *s)
bellard92319442004-06-19 16:58:13 +0000171{
Anthony Liguoric227f092009-10-01 16:12:16 -0500172 target_sigset_t s1;
bellard92319442004-06-19 16:58:13 +0000173 int i;
174
175 for(i = 0;i < TARGET_NSIG_WORDS; i++)
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200176 s1.sig[i] = tswapal(s->sig[i]);
bellard92319442004-06-19 16:58:13 +0000177 target_to_host_sigset_internal(d, &s1);
178}
ths3b46e622007-09-17 08:09:54 +0000179
blueswir1992f48a2007-10-14 16:27:31 +0000180void host_to_target_old_sigset(abi_ulong *old_sigset,
bellard66fb9762003-03-23 01:06:05 +0000181 const sigset_t *sigset)
182{
Anthony Liguoric227f092009-10-01 16:12:16 -0500183 target_sigset_t d;
bellard9e5f5282003-07-13 17:33:54 +0000184 host_to_target_sigset(&d, sigset);
185 *old_sigset = d.sig[0];
bellard66fb9762003-03-23 01:06:05 +0000186}
187
ths5fafdf22007-09-16 21:08:06 +0000188void target_to_host_old_sigset(sigset_t *sigset,
blueswir1992f48a2007-10-14 16:27:31 +0000189 const abi_ulong *old_sigset)
bellard66fb9762003-03-23 01:06:05 +0000190{
Anthony Liguoric227f092009-10-01 16:12:16 -0500191 target_sigset_t d;
bellard9e5f5282003-07-13 17:33:54 +0000192 int i;
193
194 d.sig[0] = *old_sigset;
195 for(i = 1;i < TARGET_NSIG_WORDS; i++)
196 d.sig[i] = 0;
197 target_to_host_sigset(sigset, &d);
bellard66fb9762003-03-23 01:06:05 +0000198}
199
Alex Barcelo1c275922014-03-14 14:36:55 +0000200/* Wrapper for sigprocmask function
201 * Emulates a sigprocmask in a safe way for the guest. Note that set and oldset
202 * are host signal set, not guest ones. This wraps the sigprocmask host calls
203 * that should be protected (calls originated from guest)
204 */
205int do_sigprocmask(int how, const sigset_t *set, sigset_t *oldset)
206{
Peter Maydella7ec0f92014-03-14 14:36:56 +0000207 int ret;
208 sigset_t val;
209 sigset_t *temp = NULL;
210 CPUState *cpu = thread_cpu;
211 TaskState *ts = (TaskState *)cpu->opaque;
212 bool segv_was_blocked = ts->sigsegv_blocked;
213
214 if (set) {
215 bool has_sigsegv = sigismember(set, SIGSEGV);
216 val = *set;
217 temp = &val;
218
219 sigdelset(temp, SIGSEGV);
220
221 switch (how) {
222 case SIG_BLOCK:
223 if (has_sigsegv) {
224 ts->sigsegv_blocked = true;
225 }
226 break;
227 case SIG_UNBLOCK:
228 if (has_sigsegv) {
229 ts->sigsegv_blocked = false;
230 }
231 break;
232 case SIG_SETMASK:
233 ts->sigsegv_blocked = has_sigsegv;
234 break;
235 default:
236 g_assert_not_reached();
237 }
238 }
239
240 ret = sigprocmask(how, temp, oldset);
241
242 if (oldset && segv_was_blocked) {
243 sigaddset(oldset, SIGSEGV);
244 }
245
246 return ret;
Alex Barcelo1c275922014-03-14 14:36:55 +0000247}
248
bellard9de5e442003-03-23 16:49:39 +0000249/* siginfo conversion */
250
Anthony Liguoric227f092009-10-01 16:12:16 -0500251static inline void host_to_target_siginfo_noswap(target_siginfo_t *tinfo,
bellard9de5e442003-03-23 16:49:39 +0000252 const siginfo_t *info)
bellard66fb9762003-03-23 01:06:05 +0000253{
Richard Hendersona05c6402012-09-15 11:34:20 -0700254 int sig = host_to_target_signal(info->si_signo);
bellard9de5e442003-03-23 16:49:39 +0000255 tinfo->si_signo = sig;
256 tinfo->si_errno = 0;
pbrookafd7cd92008-05-31 12:14:21 +0000257 tinfo->si_code = info->si_code;
Richard Hendersona05c6402012-09-15 11:34:20 -0700258
259 if (sig == TARGET_SIGILL || sig == TARGET_SIGFPE || sig == TARGET_SIGSEGV
260 || sig == TARGET_SIGBUS || sig == TARGET_SIGTRAP) {
261 /* Should never come here, but who knows. The information for
262 the target is irrelevant. */
bellard9de5e442003-03-23 16:49:39 +0000263 tinfo->_sifields._sigfault._addr = 0;
Richard Hendersona05c6402012-09-15 11:34:20 -0700264 } else if (sig == TARGET_SIGIO) {
265 tinfo->_sifields._sigpoll._band = info->si_band;
ths7f7f7c82007-07-12 11:02:46 +0000266 tinfo->_sifields._sigpoll._fd = info->si_fd;
Richard Hendersona05c6402012-09-15 11:34:20 -0700267 } else if (sig == TARGET_SIGCHLD) {
268 tinfo->_sifields._sigchld._pid = info->si_pid;
269 tinfo->_sifields._sigchld._uid = info->si_uid;
270 tinfo->_sifields._sigchld._status
271 = host_to_target_waitstatus(info->si_status);
272 tinfo->_sifields._sigchld._utime = info->si_utime;
273 tinfo->_sifields._sigchld._stime = info->si_stime;
bellard9de5e442003-03-23 16:49:39 +0000274 } else if (sig >= TARGET_SIGRTMIN) {
275 tinfo->_sifields._rt._pid = info->si_pid;
276 tinfo->_sifields._rt._uid = info->si_uid;
277 /* XXX: potential problem if 64 bit */
Richard Hendersona05c6402012-09-15 11:34:20 -0700278 tinfo->_sifields._rt._sigval.sival_ptr
279 = (abi_ulong)(unsigned long)info->si_value.sival_ptr;
bellard9de5e442003-03-23 16:49:39 +0000280 }
bellard66fb9762003-03-23 01:06:05 +0000281}
282
Anthony Liguoric227f092009-10-01 16:12:16 -0500283static void tswap_siginfo(target_siginfo_t *tinfo,
284 const target_siginfo_t *info)
bellard9de5e442003-03-23 16:49:39 +0000285{
Richard Hendersona05c6402012-09-15 11:34:20 -0700286 int sig = info->si_signo;
bellard9de5e442003-03-23 16:49:39 +0000287 tinfo->si_signo = tswap32(sig);
288 tinfo->si_errno = tswap32(info->si_errno);
289 tinfo->si_code = tswap32(info->si_code);
Richard Hendersona05c6402012-09-15 11:34:20 -0700290
291 if (sig == TARGET_SIGILL || sig == TARGET_SIGFPE || sig == TARGET_SIGSEGV
292 || sig == TARGET_SIGBUS || sig == TARGET_SIGTRAP) {
293 tinfo->_sifields._sigfault._addr
294 = tswapal(info->_sifields._sigfault._addr);
295 } else if (sig == TARGET_SIGIO) {
296 tinfo->_sifields._sigpoll._band
297 = tswap32(info->_sifields._sigpoll._band);
298 tinfo->_sifields._sigpoll._fd = tswap32(info->_sifields._sigpoll._fd);
299 } else if (sig == TARGET_SIGCHLD) {
300 tinfo->_sifields._sigchld._pid
301 = tswap32(info->_sifields._sigchld._pid);
302 tinfo->_sifields._sigchld._uid
303 = tswap32(info->_sifields._sigchld._uid);
304 tinfo->_sifields._sigchld._status
305 = tswap32(info->_sifields._sigchld._status);
306 tinfo->_sifields._sigchld._utime
307 = tswapal(info->_sifields._sigchld._utime);
308 tinfo->_sifields._sigchld._stime
309 = tswapal(info->_sifields._sigchld._stime);
bellard9de5e442003-03-23 16:49:39 +0000310 } else if (sig >= TARGET_SIGRTMIN) {
311 tinfo->_sifields._rt._pid = tswap32(info->_sifields._rt._pid);
312 tinfo->_sifields._rt._uid = tswap32(info->_sifields._rt._uid);
Richard Hendersona05c6402012-09-15 11:34:20 -0700313 tinfo->_sifields._rt._sigval.sival_ptr
314 = tswapal(info->_sifields._rt._sigval.sival_ptr);
bellard9de5e442003-03-23 16:49:39 +0000315 }
316}
317
318
Anthony Liguoric227f092009-10-01 16:12:16 -0500319void host_to_target_siginfo(target_siginfo_t *tinfo, const siginfo_t *info)
bellard9de5e442003-03-23 16:49:39 +0000320{
321 host_to_target_siginfo_noswap(tinfo, info);
322 tswap_siginfo(tinfo, tinfo);
323}
324
325/* XXX: we support only POSIX RT signals are used. */
thsaa1f17c2007-07-11 22:48:58 +0000326/* XXX: find a solution for 64 bit (additional malloced data is needed) */
Anthony Liguoric227f092009-10-01 16:12:16 -0500327void target_to_host_siginfo(siginfo_t *info, const target_siginfo_t *tinfo)
bellard66fb9762003-03-23 01:06:05 +0000328{
329 info->si_signo = tswap32(tinfo->si_signo);
330 info->si_errno = tswap32(tinfo->si_errno);
331 info->si_code = tswap32(tinfo->si_code);
bellard9de5e442003-03-23 16:49:39 +0000332 info->si_pid = tswap32(tinfo->_sifields._rt._pid);
333 info->si_uid = tswap32(tinfo->_sifields._rt._uid);
ths5fafdf22007-09-16 21:08:06 +0000334 info->si_value.sival_ptr =
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200335 (void *)(long)tswapal(tinfo->_sifields._rt._sigval.sival_ptr);
bellard66fb9762003-03-23 01:06:05 +0000336}
337
aurel32ca587a82008-12-18 22:44:13 +0000338static int fatal_signal (int sig)
339{
340 switch (sig) {
341 case TARGET_SIGCHLD:
342 case TARGET_SIGURG:
343 case TARGET_SIGWINCH:
344 /* Ignored by default. */
345 return 0;
346 case TARGET_SIGCONT:
347 case TARGET_SIGSTOP:
348 case TARGET_SIGTSTP:
349 case TARGET_SIGTTIN:
350 case TARGET_SIGTTOU:
351 /* Job control signals. */
352 return 0;
353 default:
354 return 1;
355 }
356}
357
Mika Westerbergedf8e2a2009-04-07 09:57:11 +0300358/* returns 1 if given signal should dump core if not handled */
359static int core_dump_signal(int sig)
360{
361 switch (sig) {
362 case TARGET_SIGABRT:
363 case TARGET_SIGFPE:
364 case TARGET_SIGILL:
365 case TARGET_SIGQUIT:
366 case TARGET_SIGSEGV:
367 case TARGET_SIGTRAP:
368 case TARGET_SIGBUS:
369 return (1);
370 default:
371 return (0);
372 }
373}
374
bellard31e31b82003-02-18 22:55:36 +0000375void signal_init(void)
376{
377 struct sigaction act;
pbrook624f7972008-05-31 16:11:38 +0000378 struct sigaction oact;
bellard9e5f5282003-07-13 17:33:54 +0000379 int i, j;
pbrook624f7972008-05-31 16:11:38 +0000380 int host_sig;
bellard31e31b82003-02-18 22:55:36 +0000381
bellard9e5f5282003-07-13 17:33:54 +0000382 /* generate signal conversion tables */
Arnaud Patard3ca05582009-03-30 01:18:20 +0200383 for(i = 1; i < _NSIG; i++) {
bellard9e5f5282003-07-13 17:33:54 +0000384 if (host_to_target_signal_table[i] == 0)
385 host_to_target_signal_table[i] = i;
386 }
Arnaud Patard3ca05582009-03-30 01:18:20 +0200387 for(i = 1; i < _NSIG; i++) {
bellard9e5f5282003-07-13 17:33:54 +0000388 j = host_to_target_signal_table[i];
389 target_to_host_signal_table[j] = i;
390 }
ths3b46e622007-09-17 08:09:54 +0000391
bellard9de5e442003-03-23 16:49:39 +0000392 /* set all host signal handlers. ALL signals are blocked during
393 the handlers to serialize them. */
pbrook624f7972008-05-31 16:11:38 +0000394 memset(sigact_table, 0, sizeof(sigact_table));
395
bellard9de5e442003-03-23 16:49:39 +0000396 sigfillset(&act.sa_mask);
bellard31e31b82003-02-18 22:55:36 +0000397 act.sa_flags = SA_SIGINFO;
398 act.sa_sigaction = host_signal_handler;
pbrook624f7972008-05-31 16:11:38 +0000399 for(i = 1; i <= TARGET_NSIG; i++) {
400 host_sig = target_to_host_signal(i);
401 sigaction(host_sig, NULL, &oact);
402 if (oact.sa_sigaction == (void *)SIG_IGN) {
403 sigact_table[i - 1]._sa_handler = TARGET_SIG_IGN;
404 } else if (oact.sa_sigaction == (void *)SIG_DFL) {
405 sigact_table[i - 1]._sa_handler = TARGET_SIG_DFL;
406 }
407 /* If there's already a handler installed then something has
408 gone horribly wrong, so don't even try to handle that case. */
aurel32ca587a82008-12-18 22:44:13 +0000409 /* Install some handlers for our own use. We need at least
410 SIGSEGV and SIGBUS, to detect exceptions. We can not just
411 trap all signals because it affects syscall interrupt
412 behavior. But do trap all default-fatal signals. */
413 if (fatal_signal (i))
pbrook624f7972008-05-31 16:11:38 +0000414 sigaction(host_sig, &act, NULL);
bellard31e31b82003-02-18 22:55:36 +0000415 }
bellard31e31b82003-02-18 22:55:36 +0000416}
417
bellard66fb9762003-03-23 01:06:05 +0000418/* signal queue handling */
419
Andreas Färber9349b4f2012-03-14 01:38:32 +0100420static inline struct sigqueue *alloc_sigqueue(CPUArchState *env)
bellard66fb9762003-03-23 01:06:05 +0000421{
Andreas Färber0429a972013-08-26 18:14:44 +0200422 CPUState *cpu = ENV_GET_CPU(env);
423 TaskState *ts = cpu->opaque;
pbrook624f7972008-05-31 16:11:38 +0000424 struct sigqueue *q = ts->first_free;
bellard66fb9762003-03-23 01:06:05 +0000425 if (!q)
426 return NULL;
pbrook624f7972008-05-31 16:11:38 +0000427 ts->first_free = q->next;
bellard66fb9762003-03-23 01:06:05 +0000428 return q;
429}
430
Andreas Färber9349b4f2012-03-14 01:38:32 +0100431static inline void free_sigqueue(CPUArchState *env, struct sigqueue *q)
bellard66fb9762003-03-23 01:06:05 +0000432{
Andreas Färber0429a972013-08-26 18:14:44 +0200433 CPUState *cpu = ENV_GET_CPU(env);
434 TaskState *ts = cpu->opaque;
435
pbrook624f7972008-05-31 16:11:38 +0000436 q->next = ts->first_free;
437 ts->first_free = q;
bellard66fb9762003-03-23 01:06:05 +0000438}
439
bellard9de5e442003-03-23 16:49:39 +0000440/* abort execution with signal */
Riku Voipio66393fb2009-12-04 15:16:32 +0200441static void QEMU_NORETURN force_sig(int target_sig)
bellard66fb9762003-03-23 01:06:05 +0000442{
Andreas Färber0429a972013-08-26 18:14:44 +0200443 CPUState *cpu = thread_cpu;
444 CPUArchState *env = cpu->env_ptr;
445 TaskState *ts = (TaskState *)cpu->opaque;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +0300446 int host_sig, core_dumped = 0;
aurel32603e4fd2009-04-15 16:18:38 +0000447 struct sigaction act;
Riku Voipio66393fb2009-12-04 15:16:32 +0200448 host_sig = target_to_host_signal(target_sig);
Andreas Färbera2247f82013-06-09 19:47:04 +0200449 gdb_signalled(env, target_sig);
aurel32603e4fd2009-04-15 16:18:38 +0000450
Mika Westerbergedf8e2a2009-04-07 09:57:11 +0300451 /* dump core if supported by target binary format */
Riku Voipio66393fb2009-12-04 15:16:32 +0200452 if (core_dump_signal(target_sig) && (ts->bprm->core_dump != NULL)) {
Mika Westerbergedf8e2a2009-04-07 09:57:11 +0300453 stop_all_tasks();
454 core_dumped =
Andreas Färbera2247f82013-06-09 19:47:04 +0200455 ((*ts->bprm->core_dump)(target_sig, env) == 0);
Mika Westerbergedf8e2a2009-04-07 09:57:11 +0300456 }
457 if (core_dumped) {
458 /* we already dumped the core of target process, we don't want
459 * a coredump of qemu itself */
460 struct rlimit nodump;
461 getrlimit(RLIMIT_CORE, &nodump);
462 nodump.rlim_cur=0;
463 setrlimit(RLIMIT_CORE, &nodump);
464 (void) fprintf(stderr, "qemu: uncaught target signal %d (%s) - %s\n",
Riku Voipio66393fb2009-12-04 15:16:32 +0200465 target_sig, strsignal(host_sig), "core dumped" );
Mika Westerbergedf8e2a2009-04-07 09:57:11 +0300466 }
467
Stefan Weil0c587512011-04-28 17:20:32 +0200468 /* The proper exit code for dying from an uncaught signal is
aurel32603e4fd2009-04-15 16:18:38 +0000469 * -<signal>. The kernel doesn't allow exit() or _exit() to pass
470 * a negative value. To get the proper exit code we need to
471 * actually die from an uncaught signal. Here the default signal
472 * handler is installed, we send ourself a signal and we wait for
473 * it to arrive. */
474 sigfillset(&act.sa_mask);
475 act.sa_handler = SIG_DFL;
Peter Maydell3a5d30b2014-02-17 18:55:32 +0000476 act.sa_flags = 0;
aurel32603e4fd2009-04-15 16:18:38 +0000477 sigaction(host_sig, &act, NULL);
478
479 /* For some reason raise(host_sig) doesn't send the signal when
480 * statically linked on x86-64. */
481 kill(getpid(), host_sig);
482
483 /* Make sure the signal isn't masked (just reuse the mask inside
484 of act) */
485 sigdelset(&act.sa_mask, host_sig);
486 sigsuspend(&act.sa_mask);
487
488 /* unreachable */
Blue Swirla6c6f762010-03-13 14:18:50 +0000489 abort();
bellard66fb9762003-03-23 01:06:05 +0000490}
491
bellard9de5e442003-03-23 16:49:39 +0000492/* queue a signal so that it will be send to the virtual CPU as soon
493 as possible */
Andreas Färber9349b4f2012-03-14 01:38:32 +0100494int queue_signal(CPUArchState *env, int sig, target_siginfo_t *info)
bellard31e31b82003-02-18 22:55:36 +0000495{
Andreas Färber0429a972013-08-26 18:14:44 +0200496 CPUState *cpu = ENV_GET_CPU(env);
497 TaskState *ts = cpu->opaque;
pbrook624f7972008-05-31 16:11:38 +0000498 struct emulated_sigtable *k;
bellard9de5e442003-03-23 16:49:39 +0000499 struct sigqueue *q, **pq;
blueswir1992f48a2007-10-14 16:27:31 +0000500 abi_ulong handler;
aurel32ca587a82008-12-18 22:44:13 +0000501 int queue;
bellard66fb9762003-03-23 01:06:05 +0000502
bellard9de5e442003-03-23 16:49:39 +0000503#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000504 fprintf(stderr, "queue_signal: sig=%d\n",
bellard9de5e442003-03-23 16:49:39 +0000505 sig);
bellard66fb9762003-03-23 01:06:05 +0000506#endif
pbrook624f7972008-05-31 16:11:38 +0000507 k = &ts->sigtab[sig - 1];
aurel32ca587a82008-12-18 22:44:13 +0000508 queue = gdb_queuesig ();
pbrook624f7972008-05-31 16:11:38 +0000509 handler = sigact_table[sig - 1]._sa_handler;
Peter Maydella7ec0f92014-03-14 14:36:56 +0000510
511 if (ts->sigsegv_blocked && sig == TARGET_SIGSEGV) {
512 /* Guest has blocked SIGSEGV but we got one anyway. Assume this
513 * is a forced SIGSEGV (ie one the kernel handles via force_sig_info
514 * because it got a real MMU fault). A blocked SIGSEGV in that
515 * situation is treated as if using the default handler. This is
516 * not correct if some other process has randomly sent us a SIGSEGV
517 * via kill(), but that is not easy to distinguish at this point,
518 * so we assume it doesn't happen.
519 */
520 handler = TARGET_SIG_DFL;
521 }
522
aurel32ca587a82008-12-18 22:44:13 +0000523 if (!queue && handler == TARGET_SIG_DFL) {
ths60b19692008-11-27 15:47:15 +0000524 if (sig == TARGET_SIGTSTP || sig == TARGET_SIGTTIN || sig == TARGET_SIGTTOU) {
525 kill(getpid(),SIGSTOP);
526 return 0;
527 } else
bellard66fb9762003-03-23 01:06:05 +0000528 /* default handler : ignore some signal. The other are fatal */
ths5fafdf22007-09-16 21:08:06 +0000529 if (sig != TARGET_SIGCHLD &&
530 sig != TARGET_SIGURG &&
ths60b19692008-11-27 15:47:15 +0000531 sig != TARGET_SIGWINCH &&
532 sig != TARGET_SIGCONT) {
bellard66fb9762003-03-23 01:06:05 +0000533 force_sig(sig);
bellard9de5e442003-03-23 16:49:39 +0000534 } else {
535 return 0; /* indicate ignored */
bellard66fb9762003-03-23 01:06:05 +0000536 }
aurel32ca587a82008-12-18 22:44:13 +0000537 } else if (!queue && handler == TARGET_SIG_IGN) {
bellard66fb9762003-03-23 01:06:05 +0000538 /* ignore signal */
bellard9de5e442003-03-23 16:49:39 +0000539 return 0;
aurel32ca587a82008-12-18 22:44:13 +0000540 } else if (!queue && handler == TARGET_SIG_ERR) {
bellard66fb9762003-03-23 01:06:05 +0000541 force_sig(sig);
542 } else {
bellard9de5e442003-03-23 16:49:39 +0000543 pq = &k->first;
544 if (sig < TARGET_SIGRTMIN) {
545 /* if non real time signal, we queue exactly one signal */
546 if (!k->pending)
547 q = &k->info;
548 else
549 return 0;
550 } else {
551 if (!k->pending) {
552 /* first signal */
553 q = &k->info;
554 } else {
pbrook624f7972008-05-31 16:11:38 +0000555 q = alloc_sigqueue(env);
bellard9de5e442003-03-23 16:49:39 +0000556 if (!q)
557 return -EAGAIN;
558 while (*pq != NULL)
559 pq = &(*pq)->next;
560 }
561 }
562 *pq = q;
563 q->info = *info;
564 q->next = NULL;
565 k->pending = 1;
566 /* signal that a new signal is pending */
pbrook624f7972008-05-31 16:11:38 +0000567 ts->signal_pending = 1;
bellard9de5e442003-03-23 16:49:39 +0000568 return 1; /* indicates that the signal was queued */
569 }
570}
571
ths5fafdf22007-09-16 21:08:06 +0000572static void host_signal_handler(int host_signum, siginfo_t *info,
bellard9de5e442003-03-23 16:49:39 +0000573 void *puc)
574{
Andreas Färbera2247f82013-06-09 19:47:04 +0200575 CPUArchState *env = thread_cpu->env_ptr;
bellard9de5e442003-03-23 16:49:39 +0000576 int sig;
Anthony Liguoric227f092009-10-01 16:12:16 -0500577 target_siginfo_t tinfo;
bellard9de5e442003-03-23 16:49:39 +0000578
579 /* the CPU emulator uses some host signals to detect exceptions,
aurel32eaa449b2009-01-03 13:14:52 +0000580 we forward to it some signals */
aurel32ca587a82008-12-18 22:44:13 +0000581 if ((host_signum == SIGSEGV || host_signum == SIGBUS)
aurel32eaa449b2009-01-03 13:14:52 +0000582 && info->si_code > 0) {
bellardb346ff42003-06-15 20:05:50 +0000583 if (cpu_signal_handler(host_signum, info, puc))
bellard9de5e442003-03-23 16:49:39 +0000584 return;
585 }
586
587 /* get target signal number */
588 sig = host_to_target_signal(host_signum);
589 if (sig < 1 || sig > TARGET_NSIG)
590 return;
591#if defined(DEBUG_SIGNAL)
bellardbc8a22c2003-03-30 21:02:40 +0000592 fprintf(stderr, "qemu: got signal %d\n", sig);
bellard9de5e442003-03-23 16:49:39 +0000593#endif
594 host_to_target_siginfo_noswap(&tinfo, info);
Andreas Färbera2247f82013-06-09 19:47:04 +0200595 if (queue_signal(env, sig, &tinfo) == 1) {
bellard9de5e442003-03-23 16:49:39 +0000596 /* interrupt the virtual CPU as soon as possible */
Andreas Färbera2247f82013-06-09 19:47:04 +0200597 cpu_exit(thread_cpu);
bellard66fb9762003-03-23 01:06:05 +0000598 }
bellard31e31b82003-02-18 22:55:36 +0000599}
600
ths0da46a62007-10-20 20:23:07 +0000601/* do_sigaltstack() returns target values and errnos. */
bellard579a97f2007-11-11 14:26:47 +0000602/* compare linux/kernel/signal.c:do_sigaltstack() */
603abi_long do_sigaltstack(abi_ulong uss_addr, abi_ulong uoss_addr, abi_ulong sp)
thsa04e1342007-09-27 13:57:58 +0000604{
605 int ret;
606 struct target_sigaltstack oss;
607
608 /* XXX: test errors */
bellard579a97f2007-11-11 14:26:47 +0000609 if(uoss_addr)
thsa04e1342007-09-27 13:57:58 +0000610 {
611 __put_user(target_sigaltstack_used.ss_sp, &oss.ss_sp);
612 __put_user(target_sigaltstack_used.ss_size, &oss.ss_size);
613 __put_user(sas_ss_flags(sp), &oss.ss_flags);
614 }
615
bellard579a97f2007-11-11 14:26:47 +0000616 if(uss_addr)
thsa04e1342007-09-27 13:57:58 +0000617 {
bellard579a97f2007-11-11 14:26:47 +0000618 struct target_sigaltstack *uss;
619 struct target_sigaltstack ss;
thsa04e1342007-09-27 13:57:58 +0000620
ths0da46a62007-10-20 20:23:07 +0000621 ret = -TARGET_EFAULT;
Riku Voipio9eeb8302014-04-23 11:26:34 +0300622 if (!lock_user_struct(VERIFY_READ, uss, uss_addr, 1)) {
thsa04e1342007-09-27 13:57:58 +0000623 goto out;
Riku Voipio9eeb8302014-04-23 11:26:34 +0300624 }
625 __get_user(ss.ss_sp, &uss->ss_sp);
626 __get_user(ss.ss_size, &uss->ss_size);
627 __get_user(ss.ss_flags, &uss->ss_flags);
bellard579a97f2007-11-11 14:26:47 +0000628 unlock_user_struct(uss, uss_addr, 0);
thsa04e1342007-09-27 13:57:58 +0000629
ths0da46a62007-10-20 20:23:07 +0000630 ret = -TARGET_EPERM;
thsa04e1342007-09-27 13:57:58 +0000631 if (on_sig_stack(sp))
632 goto out;
633
ths0da46a62007-10-20 20:23:07 +0000634 ret = -TARGET_EINVAL;
thsa04e1342007-09-27 13:57:58 +0000635 if (ss.ss_flags != TARGET_SS_DISABLE
636 && ss.ss_flags != TARGET_SS_ONSTACK
637 && ss.ss_flags != 0)
638 goto out;
639
640 if (ss.ss_flags == TARGET_SS_DISABLE) {
641 ss.ss_size = 0;
642 ss.ss_sp = 0;
643 } else {
ths0da46a62007-10-20 20:23:07 +0000644 ret = -TARGET_ENOMEM;
thsa04e1342007-09-27 13:57:58 +0000645 if (ss.ss_size < MINSIGSTKSZ)
646 goto out;
647 }
648
649 target_sigaltstack_used.ss_sp = ss.ss_sp;
650 target_sigaltstack_used.ss_size = ss.ss_size;
651 }
652
bellard579a97f2007-11-11 14:26:47 +0000653 if (uoss_addr) {
ths0da46a62007-10-20 20:23:07 +0000654 ret = -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +0000655 if (copy_to_user(uoss_addr, &oss, sizeof(oss)))
thsa04e1342007-09-27 13:57:58 +0000656 goto out;
thsa04e1342007-09-27 13:57:58 +0000657 }
658
659 ret = 0;
660out:
661 return ret;
662}
663
ths0da46a62007-10-20 20:23:07 +0000664/* do_sigaction() return host values and errnos */
bellard66fb9762003-03-23 01:06:05 +0000665int do_sigaction(int sig, const struct target_sigaction *act,
666 struct target_sigaction *oact)
bellard31e31b82003-02-18 22:55:36 +0000667{
pbrook624f7972008-05-31 16:11:38 +0000668 struct target_sigaction *k;
bellard773b93e2004-01-04 17:15:59 +0000669 struct sigaction act1;
670 int host_sig;
ths0da46a62007-10-20 20:23:07 +0000671 int ret = 0;
bellard31e31b82003-02-18 22:55:36 +0000672
ths2a913eb2008-11-27 15:46:25 +0000673 if (sig < 1 || sig > TARGET_NSIG || sig == TARGET_SIGKILL || sig == TARGET_SIGSTOP)
bellard66fb9762003-03-23 01:06:05 +0000674 return -EINVAL;
675 k = &sigact_table[sig - 1];
bellard773b93e2004-01-04 17:15:59 +0000676#if defined(DEBUG_SIGNAL)
Blue Swirl0bf9e312009-07-20 17:19:25 +0000677 fprintf(stderr, "sigaction sig=%d act=0x%p, oact=0x%p\n",
678 sig, act, oact);
bellard66fb9762003-03-23 01:06:05 +0000679#endif
680 if (oact) {
Richard Hendersond2565872013-01-04 16:39:32 -0800681 __put_user(k->_sa_handler, &oact->_sa_handler);
682 __put_user(k->sa_flags, &oact->sa_flags);
ths388bb212007-05-13 13:58:00 +0000683#if !defined(TARGET_MIPS)
Richard Hendersond2565872013-01-04 16:39:32 -0800684 __put_user(k->sa_restorer, &oact->sa_restorer);
ths388bb212007-05-13 13:58:00 +0000685#endif
Richard Hendersond2565872013-01-04 16:39:32 -0800686 /* Not swapped. */
pbrook624f7972008-05-31 16:11:38 +0000687 oact->sa_mask = k->sa_mask;
bellard66fb9762003-03-23 01:06:05 +0000688 }
689 if (act) {
pbrook624f7972008-05-31 16:11:38 +0000690 /* FIXME: This is not threadsafe. */
Richard Hendersond2565872013-01-04 16:39:32 -0800691 __get_user(k->_sa_handler, &act->_sa_handler);
692 __get_user(k->sa_flags, &act->sa_flags);
ths388bb212007-05-13 13:58:00 +0000693#if !defined(TARGET_MIPS)
Richard Hendersond2565872013-01-04 16:39:32 -0800694 __get_user(k->sa_restorer, &act->sa_restorer);
ths388bb212007-05-13 13:58:00 +0000695#endif
Richard Hendersond2565872013-01-04 16:39:32 -0800696 /* To be swapped in target_to_host_sigset. */
pbrook624f7972008-05-31 16:11:38 +0000697 k->sa_mask = act->sa_mask;
bellard773b93e2004-01-04 17:15:59 +0000698
699 /* we update the host linux signal state */
700 host_sig = target_to_host_signal(sig);
701 if (host_sig != SIGSEGV && host_sig != SIGBUS) {
702 sigfillset(&act1.sa_mask);
703 act1.sa_flags = SA_SIGINFO;
pbrook624f7972008-05-31 16:11:38 +0000704 if (k->sa_flags & TARGET_SA_RESTART)
bellard773b93e2004-01-04 17:15:59 +0000705 act1.sa_flags |= SA_RESTART;
706 /* NOTE: it is important to update the host kernel signal
707 ignore state to avoid getting unexpected interrupted
708 syscalls */
pbrook624f7972008-05-31 16:11:38 +0000709 if (k->_sa_handler == TARGET_SIG_IGN) {
bellard773b93e2004-01-04 17:15:59 +0000710 act1.sa_sigaction = (void *)SIG_IGN;
pbrook624f7972008-05-31 16:11:38 +0000711 } else if (k->_sa_handler == TARGET_SIG_DFL) {
aurel32ca587a82008-12-18 22:44:13 +0000712 if (fatal_signal (sig))
713 act1.sa_sigaction = host_signal_handler;
714 else
715 act1.sa_sigaction = (void *)SIG_DFL;
bellard773b93e2004-01-04 17:15:59 +0000716 } else {
717 act1.sa_sigaction = host_signal_handler;
718 }
ths0da46a62007-10-20 20:23:07 +0000719 ret = sigaction(host_sig, &act1, NULL);
bellard773b93e2004-01-04 17:15:59 +0000720 }
bellard66fb9762003-03-23 01:06:05 +0000721 }
ths0da46a62007-10-20 20:23:07 +0000722 return ret;
bellard66fb9762003-03-23 01:06:05 +0000723}
bellard31e31b82003-02-18 22:55:36 +0000724
Riku Voipiob0fd8d12014-04-23 10:46:13 +0300725static inline void copy_siginfo_to_user(target_siginfo_t *tinfo,
Anthony Liguoric227f092009-10-01 16:12:16 -0500726 const target_siginfo_t *info)
bellard43fff232003-07-09 19:31:39 +0000727{
728 tswap_siginfo(tinfo, info);
bellard43fff232003-07-09 19:31:39 +0000729}
730
thsc3b5bc82007-12-02 06:31:25 +0000731static inline int current_exec_domain_sig(int sig)
732{
733 return /* current->exec_domain && current->exec_domain->signal_invmap
734 && sig < 32 ? current->exec_domain->signal_invmap[sig] : */ sig;
735}
736
bellard459a4012007-11-11 19:45:10 +0000737#if defined(TARGET_I386) && TARGET_ABI_BITS == 32
bellard66fb9762003-03-23 01:06:05 +0000738
739/* from the Linux kernel */
740
741struct target_fpreg {
742 uint16_t significand[4];
743 uint16_t exponent;
744};
745
746struct target_fpxreg {
747 uint16_t significand[4];
748 uint16_t exponent;
749 uint16_t padding[3];
750};
751
752struct target_xmmreg {
blueswir1992f48a2007-10-14 16:27:31 +0000753 abi_ulong element[4];
bellard66fb9762003-03-23 01:06:05 +0000754};
755
756struct target_fpstate {
757 /* Regular FPU environment */
blueswir1992f48a2007-10-14 16:27:31 +0000758 abi_ulong cw;
759 abi_ulong sw;
760 abi_ulong tag;
761 abi_ulong ipoff;
762 abi_ulong cssel;
763 abi_ulong dataoff;
764 abi_ulong datasel;
bellard66fb9762003-03-23 01:06:05 +0000765 struct target_fpreg _st[8];
766 uint16_t status;
767 uint16_t magic; /* 0xffff = regular FPU data only */
768
769 /* FXSR FPU environment */
blueswir1992f48a2007-10-14 16:27:31 +0000770 abi_ulong _fxsr_env[6]; /* FXSR FPU env is ignored */
771 abi_ulong mxcsr;
772 abi_ulong reserved;
bellard66fb9762003-03-23 01:06:05 +0000773 struct target_fpxreg _fxsr_st[8]; /* FXSR FPU reg data is ignored */
774 struct target_xmmreg _xmm[8];
blueswir1992f48a2007-10-14 16:27:31 +0000775 abi_ulong padding[56];
bellard66fb9762003-03-23 01:06:05 +0000776};
777
778#define X86_FXSR_MAGIC 0x0000
779
780struct target_sigcontext {
781 uint16_t gs, __gsh;
782 uint16_t fs, __fsh;
783 uint16_t es, __esh;
784 uint16_t ds, __dsh;
blueswir1992f48a2007-10-14 16:27:31 +0000785 abi_ulong edi;
786 abi_ulong esi;
787 abi_ulong ebp;
788 abi_ulong esp;
789 abi_ulong ebx;
790 abi_ulong edx;
791 abi_ulong ecx;
792 abi_ulong eax;
793 abi_ulong trapno;
794 abi_ulong err;
795 abi_ulong eip;
bellard66fb9762003-03-23 01:06:05 +0000796 uint16_t cs, __csh;
blueswir1992f48a2007-10-14 16:27:31 +0000797 abi_ulong eflags;
798 abi_ulong esp_at_signal;
bellard66fb9762003-03-23 01:06:05 +0000799 uint16_t ss, __ssh;
blueswir1992f48a2007-10-14 16:27:31 +0000800 abi_ulong fpstate; /* pointer */
801 abi_ulong oldmask;
802 abi_ulong cr2;
bellard66fb9762003-03-23 01:06:05 +0000803};
804
bellard66fb9762003-03-23 01:06:05 +0000805struct target_ucontext {
blueswir1992f48a2007-10-14 16:27:31 +0000806 abi_ulong tuc_flags;
807 abi_ulong tuc_link;
Anthony Liguoric227f092009-10-01 16:12:16 -0500808 target_stack_t tuc_stack;
bellardb8076a72005-04-07 22:20:31 +0000809 struct target_sigcontext tuc_mcontext;
Anthony Liguoric227f092009-10-01 16:12:16 -0500810 target_sigset_t tuc_sigmask; /* mask last for extensibility */
bellard66fb9762003-03-23 01:06:05 +0000811};
812
813struct sigframe
814{
blueswir1992f48a2007-10-14 16:27:31 +0000815 abi_ulong pretcode;
bellard66fb9762003-03-23 01:06:05 +0000816 int sig;
817 struct target_sigcontext sc;
818 struct target_fpstate fpstate;
blueswir1992f48a2007-10-14 16:27:31 +0000819 abi_ulong extramask[TARGET_NSIG_WORDS-1];
bellard66fb9762003-03-23 01:06:05 +0000820 char retcode[8];
821};
822
823struct rt_sigframe
824{
blueswir1992f48a2007-10-14 16:27:31 +0000825 abi_ulong pretcode;
bellard66fb9762003-03-23 01:06:05 +0000826 int sig;
blueswir1992f48a2007-10-14 16:27:31 +0000827 abi_ulong pinfo;
828 abi_ulong puc;
bellard66fb9762003-03-23 01:06:05 +0000829 struct target_siginfo info;
830 struct target_ucontext uc;
831 struct target_fpstate fpstate;
832 char retcode[8];
833};
834
835/*
836 * Set up a signal frame.
837 */
838
bellard66fb9762003-03-23 01:06:05 +0000839/* XXX: save x87 state */
Riku Voipio41ecc722014-04-23 11:01:00 +0300840static void setup_sigcontext(struct target_sigcontext *sc,
841 struct target_fpstate *fpstate, CPUX86State *env, abi_ulong mask,
842 abi_ulong fpstate_addr)
bellard66fb9762003-03-23 01:06:05 +0000843{
Andreas Färber27103422013-08-26 08:31:06 +0200844 CPUState *cs = CPU(x86_env_get_cpu(env));
Andreas Färber27103422013-08-26 08:31:06 +0200845 uint16_t magic;
bellard66fb9762003-03-23 01:06:05 +0000846
bellard579a97f2007-11-11 14:26:47 +0000847 /* already locked in setup_frame() */
Riku Voipio1d8b5122014-04-23 10:26:05 +0300848 __put_user(env->segs[R_GS].selector, (unsigned int *)&sc->gs);
849 __put_user(env->segs[R_FS].selector, (unsigned int *)&sc->fs);
850 __put_user(env->segs[R_ES].selector, (unsigned int *)&sc->es);
851 __put_user(env->segs[R_DS].selector, (unsigned int *)&sc->ds);
852 __put_user(env->regs[R_EDI], &sc->edi);
853 __put_user(env->regs[R_ESI], &sc->esi);
854 __put_user(env->regs[R_EBP], &sc->ebp);
855 __put_user(env->regs[R_ESP], &sc->esp);
856 __put_user(env->regs[R_EBX], &sc->ebx);
857 __put_user(env->regs[R_EDX], &sc->edx);
858 __put_user(env->regs[R_ECX], &sc->ecx);
859 __put_user(env->regs[R_EAX], &sc->eax);
860 __put_user(cs->exception_index, &sc->trapno);
861 __put_user(env->error_code, &sc->err);
862 __put_user(env->eip, &sc->eip);
863 __put_user(env->segs[R_CS].selector, (unsigned int *)&sc->cs);
864 __put_user(env->eflags, &sc->eflags);
865 __put_user(env->regs[R_ESP], &sc->esp_at_signal);
866 __put_user(env->segs[R_SS].selector, (unsigned int *)&sc->ss);
bellarded2dcdf2003-05-29 20:06:27 +0000867
bellard28be6232007-11-11 22:23:38 +0000868 cpu_x86_fsave(env, fpstate_addr, 1);
bellarded2dcdf2003-05-29 20:06:27 +0000869 fpstate->status = fpstate->sw;
bellard775b58d2007-11-11 16:22:17 +0000870 magic = 0xffff;
Riku Voipio1d8b5122014-04-23 10:26:05 +0300871 __put_user(magic, &fpstate->magic);
872 __put_user(fpstate_addr, &sc->fpstate);
bellarded2dcdf2003-05-29 20:06:27 +0000873
bellard66fb9762003-03-23 01:06:05 +0000874 /* non-iBCS2 extensions.. */
Riku Voipio1d8b5122014-04-23 10:26:05 +0300875 __put_user(mask, &sc->oldmask);
876 __put_user(env->cr[2], &sc->cr2);
bellard66fb9762003-03-23 01:06:05 +0000877}
878
879/*
880 * Determine which stack to use..
881 */
882
bellard579a97f2007-11-11 14:26:47 +0000883static inline abi_ulong
pbrook624f7972008-05-31 16:11:38 +0000884get_sigframe(struct target_sigaction *ka, CPUX86State *env, size_t frame_size)
bellard66fb9762003-03-23 01:06:05 +0000885{
886 unsigned long esp;
887
888 /* Default to using normal stack */
889 esp = env->regs[R_ESP];
bellard66fb9762003-03-23 01:06:05 +0000890 /* This is the X/Open sanctioned signal stack switching. */
pbrook624f7972008-05-31 16:11:38 +0000891 if (ka->sa_flags & TARGET_SA_ONSTACK) {
thsa04e1342007-09-27 13:57:58 +0000892 if (sas_ss_flags(esp) == 0)
893 esp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
894 }
bellard66fb9762003-03-23 01:06:05 +0000895
896 /* This is the legacy signal stack switching. */
ths5fafdf22007-09-16 21:08:06 +0000897 else
bellarda52c7572003-06-21 13:14:12 +0000898 if ((env->segs[R_SS].selector & 0xffff) != __USER_DS &&
pbrook624f7972008-05-31 16:11:38 +0000899 !(ka->sa_flags & TARGET_SA_RESTORER) &&
900 ka->sa_restorer) {
901 esp = (unsigned long) ka->sa_restorer;
bellarda52c7572003-06-21 13:14:12 +0000902 }
bellard579a97f2007-11-11 14:26:47 +0000903 return (esp - frame_size) & -8ul;
bellard66fb9762003-03-23 01:06:05 +0000904}
905
bellard579a97f2007-11-11 14:26:47 +0000906/* compare linux/arch/i386/kernel/signal.c:setup_frame() */
pbrook624f7972008-05-31 16:11:38 +0000907static void setup_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -0500908 target_sigset_t *set, CPUX86State *env)
bellard66fb9762003-03-23 01:06:05 +0000909{
bellard579a97f2007-11-11 14:26:47 +0000910 abi_ulong frame_addr;
bellard66fb9762003-03-23 01:06:05 +0000911 struct sigframe *frame;
Riku Voipio7df2fa32014-04-23 10:34:53 +0300912 int i;
bellard66fb9762003-03-23 01:06:05 +0000913
bellard579a97f2007-11-11 14:26:47 +0000914 frame_addr = get_sigframe(ka, env, sizeof(*frame));
bellard66fb9762003-03-23 01:06:05 +0000915
bellard579a97f2007-11-11 14:26:47 +0000916 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
bellard66fb9762003-03-23 01:06:05 +0000917 goto give_sigsegv;
bellard579a97f2007-11-11 14:26:47 +0000918
Riku Voipio1d8b5122014-04-23 10:26:05 +0300919 __put_user(current_exec_domain_sig(sig),
920 &frame->sig);
bellard66fb9762003-03-23 01:06:05 +0000921
bellard28be6232007-11-11 22:23:38 +0000922 setup_sigcontext(&frame->sc, &frame->fpstate, env, set->sig[0],
923 frame_addr + offsetof(struct sigframe, fpstate));
bellard66fb9762003-03-23 01:06:05 +0000924
Riku Voipio7df2fa32014-04-23 10:34:53 +0300925 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
926 __put_user(set->sig[i], &frame->extramask[i - 1]);
927 }
bellard66fb9762003-03-23 01:06:05 +0000928
929 /* Set up to return from userspace. If provided, use a stub
930 already in userspace. */
pbrook624f7972008-05-31 16:11:38 +0000931 if (ka->sa_flags & TARGET_SA_RESTORER) {
Riku Voipio1d8b5122014-04-23 10:26:05 +0300932 __put_user(ka->sa_restorer, &frame->pretcode);
bellard66fb9762003-03-23 01:06:05 +0000933 } else {
bellard775b58d2007-11-11 16:22:17 +0000934 uint16_t val16;
bellard28be6232007-11-11 22:23:38 +0000935 abi_ulong retcode_addr;
936 retcode_addr = frame_addr + offsetof(struct sigframe, retcode);
Riku Voipio1d8b5122014-04-23 10:26:05 +0300937 __put_user(retcode_addr, &frame->pretcode);
bellard66fb9762003-03-23 01:06:05 +0000938 /* This is popl %eax ; movl $,%eax ; int $0x80 */
bellard775b58d2007-11-11 16:22:17 +0000939 val16 = 0xb858;
Riku Voipio1d8b5122014-04-23 10:26:05 +0300940 __put_user(val16, (uint16_t *)(frame->retcode+0));
941 __put_user(TARGET_NR_sigreturn, (int *)(frame->retcode+2));
bellard775b58d2007-11-11 16:22:17 +0000942 val16 = 0x80cd;
Riku Voipio1d8b5122014-04-23 10:26:05 +0300943 __put_user(val16, (uint16_t *)(frame->retcode+6));
bellard66fb9762003-03-23 01:06:05 +0000944 }
945
bellard66fb9762003-03-23 01:06:05 +0000946
947 /* Set up registers for signal handler */
bellard28be6232007-11-11 22:23:38 +0000948 env->regs[R_ESP] = frame_addr;
pbrook624f7972008-05-31 16:11:38 +0000949 env->eip = ka->_sa_handler;
bellard66fb9762003-03-23 01:06:05 +0000950
951 cpu_x86_load_seg(env, R_DS, __USER_DS);
952 cpu_x86_load_seg(env, R_ES, __USER_DS);
953 cpu_x86_load_seg(env, R_SS, __USER_DS);
954 cpu_x86_load_seg(env, R_CS, __USER_CS);
955 env->eflags &= ~TF_MASK;
956
bellard579a97f2007-11-11 14:26:47 +0000957 unlock_user_struct(frame, frame_addr, 1);
958
bellard66fb9762003-03-23 01:06:05 +0000959 return;
960
961give_sigsegv:
962 if (sig == TARGET_SIGSEGV)
pbrook624f7972008-05-31 16:11:38 +0000963 ka->_sa_handler = TARGET_SIG_DFL;
bellard66fb9762003-03-23 01:06:05 +0000964 force_sig(TARGET_SIGSEGV /* , current */);
965}
966
bellard579a97f2007-11-11 14:26:47 +0000967/* compare linux/arch/i386/kernel/signal.c:setup_rt_frame() */
pbrook624f7972008-05-31 16:11:38 +0000968static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -0500969 target_siginfo_t *info,
970 target_sigset_t *set, CPUX86State *env)
bellard66fb9762003-03-23 01:06:05 +0000971{
bellard28be6232007-11-11 22:23:38 +0000972 abi_ulong frame_addr, addr;
bellard66fb9762003-03-23 01:06:05 +0000973 struct rt_sigframe *frame;
Riku Voipio0188fad2014-04-23 13:34:15 +0300974 int i;
bellard66fb9762003-03-23 01:06:05 +0000975
bellard579a97f2007-11-11 14:26:47 +0000976 frame_addr = get_sigframe(ka, env, sizeof(*frame));
bellard66fb9762003-03-23 01:06:05 +0000977
bellard579a97f2007-11-11 14:26:47 +0000978 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
bellard66fb9762003-03-23 01:06:05 +0000979 goto give_sigsegv;
bellard66fb9762003-03-23 01:06:05 +0000980
Riku Voipio1d8b5122014-04-23 10:26:05 +0300981 __put_user(current_exec_domain_sig(sig), &frame->sig);
bellard28be6232007-11-11 22:23:38 +0000982 addr = frame_addr + offsetof(struct rt_sigframe, info);
Riku Voipio1d8b5122014-04-23 10:26:05 +0300983 __put_user(addr, &frame->pinfo);
bellard28be6232007-11-11 22:23:38 +0000984 addr = frame_addr + offsetof(struct rt_sigframe, uc);
Riku Voipio1d8b5122014-04-23 10:26:05 +0300985 __put_user(addr, &frame->puc);
Riku Voipiob0fd8d12014-04-23 10:46:13 +0300986 copy_siginfo_to_user(&frame->info, info);
bellard66fb9762003-03-23 01:06:05 +0000987
988 /* Create the ucontext. */
Riku Voipio1d8b5122014-04-23 10:26:05 +0300989 __put_user(0, &frame->uc.tuc_flags);
990 __put_user(0, &frame->uc.tuc_link);
991 __put_user(target_sigaltstack_used.ss_sp, &frame->uc.tuc_stack.ss_sp);
992 __put_user(sas_ss_flags(get_sp_from_cpustate(env)),
993 &frame->uc.tuc_stack.ss_flags);
994 __put_user(target_sigaltstack_used.ss_size,
995 &frame->uc.tuc_stack.ss_size);
Riku Voipio41ecc722014-04-23 11:01:00 +0300996 setup_sigcontext(&frame->uc.tuc_mcontext, &frame->fpstate, env,
997 set->sig[0], frame_addr + offsetof(struct rt_sigframe, fpstate));
998
Riku Voipio0188fad2014-04-23 13:34:15 +0300999 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
1000 __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
1001 }
bellard66fb9762003-03-23 01:06:05 +00001002
1003 /* Set up to return from userspace. If provided, use a stub
1004 already in userspace. */
pbrook624f7972008-05-31 16:11:38 +00001005 if (ka->sa_flags & TARGET_SA_RESTORER) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03001006 __put_user(ka->sa_restorer, &frame->pretcode);
bellard66fb9762003-03-23 01:06:05 +00001007 } else {
bellard775b58d2007-11-11 16:22:17 +00001008 uint16_t val16;
bellard28be6232007-11-11 22:23:38 +00001009 addr = frame_addr + offsetof(struct rt_sigframe, retcode);
Riku Voipio1d8b5122014-04-23 10:26:05 +03001010 __put_user(addr, &frame->pretcode);
bellard66fb9762003-03-23 01:06:05 +00001011 /* This is movl $,%eax ; int $0x80 */
Riku Voipio1d8b5122014-04-23 10:26:05 +03001012 __put_user(0xb8, (char *)(frame->retcode+0));
1013 __put_user(TARGET_NR_rt_sigreturn, (int *)(frame->retcode+1));
bellard775b58d2007-11-11 16:22:17 +00001014 val16 = 0x80cd;
Riku Voipio1d8b5122014-04-23 10:26:05 +03001015 __put_user(val16, (uint16_t *)(frame->retcode+5));
bellard66fb9762003-03-23 01:06:05 +00001016 }
1017
bellard66fb9762003-03-23 01:06:05 +00001018 /* Set up registers for signal handler */
bellard28be6232007-11-11 22:23:38 +00001019 env->regs[R_ESP] = frame_addr;
pbrook624f7972008-05-31 16:11:38 +00001020 env->eip = ka->_sa_handler;
bellard66fb9762003-03-23 01:06:05 +00001021
1022 cpu_x86_load_seg(env, R_DS, __USER_DS);
1023 cpu_x86_load_seg(env, R_ES, __USER_DS);
1024 cpu_x86_load_seg(env, R_SS, __USER_DS);
1025 cpu_x86_load_seg(env, R_CS, __USER_CS);
1026 env->eflags &= ~TF_MASK;
1027
bellard579a97f2007-11-11 14:26:47 +00001028 unlock_user_struct(frame, frame_addr, 1);
1029
bellard66fb9762003-03-23 01:06:05 +00001030 return;
1031
1032give_sigsegv:
1033 if (sig == TARGET_SIGSEGV)
pbrook624f7972008-05-31 16:11:38 +00001034 ka->_sa_handler = TARGET_SIG_DFL;
bellard66fb9762003-03-23 01:06:05 +00001035 force_sig(TARGET_SIGSEGV /* , current */);
1036}
1037
1038static int
1039restore_sigcontext(CPUX86State *env, struct target_sigcontext *sc, int *peax)
1040{
1041 unsigned int err = 0;
bellard28be6232007-11-11 22:23:38 +00001042 abi_ulong fpstate_addr;
1043 unsigned int tmpflags;
bellard66fb9762003-03-23 01:06:05 +00001044
bellard28be6232007-11-11 22:23:38 +00001045 cpu_x86_load_seg(env, R_GS, tswap16(sc->gs));
1046 cpu_x86_load_seg(env, R_FS, tswap16(sc->fs));
1047 cpu_x86_load_seg(env, R_ES, tswap16(sc->es));
1048 cpu_x86_load_seg(env, R_DS, tswap16(sc->ds));
bellard66fb9762003-03-23 01:06:05 +00001049
bellard28be6232007-11-11 22:23:38 +00001050 env->regs[R_EDI] = tswapl(sc->edi);
1051 env->regs[R_ESI] = tswapl(sc->esi);
1052 env->regs[R_EBP] = tswapl(sc->ebp);
1053 env->regs[R_ESP] = tswapl(sc->esp);
1054 env->regs[R_EBX] = tswapl(sc->ebx);
1055 env->regs[R_EDX] = tswapl(sc->edx);
1056 env->regs[R_ECX] = tswapl(sc->ecx);
1057 env->eip = tswapl(sc->eip);
bellard66fb9762003-03-23 01:06:05 +00001058
Mike McCormack9a826d72011-06-01 15:14:37 +09001059 cpu_x86_load_seg(env, R_CS, lduw_p(&sc->cs) | 3);
1060 cpu_x86_load_seg(env, R_SS, lduw_p(&sc->ss) | 3);
ths5fafdf22007-09-16 21:08:06 +00001061
bellard28be6232007-11-11 22:23:38 +00001062 tmpflags = tswapl(sc->eflags);
1063 env->eflags = (env->eflags & ~0x40DD5) | (tmpflags & 0x40DD5);
1064 // regs->orig_eax = -1; /* disable syscall checks */
1065
1066 fpstate_addr = tswapl(sc->fpstate);
1067 if (fpstate_addr != 0) {
1068 if (!access_ok(VERIFY_READ, fpstate_addr,
1069 sizeof(struct target_fpstate)))
1070 goto badframe;
1071 cpu_x86_frstor(env, fpstate_addr, 1);
bellard66fb9762003-03-23 01:06:05 +00001072 }
1073
bellard28be6232007-11-11 22:23:38 +00001074 *peax = tswapl(sc->eax);
bellard66fb9762003-03-23 01:06:05 +00001075 return err;
bellard66fb9762003-03-23 01:06:05 +00001076badframe:
1077 return 1;
bellard66fb9762003-03-23 01:06:05 +00001078}
1079
1080long do_sigreturn(CPUX86State *env)
1081{
bellard579a97f2007-11-11 14:26:47 +00001082 struct sigframe *frame;
1083 abi_ulong frame_addr = env->regs[R_ESP] - 8;
Anthony Liguoric227f092009-10-01 16:12:16 -05001084 target_sigset_t target_set;
bellard66fb9762003-03-23 01:06:05 +00001085 sigset_t set;
1086 int eax, i;
1087
bellard447db212003-05-10 15:10:36 +00001088#if defined(DEBUG_SIGNAL)
1089 fprintf(stderr, "do_sigreturn\n");
1090#endif
bellard579a97f2007-11-11 14:26:47 +00001091 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
1092 goto badframe;
bellard66fb9762003-03-23 01:06:05 +00001093 /* set blocked signals */
Riku Voipiof5f601a2014-04-23 13:00:17 +03001094 __get_user(target_set.sig[0], &frame->sc.oldmask);
bellard92319442004-06-19 16:58:13 +00001095 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
Riku Voipiof5f601a2014-04-23 13:00:17 +03001096 __get_user(target_set.sig[i], &frame->extramask[i - 1]);
bellard92319442004-06-19 16:58:13 +00001097 }
bellard66fb9762003-03-23 01:06:05 +00001098
bellard92319442004-06-19 16:58:13 +00001099 target_to_host_sigset_internal(&set, &target_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00001100 do_sigprocmask(SIG_SETMASK, &set, NULL);
ths3b46e622007-09-17 08:09:54 +00001101
bellard66fb9762003-03-23 01:06:05 +00001102 /* restore registers */
1103 if (restore_sigcontext(env, &frame->sc, &eax))
1104 goto badframe;
bellard579a97f2007-11-11 14:26:47 +00001105 unlock_user_struct(frame, frame_addr, 0);
bellard66fb9762003-03-23 01:06:05 +00001106 return eax;
1107
1108badframe:
bellard579a97f2007-11-11 14:26:47 +00001109 unlock_user_struct(frame, frame_addr, 0);
bellard66fb9762003-03-23 01:06:05 +00001110 force_sig(TARGET_SIGSEGV);
1111 return 0;
1112}
1113
1114long do_rt_sigreturn(CPUX86State *env)
1115{
bellard28be6232007-11-11 22:23:38 +00001116 abi_ulong frame_addr;
1117 struct rt_sigframe *frame;
bellard66fb9762003-03-23 01:06:05 +00001118 sigset_t set;
bellard66fb9762003-03-23 01:06:05 +00001119 int eax;
1120
bellard28be6232007-11-11 22:23:38 +00001121 frame_addr = env->regs[R_ESP] - 4;
1122 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
1123 goto badframe;
bellardb8076a72005-04-07 22:20:31 +00001124 target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
Alex Barcelo1c275922014-03-14 14:36:55 +00001125 do_sigprocmask(SIG_SETMASK, &set, NULL);
ths5fafdf22007-09-16 21:08:06 +00001126
bellardb8076a72005-04-07 22:20:31 +00001127 if (restore_sigcontext(env, &frame->uc.tuc_mcontext, &eax))
bellard66fb9762003-03-23 01:06:05 +00001128 goto badframe;
1129
bellard28be6232007-11-11 22:23:38 +00001130 if (do_sigaltstack(frame_addr + offsetof(struct rt_sigframe, uc.tuc_stack), 0,
1131 get_sp_from_cpustate(env)) == -EFAULT)
bellard66fb9762003-03-23 01:06:05 +00001132 goto badframe;
thsa04e1342007-09-27 13:57:58 +00001133
bellard28be6232007-11-11 22:23:38 +00001134 unlock_user_struct(frame, frame_addr, 0);
bellard66fb9762003-03-23 01:06:05 +00001135 return eax;
1136
1137badframe:
bellard28be6232007-11-11 22:23:38 +00001138 unlock_user_struct(frame, frame_addr, 0);
1139 force_sig(TARGET_SIGSEGV);
bellard66fb9762003-03-23 01:06:05 +00001140 return 0;
1141}
1142
Andreas Schwab1744aea2013-09-03 20:12:16 +01001143#elif defined(TARGET_AARCH64)
1144
1145struct target_sigcontext {
1146 uint64_t fault_address;
1147 /* AArch64 registers */
1148 uint64_t regs[31];
1149 uint64_t sp;
1150 uint64_t pc;
1151 uint64_t pstate;
1152 /* 4K reserved for FP/SIMD state and future expansion */
1153 char __reserved[4096] __attribute__((__aligned__(16)));
1154};
1155
1156struct target_ucontext {
1157 abi_ulong tuc_flags;
1158 abi_ulong tuc_link;
1159 target_stack_t tuc_stack;
1160 target_sigset_t tuc_sigmask;
1161 /* glibc uses a 1024-bit sigset_t */
1162 char __unused[1024 / 8 - sizeof(target_sigset_t)];
1163 /* last for future expansion */
1164 struct target_sigcontext tuc_mcontext;
1165};
1166
1167/*
1168 * Header to be used at the beginning of structures extending the user
1169 * context. Such structures must be placed after the rt_sigframe on the stack
1170 * and be 16-byte aligned. The last structure must be a dummy one with the
1171 * magic and size set to 0.
1172 */
1173struct target_aarch64_ctx {
1174 uint32_t magic;
1175 uint32_t size;
1176};
1177
1178#define TARGET_FPSIMD_MAGIC 0x46508001
1179
1180struct target_fpsimd_context {
1181 struct target_aarch64_ctx head;
1182 uint32_t fpsr;
1183 uint32_t fpcr;
1184 uint64_t vregs[32 * 2]; /* really uint128_t vregs[32] */
1185};
1186
1187/*
1188 * Auxiliary context saved in the sigcontext.__reserved array. Not exported to
1189 * user space as it will change with the addition of new context. User space
1190 * should check the magic/size information.
1191 */
1192struct target_aux_context {
1193 struct target_fpsimd_context fpsimd;
1194 /* additional context to be added before "end" */
1195 struct target_aarch64_ctx end;
1196};
1197
1198struct target_rt_sigframe {
1199 struct target_siginfo info;
1200 struct target_ucontext uc;
1201 uint64_t fp;
1202 uint64_t lr;
1203 uint32_t tramp[2];
1204};
1205
1206static int target_setup_sigframe(struct target_rt_sigframe *sf,
1207 CPUARMState *env, target_sigset_t *set)
1208{
1209 int i;
1210 struct target_aux_context *aux =
1211 (struct target_aux_context *)sf->uc.tuc_mcontext.__reserved;
1212
1213 /* set up the stack frame for unwinding */
1214 __put_user(env->xregs[29], &sf->fp);
1215 __put_user(env->xregs[30], &sf->lr);
1216
1217 for (i = 0; i < 31; i++) {
1218 __put_user(env->xregs[i], &sf->uc.tuc_mcontext.regs[i]);
1219 }
1220 __put_user(env->xregs[31], &sf->uc.tuc_mcontext.sp);
1221 __put_user(env->pc, &sf->uc.tuc_mcontext.pc);
Peter Maydelld3563122013-12-17 19:42:30 +00001222 __put_user(pstate_read(env), &sf->uc.tuc_mcontext.pstate);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001223
Peter Maydell7af03922014-05-01 18:36:17 +01001224 __put_user(env->exception.vaddress, &sf->uc.tuc_mcontext.fault_address);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001225
1226 for (i = 0; i < TARGET_NSIG_WORDS; i++) {
1227 __put_user(set->sig[i], &sf->uc.tuc_sigmask.sig[i]);
1228 }
1229
1230 for (i = 0; i < 32; i++) {
1231#ifdef TARGET_WORDS_BIGENDIAN
1232 __put_user(env->vfp.regs[i * 2], &aux->fpsimd.vregs[i * 2 + 1]);
1233 __put_user(env->vfp.regs[i * 2 + 1], &aux->fpsimd.vregs[i * 2]);
1234#else
1235 __put_user(env->vfp.regs[i * 2], &aux->fpsimd.vregs[i * 2]);
1236 __put_user(env->vfp.regs[i * 2 + 1], &aux->fpsimd.vregs[i * 2 + 1]);
1237#endif
1238 }
Will Newtone0ee1382014-01-04 22:15:48 +00001239 __put_user(vfp_get_fpsr(env), &aux->fpsimd.fpsr);
1240 __put_user(vfp_get_fpcr(env), &aux->fpsimd.fpcr);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001241 __put_user(TARGET_FPSIMD_MAGIC, &aux->fpsimd.head.magic);
1242 __put_user(sizeof(struct target_fpsimd_context),
1243 &aux->fpsimd.head.size);
1244
1245 /* set the "end" magic */
1246 __put_user(0, &aux->end.magic);
1247 __put_user(0, &aux->end.size);
1248
1249 return 0;
1250}
1251
1252static int target_restore_sigframe(CPUARMState *env,
1253 struct target_rt_sigframe *sf)
1254{
1255 sigset_t set;
1256 int i;
1257 struct target_aux_context *aux =
1258 (struct target_aux_context *)sf->uc.tuc_mcontext.__reserved;
Will Newtone0ee1382014-01-04 22:15:48 +00001259 uint32_t magic, size, fpsr, fpcr;
Peter Maydelld3563122013-12-17 19:42:30 +00001260 uint64_t pstate;
Andreas Schwab1744aea2013-09-03 20:12:16 +01001261
1262 target_to_host_sigset(&set, &sf->uc.tuc_sigmask);
Alex Barcelo1c275922014-03-14 14:36:55 +00001263 do_sigprocmask(SIG_SETMASK, &set, NULL);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001264
1265 for (i = 0; i < 31; i++) {
1266 __get_user(env->xregs[i], &sf->uc.tuc_mcontext.regs[i]);
1267 }
1268
1269 __get_user(env->xregs[31], &sf->uc.tuc_mcontext.sp);
1270 __get_user(env->pc, &sf->uc.tuc_mcontext.pc);
Peter Maydelld3563122013-12-17 19:42:30 +00001271 __get_user(pstate, &sf->uc.tuc_mcontext.pstate);
1272 pstate_write(env, pstate);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001273
1274 __get_user(magic, &aux->fpsimd.head.magic);
1275 __get_user(size, &aux->fpsimd.head.size);
1276
1277 if (magic != TARGET_FPSIMD_MAGIC
1278 || size != sizeof(struct target_fpsimd_context)) {
1279 return 1;
1280 }
1281
Peter Maydell4cf23482014-03-02 19:36:38 +00001282 for (i = 0; i < 32; i++) {
1283#ifdef TARGET_WORDS_BIGENDIAN
1284 __get_user(env->vfp.regs[i * 2], &aux->fpsimd.vregs[i * 2 + 1]);
1285 __get_user(env->vfp.regs[i * 2 + 1], &aux->fpsimd.vregs[i * 2]);
1286#else
1287 __get_user(env->vfp.regs[i * 2], &aux->fpsimd.vregs[i * 2]);
1288 __get_user(env->vfp.regs[i * 2 + 1], &aux->fpsimd.vregs[i * 2 + 1]);
1289#endif
Andreas Schwab1744aea2013-09-03 20:12:16 +01001290 }
Will Newtone0ee1382014-01-04 22:15:48 +00001291 __get_user(fpsr, &aux->fpsimd.fpsr);
1292 vfp_set_fpsr(env, fpsr);
1293 __get_user(fpcr, &aux->fpsimd.fpcr);
1294 vfp_set_fpcr(env, fpcr);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001295
1296 return 0;
1297}
1298
1299static abi_ulong get_sigframe(struct target_sigaction *ka, CPUARMState *env)
1300{
1301 abi_ulong sp;
1302
1303 sp = env->xregs[31];
1304
1305 /*
1306 * This is the X/Open sanctioned signal stack switching.
1307 */
1308 if ((ka->sa_flags & SA_ONSTACK) && !sas_ss_flags(sp)) {
1309 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
1310 }
1311
1312 sp = (sp - sizeof(struct target_rt_sigframe)) & ~15;
1313
1314 return sp;
1315}
1316
1317static void target_setup_frame(int usig, struct target_sigaction *ka,
1318 target_siginfo_t *info, target_sigset_t *set,
1319 CPUARMState *env)
1320{
1321 struct target_rt_sigframe *frame;
Michael Matz8a3ae912014-03-02 19:36:39 +00001322 abi_ulong frame_addr, return_addr;
Andreas Schwab1744aea2013-09-03 20:12:16 +01001323
1324 frame_addr = get_sigframe(ka, env);
1325 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
1326 goto give_sigsegv;
1327 }
1328
1329 __put_user(0, &frame->uc.tuc_flags);
1330 __put_user(0, &frame->uc.tuc_link);
1331
1332 __put_user(target_sigaltstack_used.ss_sp,
1333 &frame->uc.tuc_stack.ss_sp);
1334 __put_user(sas_ss_flags(env->xregs[31]),
1335 &frame->uc.tuc_stack.ss_flags);
1336 __put_user(target_sigaltstack_used.ss_size,
1337 &frame->uc.tuc_stack.ss_size);
1338 target_setup_sigframe(frame, env, set);
Michael Matz8a3ae912014-03-02 19:36:39 +00001339 if (ka->sa_flags & TARGET_SA_RESTORER) {
1340 return_addr = ka->sa_restorer;
1341 } else {
1342 /* mov x8,#__NR_rt_sigreturn; svc #0 */
1343 __put_user(0xd2801168, &frame->tramp[0]);
1344 __put_user(0xd4000001, &frame->tramp[1]);
1345 return_addr = frame_addr + offsetof(struct target_rt_sigframe, tramp);
1346 }
Andreas Schwab1744aea2013-09-03 20:12:16 +01001347 env->xregs[0] = usig;
1348 env->xregs[31] = frame_addr;
1349 env->xregs[29] = env->xregs[31] + offsetof(struct target_rt_sigframe, fp);
1350 env->pc = ka->_sa_handler;
Michael Matz8a3ae912014-03-02 19:36:39 +00001351 env->xregs[30] = return_addr;
Andreas Schwab1744aea2013-09-03 20:12:16 +01001352 if (info) {
Riku Voipiob0fd8d12014-04-23 10:46:13 +03001353 copy_siginfo_to_user(&frame->info, info);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001354 env->xregs[1] = frame_addr + offsetof(struct target_rt_sigframe, info);
1355 env->xregs[2] = frame_addr + offsetof(struct target_rt_sigframe, uc);
1356 }
1357
1358 unlock_user_struct(frame, frame_addr, 1);
1359 return;
1360
1361 give_sigsegv:
1362 unlock_user_struct(frame, frame_addr, 1);
1363 force_sig(TARGET_SIGSEGV);
1364}
1365
1366static void setup_rt_frame(int sig, struct target_sigaction *ka,
1367 target_siginfo_t *info, target_sigset_t *set,
1368 CPUARMState *env)
1369{
1370 target_setup_frame(sig, ka, info, set, env);
1371}
1372
1373static void setup_frame(int sig, struct target_sigaction *ka,
1374 target_sigset_t *set, CPUARMState *env)
1375{
1376 target_setup_frame(sig, ka, 0, set, env);
1377}
1378
1379long do_rt_sigreturn(CPUARMState *env)
1380{
Peter Maydell7f72cd22014-03-12 13:06:00 +00001381 struct target_rt_sigframe *frame = NULL;
Andreas Schwab1744aea2013-09-03 20:12:16 +01001382 abi_ulong frame_addr = env->xregs[31];
1383
1384 if (frame_addr & 15) {
1385 goto badframe;
1386 }
1387
1388 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
1389 goto badframe;
1390 }
1391
1392 if (target_restore_sigframe(env, frame)) {
1393 goto badframe;
1394 }
1395
1396 if (do_sigaltstack(frame_addr +
1397 offsetof(struct target_rt_sigframe, uc.tuc_stack),
1398 0, get_sp_from_cpustate(env)) == -EFAULT) {
1399 goto badframe;
1400 }
1401
1402 unlock_user_struct(frame, frame_addr, 0);
1403 return env->xregs[0];
1404
1405 badframe:
1406 unlock_user_struct(frame, frame_addr, 0);
1407 force_sig(TARGET_SIGSEGV);
1408 return 0;
1409}
1410
1411long do_sigreturn(CPUARMState *env)
1412{
1413 return do_rt_sigreturn(env);
1414}
1415
bellard43fff232003-07-09 19:31:39 +00001416#elif defined(TARGET_ARM)
1417
1418struct target_sigcontext {
blueswir1992f48a2007-10-14 16:27:31 +00001419 abi_ulong trap_no;
1420 abi_ulong error_code;
1421 abi_ulong oldmask;
1422 abi_ulong arm_r0;
1423 abi_ulong arm_r1;
1424 abi_ulong arm_r2;
1425 abi_ulong arm_r3;
1426 abi_ulong arm_r4;
1427 abi_ulong arm_r5;
1428 abi_ulong arm_r6;
1429 abi_ulong arm_r7;
1430 abi_ulong arm_r8;
1431 abi_ulong arm_r9;
1432 abi_ulong arm_r10;
1433 abi_ulong arm_fp;
1434 abi_ulong arm_ip;
1435 abi_ulong arm_sp;
1436 abi_ulong arm_lr;
1437 abi_ulong arm_pc;
1438 abi_ulong arm_cpsr;
1439 abi_ulong fault_address;
bellard43fff232003-07-09 19:31:39 +00001440};
1441
pbrooka745ec62008-05-06 15:36:17 +00001442struct target_ucontext_v1 {
blueswir1992f48a2007-10-14 16:27:31 +00001443 abi_ulong tuc_flags;
1444 abi_ulong tuc_link;
Anthony Liguoric227f092009-10-01 16:12:16 -05001445 target_stack_t tuc_stack;
bellardb8076a72005-04-07 22:20:31 +00001446 struct target_sigcontext tuc_mcontext;
Anthony Liguoric227f092009-10-01 16:12:16 -05001447 target_sigset_t tuc_sigmask; /* mask last for extensibility */
bellard43fff232003-07-09 19:31:39 +00001448};
1449
pbrooka745ec62008-05-06 15:36:17 +00001450struct target_ucontext_v2 {
1451 abi_ulong tuc_flags;
1452 abi_ulong tuc_link;
Anthony Liguoric227f092009-10-01 16:12:16 -05001453 target_stack_t tuc_stack;
pbrooka745ec62008-05-06 15:36:17 +00001454 struct target_sigcontext tuc_mcontext;
Anthony Liguoric227f092009-10-01 16:12:16 -05001455 target_sigset_t tuc_sigmask; /* mask last for extensibility */
Peter Maydell5f0b7c82010-11-24 15:20:03 +00001456 char __unused[128 - sizeof(target_sigset_t)];
pbrooka745ec62008-05-06 15:36:17 +00001457 abi_ulong tuc_regspace[128] __attribute__((__aligned__(8)));
1458};
1459
Peter Maydell0d871bd2010-11-24 15:20:05 +00001460struct target_user_vfp {
1461 uint64_t fpregs[32];
1462 abi_ulong fpscr;
1463};
1464
1465struct target_user_vfp_exc {
1466 abi_ulong fpexc;
1467 abi_ulong fpinst;
1468 abi_ulong fpinst2;
1469};
1470
1471struct target_vfp_sigframe {
1472 abi_ulong magic;
1473 abi_ulong size;
1474 struct target_user_vfp ufp;
1475 struct target_user_vfp_exc ufp_exc;
1476} __attribute__((__aligned__(8)));
1477
Peter Maydell08e11252010-11-24 15:20:07 +00001478struct target_iwmmxt_sigframe {
1479 abi_ulong magic;
1480 abi_ulong size;
1481 uint64_t regs[16];
1482 /* Note that not all the coprocessor control registers are stored here */
1483 uint32_t wcssf;
1484 uint32_t wcasf;
1485 uint32_t wcgr0;
1486 uint32_t wcgr1;
1487 uint32_t wcgr2;
1488 uint32_t wcgr3;
1489} __attribute__((__aligned__(8)));
1490
Peter Maydell0d871bd2010-11-24 15:20:05 +00001491#define TARGET_VFP_MAGIC 0x56465001
Peter Maydell08e11252010-11-24 15:20:07 +00001492#define TARGET_IWMMXT_MAGIC 0x12ef842a
Peter Maydell0d871bd2010-11-24 15:20:05 +00001493
pbrooka8c33202008-05-07 23:22:46 +00001494struct sigframe_v1
bellard43fff232003-07-09 19:31:39 +00001495{
1496 struct target_sigcontext sc;
blueswir1992f48a2007-10-14 16:27:31 +00001497 abi_ulong extramask[TARGET_NSIG_WORDS-1];
1498 abi_ulong retcode;
bellard43fff232003-07-09 19:31:39 +00001499};
1500
pbrooka8c33202008-05-07 23:22:46 +00001501struct sigframe_v2
1502{
1503 struct target_ucontext_v2 uc;
1504 abi_ulong retcode;
1505};
1506
pbrooka745ec62008-05-06 15:36:17 +00001507struct rt_sigframe_v1
bellard43fff232003-07-09 19:31:39 +00001508{
bellardf8b0aa22007-11-11 23:03:42 +00001509 abi_ulong pinfo;
1510 abi_ulong puc;
bellard43fff232003-07-09 19:31:39 +00001511 struct target_siginfo info;
pbrooka745ec62008-05-06 15:36:17 +00001512 struct target_ucontext_v1 uc;
1513 abi_ulong retcode;
1514};
1515
1516struct rt_sigframe_v2
1517{
1518 struct target_siginfo info;
1519 struct target_ucontext_v2 uc;
blueswir1992f48a2007-10-14 16:27:31 +00001520 abi_ulong retcode;
bellard43fff232003-07-09 19:31:39 +00001521};
1522
1523#define TARGET_CONFIG_CPU_32 1
1524
1525/*
1526 * For ARM syscalls, we encode the syscall number into the instruction.
1527 */
1528#define SWI_SYS_SIGRETURN (0xef000000|(TARGET_NR_sigreturn + ARM_SYSCALL_BASE))
1529#define SWI_SYS_RT_SIGRETURN (0xef000000|(TARGET_NR_rt_sigreturn + ARM_SYSCALL_BASE))
1530
1531/*
1532 * For Thumb syscalls, we pass the syscall number via r7. We therefore
1533 * need two 16-bit instructions.
1534 */
1535#define SWI_THUMB_SIGRETURN (0xdf00 << 16 | 0x2700 | (TARGET_NR_sigreturn))
1536#define SWI_THUMB_RT_SIGRETURN (0xdf00 << 16 | 0x2700 | (TARGET_NR_rt_sigreturn))
1537
blueswir1992f48a2007-10-14 16:27:31 +00001538static const abi_ulong retcodes[4] = {
bellard43fff232003-07-09 19:31:39 +00001539 SWI_SYS_SIGRETURN, SWI_THUMB_SIGRETURN,
1540 SWI_SYS_RT_SIGRETURN, SWI_THUMB_RT_SIGRETURN
1541};
1542
1543
Andreas Färber05390242012-02-25 03:37:53 +01001544static inline int valid_user_regs(CPUARMState *regs)
bellard43fff232003-07-09 19:31:39 +00001545{
1546 return 1;
1547}
1548
pbrooka8c33202008-05-07 23:22:46 +00001549static void
bellard43fff232003-07-09 19:31:39 +00001550setup_sigcontext(struct target_sigcontext *sc, /*struct _fpstate *fpstate,*/
Andreas Färber05390242012-02-25 03:37:53 +01001551 CPUARMState *env, abi_ulong mask)
bellard43fff232003-07-09 19:31:39 +00001552{
pbrooka8c33202008-05-07 23:22:46 +00001553 __put_user(env->regs[0], &sc->arm_r0);
1554 __put_user(env->regs[1], &sc->arm_r1);
1555 __put_user(env->regs[2], &sc->arm_r2);
1556 __put_user(env->regs[3], &sc->arm_r3);
1557 __put_user(env->regs[4], &sc->arm_r4);
1558 __put_user(env->regs[5], &sc->arm_r5);
1559 __put_user(env->regs[6], &sc->arm_r6);
1560 __put_user(env->regs[7], &sc->arm_r7);
1561 __put_user(env->regs[8], &sc->arm_r8);
1562 __put_user(env->regs[9], &sc->arm_r9);
1563 __put_user(env->regs[10], &sc->arm_r10);
1564 __put_user(env->regs[11], &sc->arm_fp);
1565 __put_user(env->regs[12], &sc->arm_ip);
1566 __put_user(env->regs[13], &sc->arm_sp);
1567 __put_user(env->regs[14], &sc->arm_lr);
1568 __put_user(env->regs[15], &sc->arm_pc);
bellard43fff232003-07-09 19:31:39 +00001569#ifdef TARGET_CONFIG_CPU_32
pbrooka8c33202008-05-07 23:22:46 +00001570 __put_user(cpsr_read(env), &sc->arm_cpsr);
bellard43fff232003-07-09 19:31:39 +00001571#endif
1572
pbrooka8c33202008-05-07 23:22:46 +00001573 __put_user(/* current->thread.trap_no */ 0, &sc->trap_no);
1574 __put_user(/* current->thread.error_code */ 0, &sc->error_code);
1575 __put_user(/* current->thread.address */ 0, &sc->fault_address);
1576 __put_user(mask, &sc->oldmask);
bellard43fff232003-07-09 19:31:39 +00001577}
1578
bellard579a97f2007-11-11 14:26:47 +00001579static inline abi_ulong
Andreas Färber05390242012-02-25 03:37:53 +01001580get_sigframe(struct target_sigaction *ka, CPUARMState *regs, int framesize)
bellard43fff232003-07-09 19:31:39 +00001581{
1582 unsigned long sp = regs->regs[13];
1583
bellard43fff232003-07-09 19:31:39 +00001584 /*
1585 * This is the X/Open sanctioned signal stack switching.
1586 */
pbrook624f7972008-05-31 16:11:38 +00001587 if ((ka->sa_flags & TARGET_SA_ONSTACK) && !sas_ss_flags(sp))
thsa04e1342007-09-27 13:57:58 +00001588 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
bellard43fff232003-07-09 19:31:39 +00001589 /*
1590 * ATPCS B01 mandates 8-byte alignment
1591 */
bellard579a97f2007-11-11 14:26:47 +00001592 return (sp - framesize) & ~7;
bellard43fff232003-07-09 19:31:39 +00001593}
1594
Riku Voipio0188fad2014-04-23 13:34:15 +03001595static void
Andreas Färber05390242012-02-25 03:37:53 +01001596setup_return(CPUARMState *env, struct target_sigaction *ka,
bellardf8b0aa22007-11-11 23:03:42 +00001597 abi_ulong *rc, abi_ulong frame_addr, int usig, abi_ulong rc_addr)
bellard43fff232003-07-09 19:31:39 +00001598{
pbrook624f7972008-05-31 16:11:38 +00001599 abi_ulong handler = ka->_sa_handler;
blueswir1992f48a2007-10-14 16:27:31 +00001600 abi_ulong retcode;
pbrook75b680e2008-03-21 16:07:30 +00001601 int thumb = handler & 1;
Peter Maydell964413d2011-01-14 20:39:19 +01001602 uint32_t cpsr = cpsr_read(env);
1603
1604 cpsr &= ~CPSR_IT;
1605 if (thumb) {
1606 cpsr |= CPSR_T;
1607 } else {
1608 cpsr &= ~CPSR_T;
1609 }
bellard43fff232003-07-09 19:31:39 +00001610
pbrook624f7972008-05-31 16:11:38 +00001611 if (ka->sa_flags & TARGET_SA_RESTORER) {
1612 retcode = ka->sa_restorer;
bellard43fff232003-07-09 19:31:39 +00001613 } else {
1614 unsigned int idx = thumb;
1615
pbrook624f7972008-05-31 16:11:38 +00001616 if (ka->sa_flags & TARGET_SA_SIGINFO)
bellard43fff232003-07-09 19:31:39 +00001617 idx += 2;
1618
Riku Voipio0188fad2014-04-23 13:34:15 +03001619 __put_user(retcodes[idx], rc);
Stefan Weilca8a2772011-10-03 22:43:19 +02001620
bellardf8b0aa22007-11-11 23:03:42 +00001621 retcode = rc_addr + thumb;
bellard43fff232003-07-09 19:31:39 +00001622 }
1623
1624 env->regs[0] = usig;
bellardf8b0aa22007-11-11 23:03:42 +00001625 env->regs[13] = frame_addr;
bellard43fff232003-07-09 19:31:39 +00001626 env->regs[14] = retcode;
1627 env->regs[15] = handler & (thumb ? ~1 : ~3);
Peter Maydell964413d2011-01-14 20:39:19 +01001628 cpsr_write(env, cpsr, 0xffffffff);
bellard43fff232003-07-09 19:31:39 +00001629}
1630
Andreas Färber05390242012-02-25 03:37:53 +01001631static abi_ulong *setup_sigframe_v2_vfp(abi_ulong *regspace, CPUARMState *env)
Peter Maydell0d871bd2010-11-24 15:20:05 +00001632{
1633 int i;
1634 struct target_vfp_sigframe *vfpframe;
1635 vfpframe = (struct target_vfp_sigframe *)regspace;
1636 __put_user(TARGET_VFP_MAGIC, &vfpframe->magic);
1637 __put_user(sizeof(*vfpframe), &vfpframe->size);
1638 for (i = 0; i < 32; i++) {
Peter Maydell005e1a02011-02-10 13:59:35 +00001639 __put_user(float64_val(env->vfp.regs[i]), &vfpframe->ufp.fpregs[i]);
Peter Maydell0d871bd2010-11-24 15:20:05 +00001640 }
1641 __put_user(vfp_get_fpscr(env), &vfpframe->ufp.fpscr);
1642 __put_user(env->vfp.xregs[ARM_VFP_FPEXC], &vfpframe->ufp_exc.fpexc);
1643 __put_user(env->vfp.xregs[ARM_VFP_FPINST], &vfpframe->ufp_exc.fpinst);
1644 __put_user(env->vfp.xregs[ARM_VFP_FPINST2], &vfpframe->ufp_exc.fpinst2);
1645 return (abi_ulong*)(vfpframe+1);
1646}
1647
Andreas Färber05390242012-02-25 03:37:53 +01001648static abi_ulong *setup_sigframe_v2_iwmmxt(abi_ulong *regspace,
1649 CPUARMState *env)
Peter Maydell08e11252010-11-24 15:20:07 +00001650{
1651 int i;
1652 struct target_iwmmxt_sigframe *iwmmxtframe;
1653 iwmmxtframe = (struct target_iwmmxt_sigframe *)regspace;
1654 __put_user(TARGET_IWMMXT_MAGIC, &iwmmxtframe->magic);
1655 __put_user(sizeof(*iwmmxtframe), &iwmmxtframe->size);
1656 for (i = 0; i < 16; i++) {
1657 __put_user(env->iwmmxt.regs[i], &iwmmxtframe->regs[i]);
1658 }
1659 __put_user(env->vfp.xregs[ARM_IWMMXT_wCSSF], &iwmmxtframe->wcssf);
1660 __put_user(env->vfp.xregs[ARM_IWMMXT_wCASF], &iwmmxtframe->wcssf);
1661 __put_user(env->vfp.xregs[ARM_IWMMXT_wCGR0], &iwmmxtframe->wcgr0);
1662 __put_user(env->vfp.xregs[ARM_IWMMXT_wCGR1], &iwmmxtframe->wcgr1);
1663 __put_user(env->vfp.xregs[ARM_IWMMXT_wCGR2], &iwmmxtframe->wcgr2);
1664 __put_user(env->vfp.xregs[ARM_IWMMXT_wCGR3], &iwmmxtframe->wcgr3);
1665 return (abi_ulong*)(iwmmxtframe+1);
1666}
1667
pbrooka8c33202008-05-07 23:22:46 +00001668static void setup_sigframe_v2(struct target_ucontext_v2 *uc,
Andreas Färber05390242012-02-25 03:37:53 +01001669 target_sigset_t *set, CPUARMState *env)
bellard43fff232003-07-09 19:31:39 +00001670{
pbrooka8c33202008-05-07 23:22:46 +00001671 struct target_sigaltstack stack;
1672 int i;
Peter Maydell0d871bd2010-11-24 15:20:05 +00001673 abi_ulong *regspace;
pbrooka8c33202008-05-07 23:22:46 +00001674
1675 /* Clear all the bits of the ucontext we don't use. */
1676 memset(uc, 0, offsetof(struct target_ucontext_v2, tuc_mcontext));
1677
1678 memset(&stack, 0, sizeof(stack));
1679 __put_user(target_sigaltstack_used.ss_sp, &stack.ss_sp);
1680 __put_user(target_sigaltstack_used.ss_size, &stack.ss_size);
1681 __put_user(sas_ss_flags(get_sp_from_cpustate(env)), &stack.ss_flags);
1682 memcpy(&uc->tuc_stack, &stack, sizeof(stack));
1683
1684 setup_sigcontext(&uc->tuc_mcontext, env, set->sig[0]);
Peter Maydell0d871bd2010-11-24 15:20:05 +00001685 /* Save coprocessor signal frame. */
1686 regspace = uc->tuc_regspace;
1687 if (arm_feature(env, ARM_FEATURE_VFP)) {
1688 regspace = setup_sigframe_v2_vfp(regspace, env);
1689 }
Peter Maydell08e11252010-11-24 15:20:07 +00001690 if (arm_feature(env, ARM_FEATURE_IWMMXT)) {
1691 regspace = setup_sigframe_v2_iwmmxt(regspace, env);
1692 }
1693
Peter Maydell0d871bd2010-11-24 15:20:05 +00001694 /* Write terminating magic word */
1695 __put_user(0, regspace);
1696
pbrooka8c33202008-05-07 23:22:46 +00001697 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
1698 __put_user(set->sig[i], &uc->tuc_sigmask.sig[i]);
1699 }
1700}
1701
1702/* compare linux/arch/arm/kernel/signal.c:setup_frame() */
pbrook624f7972008-05-31 16:11:38 +00001703static void setup_frame_v1(int usig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01001704 target_sigset_t *set, CPUARMState *regs)
pbrooka8c33202008-05-07 23:22:46 +00001705{
1706 struct sigframe_v1 *frame;
bellard579a97f2007-11-11 14:26:47 +00001707 abi_ulong frame_addr = get_sigframe(ka, regs, sizeof(*frame));
pbrooka8c33202008-05-07 23:22:46 +00001708 int i;
bellard43fff232003-07-09 19:31:39 +00001709
bellard579a97f2007-11-11 14:26:47 +00001710 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
1711 return;
1712
pbrooka8c33202008-05-07 23:22:46 +00001713 setup_sigcontext(&frame->sc, regs, set->sig[0]);
bellard43fff232003-07-09 19:31:39 +00001714
Riku Voipio0188fad2014-04-23 13:34:15 +03001715 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
1716 __put_user(set->sig[i], &frame->extramask[i - 1]);
1717 }
bellard43fff232003-07-09 19:31:39 +00001718
pbrooka8c33202008-05-07 23:22:46 +00001719 setup_return(regs, ka, &frame->retcode, frame_addr, usig,
1720 frame_addr + offsetof(struct sigframe_v1, retcode));
bellard579a97f2007-11-11 14:26:47 +00001721
bellard579a97f2007-11-11 14:26:47 +00001722 unlock_user_struct(frame, frame_addr, 1);
pbrooka8c33202008-05-07 23:22:46 +00001723}
1724
pbrook624f7972008-05-31 16:11:38 +00001725static void setup_frame_v2(int usig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01001726 target_sigset_t *set, CPUARMState *regs)
pbrooka8c33202008-05-07 23:22:46 +00001727{
1728 struct sigframe_v2 *frame;
1729 abi_ulong frame_addr = get_sigframe(ka, regs, sizeof(*frame));
1730
1731 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
1732 return;
1733
1734 setup_sigframe_v2(&frame->uc, set, regs);
1735
1736 setup_return(regs, ka, &frame->retcode, frame_addr, usig,
1737 frame_addr + offsetof(struct sigframe_v2, retcode));
1738
1739 unlock_user_struct(frame, frame_addr, 1);
1740}
1741
pbrook624f7972008-05-31 16:11:38 +00001742static void setup_frame(int usig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01001743 target_sigset_t *set, CPUARMState *regs)
pbrooka8c33202008-05-07 23:22:46 +00001744{
1745 if (get_osversion() >= 0x020612) {
1746 setup_frame_v2(usig, ka, set, regs);
1747 } else {
1748 setup_frame_v1(usig, ka, set, regs);
1749 }
bellard43fff232003-07-09 19:31:39 +00001750}
1751
bellard579a97f2007-11-11 14:26:47 +00001752/* compare linux/arch/arm/kernel/signal.c:setup_rt_frame() */
pbrook624f7972008-05-31 16:11:38 +00001753static void setup_rt_frame_v1(int usig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05001754 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01001755 target_sigset_t *set, CPUARMState *env)
bellard43fff232003-07-09 19:31:39 +00001756{
pbrooka745ec62008-05-06 15:36:17 +00001757 struct rt_sigframe_v1 *frame;
bellard579a97f2007-11-11 14:26:47 +00001758 abi_ulong frame_addr = get_sigframe(ka, env, sizeof(*frame));
thsa04e1342007-09-27 13:57:58 +00001759 struct target_sigaltstack stack;
pbrooka8c33202008-05-07 23:22:46 +00001760 int i;
bellardf8b0aa22007-11-11 23:03:42 +00001761 abi_ulong info_addr, uc_addr;
bellard43fff232003-07-09 19:31:39 +00001762
bellard579a97f2007-11-11 14:26:47 +00001763 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
bellardedf779f2004-02-22 13:40:13 +00001764 return /* 1 */;
1765
pbrooka745ec62008-05-06 15:36:17 +00001766 info_addr = frame_addr + offsetof(struct rt_sigframe_v1, info);
pbrooka8c33202008-05-07 23:22:46 +00001767 __put_user(info_addr, &frame->pinfo);
pbrooka745ec62008-05-06 15:36:17 +00001768 uc_addr = frame_addr + offsetof(struct rt_sigframe_v1, uc);
pbrooka8c33202008-05-07 23:22:46 +00001769 __put_user(uc_addr, &frame->puc);
1770 copy_siginfo_to_user(&frame->info, info);
bellard43fff232003-07-09 19:31:39 +00001771
1772 /* Clear all the bits of the ucontext we don't use. */
pbrooka745ec62008-05-06 15:36:17 +00001773 memset(&frame->uc, 0, offsetof(struct target_ucontext_v1, tuc_mcontext));
bellard43fff232003-07-09 19:31:39 +00001774
thsa04e1342007-09-27 13:57:58 +00001775 memset(&stack, 0, sizeof(stack));
1776 __put_user(target_sigaltstack_used.ss_sp, &stack.ss_sp);
1777 __put_user(target_sigaltstack_used.ss_size, &stack.ss_size);
1778 __put_user(sas_ss_flags(get_sp_from_cpustate(env)), &stack.ss_flags);
bellard775b58d2007-11-11 16:22:17 +00001779 memcpy(&frame->uc.tuc_stack, &stack, sizeof(stack));
thsa04e1342007-09-27 13:57:58 +00001780
pbrooka8c33202008-05-07 23:22:46 +00001781 setup_sigcontext(&frame->uc.tuc_mcontext, env, set->sig[0]);
bellard92319442004-06-19 16:58:13 +00001782 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
Riku Voipio0188fad2014-04-23 13:34:15 +03001783 __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
bellard92319442004-06-19 16:58:13 +00001784 }
bellard43fff232003-07-09 19:31:39 +00001785
pbrooka8c33202008-05-07 23:22:46 +00001786 setup_return(env, ka, &frame->retcode, frame_addr, usig,
1787 frame_addr + offsetof(struct rt_sigframe_v1, retcode));
pbrooka745ec62008-05-06 15:36:17 +00001788
pbrooka8c33202008-05-07 23:22:46 +00001789 env->regs[1] = info_addr;
1790 env->regs[2] = uc_addr;
pbrooka745ec62008-05-06 15:36:17 +00001791
pbrooka745ec62008-05-06 15:36:17 +00001792 unlock_user_struct(frame, frame_addr, 1);
pbrooka745ec62008-05-06 15:36:17 +00001793}
1794
pbrook624f7972008-05-31 16:11:38 +00001795static void setup_rt_frame_v2(int usig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05001796 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01001797 target_sigset_t *set, CPUARMState *env)
pbrooka745ec62008-05-06 15:36:17 +00001798{
1799 struct rt_sigframe_v2 *frame;
1800 abi_ulong frame_addr = get_sigframe(ka, env, sizeof(*frame));
pbrooka745ec62008-05-06 15:36:17 +00001801 abi_ulong info_addr, uc_addr;
1802
1803 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
1804 return /* 1 */;
1805
1806 info_addr = frame_addr + offsetof(struct rt_sigframe_v2, info);
1807 uc_addr = frame_addr + offsetof(struct rt_sigframe_v2, uc);
pbrooka8c33202008-05-07 23:22:46 +00001808 copy_siginfo_to_user(&frame->info, info);
pbrooka745ec62008-05-06 15:36:17 +00001809
pbrooka8c33202008-05-07 23:22:46 +00001810 setup_sigframe_v2(&frame->uc, set, env);
pbrooka745ec62008-05-06 15:36:17 +00001811
pbrooka8c33202008-05-07 23:22:46 +00001812 setup_return(env, ka, &frame->retcode, frame_addr, usig,
1813 frame_addr + offsetof(struct rt_sigframe_v2, retcode));
pbrooka745ec62008-05-06 15:36:17 +00001814
pbrooka8c33202008-05-07 23:22:46 +00001815 env->regs[1] = info_addr;
1816 env->regs[2] = uc_addr;
pbrooka745ec62008-05-06 15:36:17 +00001817
bellard579a97f2007-11-11 14:26:47 +00001818 unlock_user_struct(frame, frame_addr, 1);
bellard43fff232003-07-09 19:31:39 +00001819}
1820
pbrook624f7972008-05-31 16:11:38 +00001821static void setup_rt_frame(int usig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05001822 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01001823 target_sigset_t *set, CPUARMState *env)
pbrooka745ec62008-05-06 15:36:17 +00001824{
1825 if (get_osversion() >= 0x020612) {
1826 setup_rt_frame_v2(usig, ka, info, set, env);
1827 } else {
1828 setup_rt_frame_v1(usig, ka, info, set, env);
1829 }
1830}
1831
bellard43fff232003-07-09 19:31:39 +00001832static int
Andreas Färber05390242012-02-25 03:37:53 +01001833restore_sigcontext(CPUARMState *env, struct target_sigcontext *sc)
bellard43fff232003-07-09 19:31:39 +00001834{
1835 int err = 0;
bellardb5ff1b32005-11-26 10:38:39 +00001836 uint32_t cpsr;
bellard43fff232003-07-09 19:31:39 +00001837
Riku Voipio1d8b5122014-04-23 10:26:05 +03001838 __get_user(env->regs[0], &sc->arm_r0);
1839 __get_user(env->regs[1], &sc->arm_r1);
1840 __get_user(env->regs[2], &sc->arm_r2);
1841 __get_user(env->regs[3], &sc->arm_r3);
1842 __get_user(env->regs[4], &sc->arm_r4);
1843 __get_user(env->regs[5], &sc->arm_r5);
1844 __get_user(env->regs[6], &sc->arm_r6);
1845 __get_user(env->regs[7], &sc->arm_r7);
1846 __get_user(env->regs[8], &sc->arm_r8);
1847 __get_user(env->regs[9], &sc->arm_r9);
1848 __get_user(env->regs[10], &sc->arm_r10);
1849 __get_user(env->regs[11], &sc->arm_fp);
1850 __get_user(env->regs[12], &sc->arm_ip);
1851 __get_user(env->regs[13], &sc->arm_sp);
1852 __get_user(env->regs[14], &sc->arm_lr);
1853 __get_user(env->regs[15], &sc->arm_pc);
bellard43fff232003-07-09 19:31:39 +00001854#ifdef TARGET_CONFIG_CPU_32
Riku Voipio1d8b5122014-04-23 10:26:05 +03001855 __get_user(cpsr, &sc->arm_cpsr);
pbrook75b680e2008-03-21 16:07:30 +00001856 cpsr_write(env, cpsr, CPSR_USER | CPSR_EXEC);
bellard43fff232003-07-09 19:31:39 +00001857#endif
1858
1859 err |= !valid_user_regs(env);
1860
1861 return err;
1862}
1863
Andreas Färber05390242012-02-25 03:37:53 +01001864static long do_sigreturn_v1(CPUARMState *env)
bellard43fff232003-07-09 19:31:39 +00001865{
bellardf8b0aa22007-11-11 23:03:42 +00001866 abi_ulong frame_addr;
Peter Maydell978fae92013-07-29 12:00:32 +01001867 struct sigframe_v1 *frame = NULL;
Anthony Liguoric227f092009-10-01 16:12:16 -05001868 target_sigset_t set;
bellard43fff232003-07-09 19:31:39 +00001869 sigset_t host_set;
bellard92319442004-06-19 16:58:13 +00001870 int i;
bellard43fff232003-07-09 19:31:39 +00001871
1872 /*
1873 * Since we stacked the signal on a 64-bit boundary,
1874 * then 'sp' should be word aligned here. If it's
1875 * not, then the user is trying to mess with us.
1876 */
bellardf8b0aa22007-11-11 23:03:42 +00001877 frame_addr = env->regs[13];
Peter Maydell978fae92013-07-29 12:00:32 +01001878 if (frame_addr & 7) {
1879 goto badframe;
1880 }
1881
bellardf8b0aa22007-11-11 23:03:42 +00001882 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
1883 goto badframe;
bellard43fff232003-07-09 19:31:39 +00001884
Riku Voipiof5f601a2014-04-23 13:00:17 +03001885 __get_user(set.sig[0], &frame->sc.oldmask);
1886 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
1887 __get_user(set.sig[i], &frame->extramask[i - 1]);
1888 }
bellard43fff232003-07-09 19:31:39 +00001889
bellard92319442004-06-19 16:58:13 +00001890 target_to_host_sigset_internal(&host_set, &set);
Alex Barcelo1c275922014-03-14 14:36:55 +00001891 do_sigprocmask(SIG_SETMASK, &host_set, NULL);
bellard43fff232003-07-09 19:31:39 +00001892
1893 if (restore_sigcontext(env, &frame->sc))
1894 goto badframe;
1895
1896#if 0
1897 /* Send SIGTRAP if we're single-stepping */
1898 if (ptrace_cancel_bpt(current))
1899 send_sig(SIGTRAP, current, 1);
1900#endif
bellardf8b0aa22007-11-11 23:03:42 +00001901 unlock_user_struct(frame, frame_addr, 0);
1902 return env->regs[0];
bellard43fff232003-07-09 19:31:39 +00001903
1904badframe:
Riku Voipio66393fb2009-12-04 15:16:32 +02001905 force_sig(TARGET_SIGSEGV /* , current */);
bellard43fff232003-07-09 19:31:39 +00001906 return 0;
1907}
1908
Andreas Färber05390242012-02-25 03:37:53 +01001909static abi_ulong *restore_sigframe_v2_vfp(CPUARMState *env, abi_ulong *regspace)
Peter Maydell5f9099d2010-11-24 15:20:06 +00001910{
1911 int i;
1912 abi_ulong magic, sz;
1913 uint32_t fpscr, fpexc;
1914 struct target_vfp_sigframe *vfpframe;
1915 vfpframe = (struct target_vfp_sigframe *)regspace;
1916
1917 __get_user(magic, &vfpframe->magic);
1918 __get_user(sz, &vfpframe->size);
1919 if (magic != TARGET_VFP_MAGIC || sz != sizeof(*vfpframe)) {
1920 return 0;
1921 }
1922 for (i = 0; i < 32; i++) {
Peter Maydell005e1a02011-02-10 13:59:35 +00001923 __get_user(float64_val(env->vfp.regs[i]), &vfpframe->ufp.fpregs[i]);
Peter Maydell5f9099d2010-11-24 15:20:06 +00001924 }
1925 __get_user(fpscr, &vfpframe->ufp.fpscr);
1926 vfp_set_fpscr(env, fpscr);
1927 __get_user(fpexc, &vfpframe->ufp_exc.fpexc);
1928 /* Sanitise FPEXC: ensure VFP is enabled, FPINST2 is invalid
1929 * and the exception flag is cleared
1930 */
1931 fpexc |= (1 << 30);
1932 fpexc &= ~((1 << 31) | (1 << 28));
1933 env->vfp.xregs[ARM_VFP_FPEXC] = fpexc;
1934 __get_user(env->vfp.xregs[ARM_VFP_FPINST], &vfpframe->ufp_exc.fpinst);
1935 __get_user(env->vfp.xregs[ARM_VFP_FPINST2], &vfpframe->ufp_exc.fpinst2);
1936 return (abi_ulong*)(vfpframe + 1);
1937}
1938
Andreas Färber05390242012-02-25 03:37:53 +01001939static abi_ulong *restore_sigframe_v2_iwmmxt(CPUARMState *env,
1940 abi_ulong *regspace)
Peter Maydella59d69d2010-11-24 15:20:08 +00001941{
1942 int i;
1943 abi_ulong magic, sz;
1944 struct target_iwmmxt_sigframe *iwmmxtframe;
1945 iwmmxtframe = (struct target_iwmmxt_sigframe *)regspace;
1946
1947 __get_user(magic, &iwmmxtframe->magic);
1948 __get_user(sz, &iwmmxtframe->size);
1949 if (magic != TARGET_IWMMXT_MAGIC || sz != sizeof(*iwmmxtframe)) {
1950 return 0;
1951 }
1952 for (i = 0; i < 16; i++) {
1953 __get_user(env->iwmmxt.regs[i], &iwmmxtframe->regs[i]);
1954 }
1955 __get_user(env->vfp.xregs[ARM_IWMMXT_wCSSF], &iwmmxtframe->wcssf);
1956 __get_user(env->vfp.xregs[ARM_IWMMXT_wCASF], &iwmmxtframe->wcssf);
1957 __get_user(env->vfp.xregs[ARM_IWMMXT_wCGR0], &iwmmxtframe->wcgr0);
1958 __get_user(env->vfp.xregs[ARM_IWMMXT_wCGR1], &iwmmxtframe->wcgr1);
1959 __get_user(env->vfp.xregs[ARM_IWMMXT_wCGR2], &iwmmxtframe->wcgr2);
1960 __get_user(env->vfp.xregs[ARM_IWMMXT_wCGR3], &iwmmxtframe->wcgr3);
1961 return (abi_ulong*)(iwmmxtframe + 1);
1962}
1963
Andreas Färber05390242012-02-25 03:37:53 +01001964static int do_sigframe_return_v2(CPUARMState *env, target_ulong frame_addr,
pbrooka8c33202008-05-07 23:22:46 +00001965 struct target_ucontext_v2 *uc)
1966{
1967 sigset_t host_set;
Peter Maydell5f9099d2010-11-24 15:20:06 +00001968 abi_ulong *regspace;
pbrooka8c33202008-05-07 23:22:46 +00001969
1970 target_to_host_sigset(&host_set, &uc->tuc_sigmask);
Alex Barcelo1c275922014-03-14 14:36:55 +00001971 do_sigprocmask(SIG_SETMASK, &host_set, NULL);
pbrooka8c33202008-05-07 23:22:46 +00001972
1973 if (restore_sigcontext(env, &uc->tuc_mcontext))
1974 return 1;
1975
Peter Maydell5f9099d2010-11-24 15:20:06 +00001976 /* Restore coprocessor signal frame */
1977 regspace = uc->tuc_regspace;
1978 if (arm_feature(env, ARM_FEATURE_VFP)) {
1979 regspace = restore_sigframe_v2_vfp(env, regspace);
1980 if (!regspace) {
1981 return 1;
1982 }
1983 }
Peter Maydella59d69d2010-11-24 15:20:08 +00001984 if (arm_feature(env, ARM_FEATURE_IWMMXT)) {
1985 regspace = restore_sigframe_v2_iwmmxt(env, regspace);
1986 if (!regspace) {
1987 return 1;
1988 }
1989 }
Peter Maydell5f9099d2010-11-24 15:20:06 +00001990
pbrooka8c33202008-05-07 23:22:46 +00001991 if (do_sigaltstack(frame_addr + offsetof(struct target_ucontext_v2, tuc_stack), 0, get_sp_from_cpustate(env)) == -EFAULT)
1992 return 1;
1993
1994#if 0
1995 /* Send SIGTRAP if we're single-stepping */
1996 if (ptrace_cancel_bpt(current))
1997 send_sig(SIGTRAP, current, 1);
1998#endif
1999
2000 return 0;
2001}
2002
Andreas Färber05390242012-02-25 03:37:53 +01002003static long do_sigreturn_v2(CPUARMState *env)
pbrooka8c33202008-05-07 23:22:46 +00002004{
2005 abi_ulong frame_addr;
Peter Maydell978fae92013-07-29 12:00:32 +01002006 struct sigframe_v2 *frame = NULL;
pbrooka8c33202008-05-07 23:22:46 +00002007
2008 /*
2009 * Since we stacked the signal on a 64-bit boundary,
2010 * then 'sp' should be word aligned here. If it's
2011 * not, then the user is trying to mess with us.
2012 */
pbrooka8c33202008-05-07 23:22:46 +00002013 frame_addr = env->regs[13];
Peter Maydell978fae92013-07-29 12:00:32 +01002014 if (frame_addr & 7) {
2015 goto badframe;
2016 }
2017
pbrooka8c33202008-05-07 23:22:46 +00002018 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
2019 goto badframe;
2020
2021 if (do_sigframe_return_v2(env, frame_addr, &frame->uc))
2022 goto badframe;
2023
2024 unlock_user_struct(frame, frame_addr, 0);
2025 return env->regs[0];
2026
2027badframe:
2028 unlock_user_struct(frame, frame_addr, 0);
Riku Voipio66393fb2009-12-04 15:16:32 +02002029 force_sig(TARGET_SIGSEGV /* , current */);
pbrooka8c33202008-05-07 23:22:46 +00002030 return 0;
2031}
2032
Andreas Färber05390242012-02-25 03:37:53 +01002033long do_sigreturn(CPUARMState *env)
pbrooka8c33202008-05-07 23:22:46 +00002034{
2035 if (get_osversion() >= 0x020612) {
2036 return do_sigreturn_v2(env);
2037 } else {
2038 return do_sigreturn_v1(env);
2039 }
2040}
2041
Andreas Färber05390242012-02-25 03:37:53 +01002042static long do_rt_sigreturn_v1(CPUARMState *env)
bellard43fff232003-07-09 19:31:39 +00002043{
bellardf8b0aa22007-11-11 23:03:42 +00002044 abi_ulong frame_addr;
Peter Maydell978fae92013-07-29 12:00:32 +01002045 struct rt_sigframe_v1 *frame = NULL;
bellard43fff232003-07-09 19:31:39 +00002046 sigset_t host_set;
2047
2048 /*
2049 * Since we stacked the signal on a 64-bit boundary,
2050 * then 'sp' should be word aligned here. If it's
2051 * not, then the user is trying to mess with us.
2052 */
bellardf8b0aa22007-11-11 23:03:42 +00002053 frame_addr = env->regs[13];
Peter Maydell978fae92013-07-29 12:00:32 +01002054 if (frame_addr & 7) {
2055 goto badframe;
2056 }
2057
bellardf8b0aa22007-11-11 23:03:42 +00002058 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
2059 goto badframe;
bellard43fff232003-07-09 19:31:39 +00002060
bellardb8076a72005-04-07 22:20:31 +00002061 target_to_host_sigset(&host_set, &frame->uc.tuc_sigmask);
Alex Barcelo1c275922014-03-14 14:36:55 +00002062 do_sigprocmask(SIG_SETMASK, &host_set, NULL);
bellard43fff232003-07-09 19:31:39 +00002063
bellardb8076a72005-04-07 22:20:31 +00002064 if (restore_sigcontext(env, &frame->uc.tuc_mcontext))
bellard43fff232003-07-09 19:31:39 +00002065 goto badframe;
2066
pbrooka745ec62008-05-06 15:36:17 +00002067 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 +00002068 goto badframe;
2069
bellard43fff232003-07-09 19:31:39 +00002070#if 0
2071 /* Send SIGTRAP if we're single-stepping */
2072 if (ptrace_cancel_bpt(current))
2073 send_sig(SIGTRAP, current, 1);
2074#endif
bellardf8b0aa22007-11-11 23:03:42 +00002075 unlock_user_struct(frame, frame_addr, 0);
bellard43fff232003-07-09 19:31:39 +00002076 return env->regs[0];
2077
2078badframe:
bellardf8b0aa22007-11-11 23:03:42 +00002079 unlock_user_struct(frame, frame_addr, 0);
Riku Voipio66393fb2009-12-04 15:16:32 +02002080 force_sig(TARGET_SIGSEGV /* , current */);
bellard43fff232003-07-09 19:31:39 +00002081 return 0;
2082}
2083
Andreas Färber05390242012-02-25 03:37:53 +01002084static long do_rt_sigreturn_v2(CPUARMState *env)
pbrooka745ec62008-05-06 15:36:17 +00002085{
2086 abi_ulong frame_addr;
Peter Maydell978fae92013-07-29 12:00:32 +01002087 struct rt_sigframe_v2 *frame = NULL;
pbrooka745ec62008-05-06 15:36:17 +00002088
2089 /*
2090 * Since we stacked the signal on a 64-bit boundary,
2091 * then 'sp' should be word aligned here. If it's
2092 * not, then the user is trying to mess with us.
2093 */
pbrooka745ec62008-05-06 15:36:17 +00002094 frame_addr = env->regs[13];
Peter Maydell978fae92013-07-29 12:00:32 +01002095 if (frame_addr & 7) {
2096 goto badframe;
2097 }
2098
pbrooka745ec62008-05-06 15:36:17 +00002099 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
2100 goto badframe;
2101
pbrooka8c33202008-05-07 23:22:46 +00002102 if (do_sigframe_return_v2(env, frame_addr, &frame->uc))
2103 goto badframe;
pbrooka745ec62008-05-06 15:36:17 +00002104
pbrooka745ec62008-05-06 15:36:17 +00002105 unlock_user_struct(frame, frame_addr, 0);
2106 return env->regs[0];
2107
2108badframe:
2109 unlock_user_struct(frame, frame_addr, 0);
Riku Voipio66393fb2009-12-04 15:16:32 +02002110 force_sig(TARGET_SIGSEGV /* , current */);
pbrooka745ec62008-05-06 15:36:17 +00002111 return 0;
2112}
2113
Andreas Färber05390242012-02-25 03:37:53 +01002114long do_rt_sigreturn(CPUARMState *env)
pbrooka745ec62008-05-06 15:36:17 +00002115{
2116 if (get_osversion() >= 0x020612) {
2117 return do_rt_sigreturn_v2(env);
2118 } else {
2119 return do_rt_sigreturn_v1(env);
2120 }
2121}
2122
bellard6d5e2162004-09-30 22:04:13 +00002123#elif defined(TARGET_SPARC)
bellard80a9d032005-01-03 23:31:27 +00002124
bellard6d5e2162004-09-30 22:04:13 +00002125#define __SUNOS_MAXWIN 31
2126
2127/* This is what SunOS does, so shall I. */
2128struct target_sigcontext {
blueswir1992f48a2007-10-14 16:27:31 +00002129 abi_ulong sigc_onstack; /* state to restore */
bellard6d5e2162004-09-30 22:04:13 +00002130
blueswir1992f48a2007-10-14 16:27:31 +00002131 abi_ulong sigc_mask; /* sigmask to restore */
2132 abi_ulong sigc_sp; /* stack pointer */
2133 abi_ulong sigc_pc; /* program counter */
2134 abi_ulong sigc_npc; /* next program counter */
2135 abi_ulong sigc_psr; /* for condition codes etc */
2136 abi_ulong sigc_g1; /* User uses these two registers */
2137 abi_ulong sigc_o0; /* within the trampoline code. */
bellard6d5e2162004-09-30 22:04:13 +00002138
2139 /* Now comes information regarding the users window set
2140 * at the time of the signal.
2141 */
blueswir1992f48a2007-10-14 16:27:31 +00002142 abi_ulong sigc_oswins; /* outstanding windows */
bellard6d5e2162004-09-30 22:04:13 +00002143
2144 /* stack ptrs for each regwin buf */
2145 char *sigc_spbuf[__SUNOS_MAXWIN];
2146
2147 /* Windows to restore after signal */
2148 struct {
blueswir1992f48a2007-10-14 16:27:31 +00002149 abi_ulong locals[8];
2150 abi_ulong ins[8];
bellard6d5e2162004-09-30 22:04:13 +00002151 } sigc_wbuf[__SUNOS_MAXWIN];
2152};
2153/* A Sparc stack frame */
2154struct sparc_stackf {
blueswir1992f48a2007-10-14 16:27:31 +00002155 abi_ulong locals[8];
Peter Maydelle321c342011-02-01 15:54:52 +00002156 abi_ulong ins[8];
2157 /* It's simpler to treat fp and callers_pc as elements of ins[]
2158 * since we never need to access them ourselves.
2159 */
bellard6d5e2162004-09-30 22:04:13 +00002160 char *structptr;
blueswir1992f48a2007-10-14 16:27:31 +00002161 abi_ulong xargs[6];
2162 abi_ulong xxargs[1];
bellard6d5e2162004-09-30 22:04:13 +00002163};
2164
2165typedef struct {
2166 struct {
blueswir1992f48a2007-10-14 16:27:31 +00002167 abi_ulong psr;
2168 abi_ulong pc;
2169 abi_ulong npc;
2170 abi_ulong y;
2171 abi_ulong u_regs[16]; /* globals and ins */
bellard6d5e2162004-09-30 22:04:13 +00002172 } si_regs;
2173 int si_mask;
2174} __siginfo_t;
2175
2176typedef struct {
Blue Swirl8954bae2012-07-30 15:29:11 +00002177 abi_ulong si_float_regs[32];
bellard6d5e2162004-09-30 22:04:13 +00002178 unsigned long si_fsr;
2179 unsigned long si_fpqdepth;
2180 struct {
2181 unsigned long *insn_addr;
2182 unsigned long insn;
2183 } si_fpqueue [16];
Anthony Liguoric227f092009-10-01 16:12:16 -05002184} qemu_siginfo_fpu_t;
bellard6d5e2162004-09-30 22:04:13 +00002185
2186
2187struct target_signal_frame {
2188 struct sparc_stackf ss;
2189 __siginfo_t info;
bellardf8b0aa22007-11-11 23:03:42 +00002190 abi_ulong fpu_save;
blueswir1992f48a2007-10-14 16:27:31 +00002191 abi_ulong insns[2] __attribute__ ((aligned (8)));
2192 abi_ulong extramask[TARGET_NSIG_WORDS - 1];
2193 abi_ulong extra_size; /* Should be 0 */
Anthony Liguoric227f092009-10-01 16:12:16 -05002194 qemu_siginfo_fpu_t fpu_state;
bellard6d5e2162004-09-30 22:04:13 +00002195};
2196struct target_rt_signal_frame {
2197 struct sparc_stackf ss;
2198 siginfo_t info;
blueswir1992f48a2007-10-14 16:27:31 +00002199 abi_ulong regs[20];
bellard6d5e2162004-09-30 22:04:13 +00002200 sigset_t mask;
bellardf8b0aa22007-11-11 23:03:42 +00002201 abi_ulong fpu_save;
bellard6d5e2162004-09-30 22:04:13 +00002202 unsigned int insns[2];
2203 stack_t stack;
2204 unsigned int extra_size; /* Should be 0 */
Anthony Liguoric227f092009-10-01 16:12:16 -05002205 qemu_siginfo_fpu_t fpu_state;
bellard6d5e2162004-09-30 22:04:13 +00002206};
2207
bellarde80cfcf2004-12-19 23:18:01 +00002208#define UREG_O0 16
2209#define UREG_O6 22
2210#define UREG_I0 0
2211#define UREG_I1 1
2212#define UREG_I2 2
blueswir15bfb56b2007-10-05 17:01:51 +00002213#define UREG_I3 3
2214#define UREG_I4 4
2215#define UREG_I5 5
bellarde80cfcf2004-12-19 23:18:01 +00002216#define UREG_I6 6
2217#define UREG_I7 7
2218#define UREG_L0 8
bellard6d5e2162004-09-30 22:04:13 +00002219#define UREG_FP UREG_I6
2220#define UREG_SP UREG_O6
2221
pbrook624f7972008-05-31 16:11:38 +00002222static inline abi_ulong get_sigframe(struct target_sigaction *sa,
Andreas Färber05390242012-02-25 03:37:53 +01002223 CPUSPARCState *env,
2224 unsigned long framesize)
bellard6d5e2162004-09-30 22:04:13 +00002225{
bellard459a4012007-11-11 19:45:10 +00002226 abi_ulong sp;
bellard6d5e2162004-09-30 22:04:13 +00002227
2228 sp = env->regwptr[UREG_FP];
bellard6d5e2162004-09-30 22:04:13 +00002229
2230 /* This is the X/Open sanctioned signal stack switching. */
pbrook624f7972008-05-31 16:11:38 +00002231 if (sa->sa_flags & TARGET_SA_ONSTACK) {
thsa04e1342007-09-27 13:57:58 +00002232 if (!on_sig_stack(sp)
2233 && !((target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size) & 7))
2234 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
bellard6d5e2162004-09-30 22:04:13 +00002235 }
bellard459a4012007-11-11 19:45:10 +00002236 return sp - framesize;
bellard6d5e2162004-09-30 22:04:13 +00002237}
2238
2239static int
Andreas Färber05390242012-02-25 03:37:53 +01002240setup___siginfo(__siginfo_t *si, CPUSPARCState *env, abi_ulong mask)
bellard6d5e2162004-09-30 22:04:13 +00002241{
2242 int err = 0, i;
2243
Riku Voipio1d8b5122014-04-23 10:26:05 +03002244 __put_user(env->psr, &si->si_regs.psr);
2245 __put_user(env->pc, &si->si_regs.pc);
2246 __put_user(env->npc, &si->si_regs.npc);
2247 __put_user(env->y, &si->si_regs.y);
bellarda315a142005-01-30 22:59:18 +00002248 for (i=0; i < 8; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002249 __put_user(env->gregs[i], &si->si_regs.u_regs[i]);
bellard6d5e2162004-09-30 22:04:13 +00002250 }
bellarda315a142005-01-30 22:59:18 +00002251 for (i=0; i < 8; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002252 __put_user(env->regwptr[UREG_I0 + i], &si->si_regs.u_regs[i+8]);
bellard6d5e2162004-09-30 22:04:13 +00002253 }
Riku Voipio1d8b5122014-04-23 10:26:05 +03002254 __put_user(mask, &si->si_mask);
bellard6d5e2162004-09-30 22:04:13 +00002255 return err;
2256}
bellarde80cfcf2004-12-19 23:18:01 +00002257
bellard80a9d032005-01-03 23:31:27 +00002258#if 0
bellard6d5e2162004-09-30 22:04:13 +00002259static int
2260setup_sigcontext(struct target_sigcontext *sc, /*struct _fpstate *fpstate,*/
Andreas Färber05390242012-02-25 03:37:53 +01002261 CPUSPARCState *env, unsigned long mask)
bellard6d5e2162004-09-30 22:04:13 +00002262{
2263 int err = 0;
2264
Riku Voipio1d8b5122014-04-23 10:26:05 +03002265 __put_user(mask, &sc->sigc_mask);
2266 __put_user(env->regwptr[UREG_SP], &sc->sigc_sp);
2267 __put_user(env->pc, &sc->sigc_pc);
2268 __put_user(env->npc, &sc->sigc_npc);
2269 __put_user(env->psr, &sc->sigc_psr);
2270 __put_user(env->gregs[1], &sc->sigc_g1);
2271 __put_user(env->regwptr[UREG_O0], &sc->sigc_o0);
bellard6d5e2162004-09-30 22:04:13 +00002272
2273 return err;
2274}
bellard80a9d032005-01-03 23:31:27 +00002275#endif
bellard6d5e2162004-09-30 22:04:13 +00002276#define NF_ALIGNEDSZ (((sizeof(struct target_signal_frame) + 7) & (~7)))
2277
pbrook624f7972008-05-31 16:11:38 +00002278static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01002279 target_sigset_t *set, CPUSPARCState *env)
bellard6d5e2162004-09-30 22:04:13 +00002280{
bellard459a4012007-11-11 19:45:10 +00002281 abi_ulong sf_addr;
bellard6d5e2162004-09-30 22:04:13 +00002282 struct target_signal_frame *sf;
2283 int sigframe_size, err, i;
2284
2285 /* 1. Make sure everything is clean */
2286 //synchronize_user_stack();
2287
2288 sigframe_size = NF_ALIGNEDSZ;
bellard459a4012007-11-11 19:45:10 +00002289 sf_addr = get_sigframe(ka, env, sigframe_size);
bellard6d5e2162004-09-30 22:04:13 +00002290
bellard459a4012007-11-11 19:45:10 +00002291 sf = lock_user(VERIFY_WRITE, sf_addr,
2292 sizeof(struct target_signal_frame), 0);
2293 if (!sf)
2294 goto sigsegv;
2295
bellarde80cfcf2004-12-19 23:18:01 +00002296 //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 +00002297#if 0
2298 if (invalid_frame_pointer(sf, sigframe_size))
2299 goto sigill_and_return;
2300#endif
2301 /* 2. Save the current process state */
2302 err = setup___siginfo(&sf->info, env, set->sig[0]);
Riku Voipio1d8b5122014-04-23 10:26:05 +03002303 __put_user(0, &sf->extra_size);
bellard6d5e2162004-09-30 22:04:13 +00002304
Riku Voipio1d8b5122014-04-23 10:26:05 +03002305 //save_fpu_state(regs, &sf->fpu_state);
2306 //__put_user(&sf->fpu_state, &sf->fpu_save);
bellard6d5e2162004-09-30 22:04:13 +00002307
Riku Voipio1d8b5122014-04-23 10:26:05 +03002308 __put_user(set->sig[0], &sf->info.si_mask);
bellard6d5e2162004-09-30 22:04:13 +00002309 for (i = 0; i < TARGET_NSIG_WORDS - 1; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002310 __put_user(set->sig[i + 1], &sf->extramask[i]);
bellard6d5e2162004-09-30 22:04:13 +00002311 }
2312
bellarda315a142005-01-30 22:59:18 +00002313 for (i = 0; i < 8; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002314 __put_user(env->regwptr[i + UREG_L0], &sf->ss.locals[i]);
bellard6d5e2162004-09-30 22:04:13 +00002315 }
bellarda315a142005-01-30 22:59:18 +00002316 for (i = 0; i < 8; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002317 __put_user(env->regwptr[i + UREG_I0], &sf->ss.ins[i]);
bellard6d5e2162004-09-30 22:04:13 +00002318 }
bellard6d5e2162004-09-30 22:04:13 +00002319 if (err)
2320 goto sigsegv;
2321
2322 /* 3. signal handler back-trampoline and parameters */
bellard459a4012007-11-11 19:45:10 +00002323 env->regwptr[UREG_FP] = sf_addr;
bellard6d5e2162004-09-30 22:04:13 +00002324 env->regwptr[UREG_I0] = sig;
bellard459a4012007-11-11 19:45:10 +00002325 env->regwptr[UREG_I1] = sf_addr +
2326 offsetof(struct target_signal_frame, info);
2327 env->regwptr[UREG_I2] = sf_addr +
2328 offsetof(struct target_signal_frame, info);
bellard6d5e2162004-09-30 22:04:13 +00002329
2330 /* 4. signal handler */
pbrook624f7972008-05-31 16:11:38 +00002331 env->pc = ka->_sa_handler;
bellard6d5e2162004-09-30 22:04:13 +00002332 env->npc = (env->pc + 4);
2333 /* 5. return to kernel instructions */
pbrook624f7972008-05-31 16:11:38 +00002334 if (ka->sa_restorer)
2335 env->regwptr[UREG_I7] = ka->sa_restorer;
bellard6d5e2162004-09-30 22:04:13 +00002336 else {
bellard775b58d2007-11-11 16:22:17 +00002337 uint32_t val32;
bellard459a4012007-11-11 19:45:10 +00002338
2339 env->regwptr[UREG_I7] = sf_addr +
2340 offsetof(struct target_signal_frame, insns) - 2 * 4;
bellard6d5e2162004-09-30 22:04:13 +00002341
2342 /* mov __NR_sigreturn, %g1 */
bellard775b58d2007-11-11 16:22:17 +00002343 val32 = 0x821020d8;
Riku Voipio1d8b5122014-04-23 10:26:05 +03002344 __put_user(val32, &sf->insns[0]);
bellard6d5e2162004-09-30 22:04:13 +00002345
2346 /* t 0x10 */
bellard775b58d2007-11-11 16:22:17 +00002347 val32 = 0x91d02010;
Riku Voipio1d8b5122014-04-23 10:26:05 +03002348 __put_user(val32, &sf->insns[1]);
bellard6d5e2162004-09-30 22:04:13 +00002349 if (err)
2350 goto sigsegv;
2351
2352 /* Flush instruction space. */
2353 //flush_sig_insns(current->mm, (unsigned long) &(sf->insns[0]));
bellard80a9d032005-01-03 23:31:27 +00002354 // tb_flush(env);
bellard6d5e2162004-09-30 22:04:13 +00002355 }
bellard459a4012007-11-11 19:45:10 +00002356 unlock_user(sf, sf_addr, sizeof(struct target_signal_frame));
bellard6d5e2162004-09-30 22:04:13 +00002357 return;
bellard459a4012007-11-11 19:45:10 +00002358#if 0
2359sigill_and_return:
bellard6d5e2162004-09-30 22:04:13 +00002360 force_sig(TARGET_SIGILL);
bellard459a4012007-11-11 19:45:10 +00002361#endif
bellard6d5e2162004-09-30 22:04:13 +00002362sigsegv:
bellarde80cfcf2004-12-19 23:18:01 +00002363 //fprintf(stderr, "force_sig\n");
bellard459a4012007-11-11 19:45:10 +00002364 unlock_user(sf, sf_addr, sizeof(struct target_signal_frame));
bellard6d5e2162004-09-30 22:04:13 +00002365 force_sig(TARGET_SIGSEGV);
2366}
bellard6d5e2162004-09-30 22:04:13 +00002367
pbrook624f7972008-05-31 16:11:38 +00002368static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05002369 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01002370 target_sigset_t *set, CPUSPARCState *env)
bellard6d5e2162004-09-30 22:04:13 +00002371{
2372 fprintf(stderr, "setup_rt_frame: not implemented\n");
2373}
2374
Andreas Färber05390242012-02-25 03:37:53 +01002375long do_sigreturn(CPUSPARCState *env)
bellard6d5e2162004-09-30 22:04:13 +00002376{
bellardf8b0aa22007-11-11 23:03:42 +00002377 abi_ulong sf_addr;
bellard6d5e2162004-09-30 22:04:13 +00002378 struct target_signal_frame *sf;
bellarde80cfcf2004-12-19 23:18:01 +00002379 uint32_t up_psr, pc, npc;
Anthony Liguoric227f092009-10-01 16:12:16 -05002380 target_sigset_t set;
bellarde80cfcf2004-12-19 23:18:01 +00002381 sigset_t host_set;
Riku Voipio1d8b5122014-04-23 10:26:05 +03002382 int err=0, i;
bellard6d5e2162004-09-30 22:04:13 +00002383
bellardf8b0aa22007-11-11 23:03:42 +00002384 sf_addr = env->regwptr[UREG_FP];
2385 if (!lock_user_struct(VERIFY_READ, sf, sf_addr, 1))
2386 goto segv_and_exit;
bellard80a9d032005-01-03 23:31:27 +00002387#if 0
bellarde80cfcf2004-12-19 23:18:01 +00002388 fprintf(stderr, "sigreturn\n");
2389 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 +00002390#endif
bellarde80cfcf2004-12-19 23:18:01 +00002391 //cpu_dump_state(env, stderr, fprintf, 0);
bellard6d5e2162004-09-30 22:04:13 +00002392
2393 /* 1. Make sure we are not getting garbage from the user */
bellard6d5e2162004-09-30 22:04:13 +00002394
bellardf8b0aa22007-11-11 23:03:42 +00002395 if (sf_addr & 3)
bellard6d5e2162004-09-30 22:04:13 +00002396 goto segv_and_exit;
2397
Riku Voipio1d8b5122014-04-23 10:26:05 +03002398 __get_user(pc, &sf->info.si_regs.pc);
2399 __get_user(npc, &sf->info.si_regs.npc);
bellard6d5e2162004-09-30 22:04:13 +00002400
bellard6d5e2162004-09-30 22:04:13 +00002401 if ((pc | npc) & 3)
2402 goto segv_and_exit;
2403
2404 /* 2. Restore the state */
Riku Voipio1d8b5122014-04-23 10:26:05 +03002405 __get_user(up_psr, &sf->info.si_regs.psr);
bellarde80cfcf2004-12-19 23:18:01 +00002406
bellard6d5e2162004-09-30 22:04:13 +00002407 /* User can only change condition codes and FPU enabling in %psr. */
bellarda315a142005-01-30 22:59:18 +00002408 env->psr = (up_psr & (PSR_ICC /* | PSR_EF */))
2409 | (env->psr & ~(PSR_ICC /* | PSR_EF */));
2410
2411 env->pc = pc;
2412 env->npc = npc;
Riku Voipio1d8b5122014-04-23 10:26:05 +03002413 __get_user(env->y, &sf->info.si_regs.y);
bellarda315a142005-01-30 22:59:18 +00002414 for (i=0; i < 8; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002415 __get_user(env->gregs[i], &sf->info.si_regs.u_regs[i]);
bellarde80cfcf2004-12-19 23:18:01 +00002416 }
bellarda315a142005-01-30 22:59:18 +00002417 for (i=0; i < 8; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002418 __get_user(env->regwptr[i + UREG_I0], &sf->info.si_regs.u_regs[i+8]);
bellarde80cfcf2004-12-19 23:18:01 +00002419 }
bellard6d5e2162004-09-30 22:04:13 +00002420
Peter Maydell2aec3a22011-06-16 17:37:14 +01002421 /* FIXME: implement FPU save/restore:
2422 * __get_user(fpu_save, &sf->fpu_save);
2423 * if (fpu_save)
2424 * err |= restore_fpu_state(env, fpu_save);
2425 */
bellard6d5e2162004-09-30 22:04:13 +00002426
2427 /* This is pretty much atomic, no amount locking would prevent
2428 * the races which exist anyways.
2429 */
Riku Voipio1d8b5122014-04-23 10:26:05 +03002430 __get_user(set.sig[0], &sf->info.si_mask);
bellarde80cfcf2004-12-19 23:18:01 +00002431 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002432 __get_user(set.sig[i], &sf->extramask[i - 1]);
bellarde80cfcf2004-12-19 23:18:01 +00002433 }
2434
2435 target_to_host_sigset_internal(&host_set, &set);
Alex Barcelo1c275922014-03-14 14:36:55 +00002436 do_sigprocmask(SIG_SETMASK, &host_set, NULL);
bellard6d5e2162004-09-30 22:04:13 +00002437
2438 if (err)
2439 goto segv_and_exit;
bellardf8b0aa22007-11-11 23:03:42 +00002440 unlock_user_struct(sf, sf_addr, 0);
bellard6d5e2162004-09-30 22:04:13 +00002441 return env->regwptr[0];
2442
2443segv_and_exit:
bellardf8b0aa22007-11-11 23:03:42 +00002444 unlock_user_struct(sf, sf_addr, 0);
bellard6d5e2162004-09-30 22:04:13 +00002445 force_sig(TARGET_SIGSEGV);
2446}
2447
Andreas Färber05390242012-02-25 03:37:53 +01002448long do_rt_sigreturn(CPUSPARCState *env)
bellard6d5e2162004-09-30 22:04:13 +00002449{
2450 fprintf(stderr, "do_rt_sigreturn: not implemented\n");
bellardf8b0aa22007-11-11 23:03:42 +00002451 return -TARGET_ENOSYS;
bellard6d5e2162004-09-30 22:04:13 +00002452}
2453
bellard459a4012007-11-11 19:45:10 +00002454#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
blueswir15bfb56b2007-10-05 17:01:51 +00002455#define MC_TSTATE 0
2456#define MC_PC 1
2457#define MC_NPC 2
2458#define MC_Y 3
2459#define MC_G1 4
2460#define MC_G2 5
2461#define MC_G3 6
2462#define MC_G4 7
2463#define MC_G5 8
2464#define MC_G6 9
2465#define MC_G7 10
2466#define MC_O0 11
2467#define MC_O1 12
2468#define MC_O2 13
2469#define MC_O3 14
2470#define MC_O4 15
2471#define MC_O5 16
2472#define MC_O6 17
2473#define MC_O7 18
2474#define MC_NGREG 19
2475
Anthony Liguoric227f092009-10-01 16:12:16 -05002476typedef abi_ulong target_mc_greg_t;
2477typedef target_mc_greg_t target_mc_gregset_t[MC_NGREG];
blueswir15bfb56b2007-10-05 17:01:51 +00002478
2479struct target_mc_fq {
blueswir1992f48a2007-10-14 16:27:31 +00002480 abi_ulong *mcfq_addr;
blueswir15bfb56b2007-10-05 17:01:51 +00002481 uint32_t mcfq_insn;
2482};
2483
2484struct target_mc_fpu {
2485 union {
2486 uint32_t sregs[32];
2487 uint64_t dregs[32];
2488 //uint128_t qregs[16];
2489 } mcfpu_fregs;
blueswir1992f48a2007-10-14 16:27:31 +00002490 abi_ulong mcfpu_fsr;
2491 abi_ulong mcfpu_fprs;
2492 abi_ulong mcfpu_gsr;
blueswir15bfb56b2007-10-05 17:01:51 +00002493 struct target_mc_fq *mcfpu_fq;
2494 unsigned char mcfpu_qcnt;
2495 unsigned char mcfpu_qentsz;
2496 unsigned char mcfpu_enab;
2497};
Anthony Liguoric227f092009-10-01 16:12:16 -05002498typedef struct target_mc_fpu target_mc_fpu_t;
blueswir15bfb56b2007-10-05 17:01:51 +00002499
2500typedef struct {
Anthony Liguoric227f092009-10-01 16:12:16 -05002501 target_mc_gregset_t mc_gregs;
2502 target_mc_greg_t mc_fp;
2503 target_mc_greg_t mc_i7;
2504 target_mc_fpu_t mc_fpregs;
2505} target_mcontext_t;
blueswir15bfb56b2007-10-05 17:01:51 +00002506
2507struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02002508 struct target_ucontext *tuc_link;
2509 abi_ulong tuc_flags;
2510 target_sigset_t tuc_sigmask;
2511 target_mcontext_t tuc_mcontext;
blueswir15bfb56b2007-10-05 17:01:51 +00002512};
2513
2514/* A V9 register window */
2515struct target_reg_window {
blueswir1992f48a2007-10-14 16:27:31 +00002516 abi_ulong locals[8];
2517 abi_ulong ins[8];
blueswir15bfb56b2007-10-05 17:01:51 +00002518};
2519
2520#define TARGET_STACK_BIAS 2047
2521
2522/* {set, get}context() needed for 64-bit SparcLinux userland. */
2523void sparc64_set_context(CPUSPARCState *env)
2524{
bellard459a4012007-11-11 19:45:10 +00002525 abi_ulong ucp_addr;
2526 struct target_ucontext *ucp;
Anthony Liguoric227f092009-10-01 16:12:16 -05002527 target_mc_gregset_t *grp;
blueswir1992f48a2007-10-14 16:27:31 +00002528 abi_ulong pc, npc, tstate;
bellard459a4012007-11-11 19:45:10 +00002529 abi_ulong fp, i7, w_addr;
Riku Voipio1d8b5122014-04-23 10:26:05 +03002530 int err = 0;
blueswir15bfb56b2007-10-05 17:01:51 +00002531 unsigned int i;
blueswir15bfb56b2007-10-05 17:01:51 +00002532
bellard459a4012007-11-11 19:45:10 +00002533 ucp_addr = env->regwptr[UREG_I0];
2534 if (!lock_user_struct(VERIFY_READ, ucp, ucp_addr, 1))
2535 goto do_sigsegv;
Aurelien Jarno60e99242010-03-29 02:12:51 +02002536 grp = &ucp->tuc_mcontext.mc_gregs;
Riku Voipio1d8b5122014-04-23 10:26:05 +03002537 __get_user(pc, &((*grp)[MC_PC]));
2538 __get_user(npc, &((*grp)[MC_NPC]));
blueswir15bfb56b2007-10-05 17:01:51 +00002539 if (err || ((pc | npc) & 3))
2540 goto do_sigsegv;
2541 if (env->regwptr[UREG_I1]) {
Anthony Liguoric227f092009-10-01 16:12:16 -05002542 target_sigset_t target_set;
blueswir15bfb56b2007-10-05 17:01:51 +00002543 sigset_t set;
2544
2545 if (TARGET_NSIG_WORDS == 1) {
Aurelien Jarno60e99242010-03-29 02:12:51 +02002546 if (__get_user(target_set.sig[0], &ucp->tuc_sigmask.sig[0]))
blueswir15bfb56b2007-10-05 17:01:51 +00002547 goto do_sigsegv;
2548 } else {
bellard459a4012007-11-11 19:45:10 +00002549 abi_ulong *src, *dst;
Aurelien Jarno60e99242010-03-29 02:12:51 +02002550 src = ucp->tuc_sigmask.sig;
bellard459a4012007-11-11 19:45:10 +00002551 dst = target_set.sig;
Stefan Weil0d9e61c2013-12-07 14:48:08 +01002552 for (i = 0; i < TARGET_NSIG_WORDS; i++, dst++, src++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002553 __get_user(*dst, src);
Stefan Weil0d9e61c2013-12-07 14:48:08 +01002554 }
blueswir15bfb56b2007-10-05 17:01:51 +00002555 if (err)
2556 goto do_sigsegv;
2557 }
2558 target_to_host_sigset_internal(&set, &target_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00002559 do_sigprocmask(SIG_SETMASK, &set, NULL);
blueswir15bfb56b2007-10-05 17:01:51 +00002560 }
2561 env->pc = pc;
2562 env->npc = npc;
Riku Voipio1d8b5122014-04-23 10:26:05 +03002563 __get_user(env->y, &((*grp)[MC_Y]));
2564 __get_user(tstate, &((*grp)[MC_TSTATE]));
blueswir15bfb56b2007-10-05 17:01:51 +00002565 env->asi = (tstate >> 24) & 0xff;
Blue Swirl5a834bb2010-05-09 20:19:04 +00002566 cpu_put_ccr(env, tstate >> 32);
2567 cpu_put_cwp64(env, tstate & 0x1f);
Riku Voipio1d8b5122014-04-23 10:26:05 +03002568 __get_user(env->gregs[1], (&(*grp)[MC_G1]));
2569 __get_user(env->gregs[2], (&(*grp)[MC_G2]));
2570 __get_user(env->gregs[3], (&(*grp)[MC_G3]));
2571 __get_user(env->gregs[4], (&(*grp)[MC_G4]));
2572 __get_user(env->gregs[5], (&(*grp)[MC_G5]));
2573 __get_user(env->gregs[6], (&(*grp)[MC_G6]));
2574 __get_user(env->gregs[7], (&(*grp)[MC_G7]));
2575 __get_user(env->regwptr[UREG_I0], (&(*grp)[MC_O0]));
2576 __get_user(env->regwptr[UREG_I1], (&(*grp)[MC_O1]));
2577 __get_user(env->regwptr[UREG_I2], (&(*grp)[MC_O2]));
2578 __get_user(env->regwptr[UREG_I3], (&(*grp)[MC_O3]));
2579 __get_user(env->regwptr[UREG_I4], (&(*grp)[MC_O4]));
2580 __get_user(env->regwptr[UREG_I5], (&(*grp)[MC_O5]));
2581 __get_user(env->regwptr[UREG_I6], (&(*grp)[MC_O6]));
2582 __get_user(env->regwptr[UREG_I7], (&(*grp)[MC_O7]));
blueswir15bfb56b2007-10-05 17:01:51 +00002583
Riku Voipio1d8b5122014-04-23 10:26:05 +03002584 __get_user(fp, &(ucp->tuc_mcontext.mc_fp));
2585 __get_user(i7, &(ucp->tuc_mcontext.mc_i7));
blueswir15bfb56b2007-10-05 17:01:51 +00002586
bellard459a4012007-11-11 19:45:10 +00002587 w_addr = TARGET_STACK_BIAS+env->regwptr[UREG_I6];
2588 if (put_user(fp, w_addr + offsetof(struct target_reg_window, ins[6]),
2589 abi_ulong) != 0)
2590 goto do_sigsegv;
2591 if (put_user(i7, w_addr + offsetof(struct target_reg_window, ins[7]),
2592 abi_ulong) != 0)
2593 goto do_sigsegv;
Peter Maydellc7b016b2011-06-16 17:37:15 +01002594 /* FIXME this does not match how the kernel handles the FPU in
2595 * its sparc64_set_context implementation. In particular the FPU
2596 * is only restored if fenab is non-zero in:
2597 * __get_user(fenab, &(ucp->tuc_mcontext.mc_fpregs.mcfpu_enab));
2598 */
Aurelien Jarno60e99242010-03-29 02:12:51 +02002599 err |= __get_user(env->fprs, &(ucp->tuc_mcontext.mc_fpregs.mcfpu_fprs));
bellard459a4012007-11-11 19:45:10 +00002600 {
Richard Henderson30038fd2011-10-17 10:42:49 -07002601 uint32_t *src = ucp->tuc_mcontext.mc_fpregs.mcfpu_fregs.sregs;
2602 for (i = 0; i < 64; i++, src++) {
2603 if (i & 1) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002604 __get_user(env->fpr[i/2].l.lower, src);
Richard Henderson30038fd2011-10-17 10:42:49 -07002605 } else {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002606 __get_user(env->fpr[i/2].l.upper, src);
Richard Henderson30038fd2011-10-17 10:42:49 -07002607 }
2608 }
bellard459a4012007-11-11 19:45:10 +00002609 }
Riku Voipio1d8b5122014-04-23 10:26:05 +03002610 __get_user(env->fsr,
2611 &(ucp->tuc_mcontext.mc_fpregs.mcfpu_fsr));
2612 __get_user(env->gsr,
2613 &(ucp->tuc_mcontext.mc_fpregs.mcfpu_gsr));
blueswir15bfb56b2007-10-05 17:01:51 +00002614 if (err)
2615 goto do_sigsegv;
bellard459a4012007-11-11 19:45:10 +00002616 unlock_user_struct(ucp, ucp_addr, 0);
blueswir15bfb56b2007-10-05 17:01:51 +00002617 return;
2618 do_sigsegv:
bellard459a4012007-11-11 19:45:10 +00002619 unlock_user_struct(ucp, ucp_addr, 0);
Riku Voipio66393fb2009-12-04 15:16:32 +02002620 force_sig(TARGET_SIGSEGV);
blueswir15bfb56b2007-10-05 17:01:51 +00002621}
2622
2623void sparc64_get_context(CPUSPARCState *env)
2624{
bellard459a4012007-11-11 19:45:10 +00002625 abi_ulong ucp_addr;
2626 struct target_ucontext *ucp;
Anthony Liguoric227f092009-10-01 16:12:16 -05002627 target_mc_gregset_t *grp;
2628 target_mcontext_t *mcp;
bellard459a4012007-11-11 19:45:10 +00002629 abi_ulong fp, i7, w_addr;
blueswir15bfb56b2007-10-05 17:01:51 +00002630 int err;
2631 unsigned int i;
Anthony Liguoric227f092009-10-01 16:12:16 -05002632 target_sigset_t target_set;
blueswir15bfb56b2007-10-05 17:01:51 +00002633 sigset_t set;
2634
bellard459a4012007-11-11 19:45:10 +00002635 ucp_addr = env->regwptr[UREG_I0];
2636 if (!lock_user_struct(VERIFY_WRITE, ucp, ucp_addr, 0))
2637 goto do_sigsegv;
2638
Aurelien Jarno60e99242010-03-29 02:12:51 +02002639 mcp = &ucp->tuc_mcontext;
blueswir15bfb56b2007-10-05 17:01:51 +00002640 grp = &mcp->mc_gregs;
2641
2642 /* Skip over the trap instruction, first. */
2643 env->pc = env->npc;
2644 env->npc += 4;
2645
2646 err = 0;
2647
Alex Barcelo1c275922014-03-14 14:36:55 +00002648 do_sigprocmask(0, NULL, &set);
blueswir15bfb56b2007-10-05 17:01:51 +00002649 host_to_target_sigset_internal(&target_set, &set);
bellard459a4012007-11-11 19:45:10 +00002650 if (TARGET_NSIG_WORDS == 1) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002651 __put_user(target_set.sig[0],
2652 (abi_ulong *)&ucp->tuc_sigmask);
bellard459a4012007-11-11 19:45:10 +00002653 } else {
2654 abi_ulong *src, *dst;
2655 src = target_set.sig;
Aurelien Jarno60e99242010-03-29 02:12:51 +02002656 dst = ucp->tuc_sigmask.sig;
Stefan Weil0d9e61c2013-12-07 14:48:08 +01002657 for (i = 0; i < TARGET_NSIG_WORDS; i++, dst++, src++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002658 __put_user(*src, dst);
Stefan Weil0d9e61c2013-12-07 14:48:08 +01002659 }
blueswir15bfb56b2007-10-05 17:01:51 +00002660 if (err)
2661 goto do_sigsegv;
2662 }
2663
bellard459a4012007-11-11 19:45:10 +00002664 /* XXX: tstate must be saved properly */
Riku Voipio1d8b5122014-04-23 10:26:05 +03002665 // __put_user(env->tstate, &((*grp)[MC_TSTATE]));
2666 __put_user(env->pc, &((*grp)[MC_PC]));
2667 __put_user(env->npc, &((*grp)[MC_NPC]));
2668 __put_user(env->y, &((*grp)[MC_Y]));
2669 __put_user(env->gregs[1], &((*grp)[MC_G1]));
2670 __put_user(env->gregs[2], &((*grp)[MC_G2]));
2671 __put_user(env->gregs[3], &((*grp)[MC_G3]));
2672 __put_user(env->gregs[4], &((*grp)[MC_G4]));
2673 __put_user(env->gregs[5], &((*grp)[MC_G5]));
2674 __put_user(env->gregs[6], &((*grp)[MC_G6]));
2675 __put_user(env->gregs[7], &((*grp)[MC_G7]));
2676 __put_user(env->regwptr[UREG_I0], &((*grp)[MC_O0]));
2677 __put_user(env->regwptr[UREG_I1], &((*grp)[MC_O1]));
2678 __put_user(env->regwptr[UREG_I2], &((*grp)[MC_O2]));
2679 __put_user(env->regwptr[UREG_I3], &((*grp)[MC_O3]));
2680 __put_user(env->regwptr[UREG_I4], &((*grp)[MC_O4]));
2681 __put_user(env->regwptr[UREG_I5], &((*grp)[MC_O5]));
2682 __put_user(env->regwptr[UREG_I6], &((*grp)[MC_O6]));
2683 __put_user(env->regwptr[UREG_I7], &((*grp)[MC_O7]));
blueswir15bfb56b2007-10-05 17:01:51 +00002684
bellard459a4012007-11-11 19:45:10 +00002685 w_addr = TARGET_STACK_BIAS+env->regwptr[UREG_I6];
2686 fp = i7 = 0;
2687 if (get_user(fp, w_addr + offsetof(struct target_reg_window, ins[6]),
2688 abi_ulong) != 0)
2689 goto do_sigsegv;
2690 if (get_user(i7, w_addr + offsetof(struct target_reg_window, ins[7]),
2691 abi_ulong) != 0)
2692 goto do_sigsegv;
Riku Voipio1d8b5122014-04-23 10:26:05 +03002693 __put_user(fp, &(mcp->mc_fp));
2694 __put_user(i7, &(mcp->mc_i7));
blueswir15bfb56b2007-10-05 17:01:51 +00002695
bellard459a4012007-11-11 19:45:10 +00002696 {
Richard Henderson30038fd2011-10-17 10:42:49 -07002697 uint32_t *dst = ucp->tuc_mcontext.mc_fpregs.mcfpu_fregs.sregs;
2698 for (i = 0; i < 64; i++, dst++) {
2699 if (i & 1) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002700 __put_user(env->fpr[i/2].l.lower, dst);
Richard Henderson30038fd2011-10-17 10:42:49 -07002701 } else {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002702 __put_user(env->fpr[i/2].l.upper, dst);
Richard Henderson30038fd2011-10-17 10:42:49 -07002703 }
2704 }
bellard459a4012007-11-11 19:45:10 +00002705 }
Riku Voipio1d8b5122014-04-23 10:26:05 +03002706 __put_user(env->fsr, &(mcp->mc_fpregs.mcfpu_fsr));
2707 __put_user(env->gsr, &(mcp->mc_fpregs.mcfpu_gsr));
2708 __put_user(env->fprs, &(mcp->mc_fpregs.mcfpu_fprs));
blueswir15bfb56b2007-10-05 17:01:51 +00002709
2710 if (err)
2711 goto do_sigsegv;
bellard459a4012007-11-11 19:45:10 +00002712 unlock_user_struct(ucp, ucp_addr, 1);
blueswir15bfb56b2007-10-05 17:01:51 +00002713 return;
2714 do_sigsegv:
bellard459a4012007-11-11 19:45:10 +00002715 unlock_user_struct(ucp, ucp_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02002716 force_sig(TARGET_SIGSEGV);
blueswir15bfb56b2007-10-05 17:01:51 +00002717}
2718#endif
Richard Hendersonff970902013-02-10 10:30:42 -08002719#elif defined(TARGET_MIPS) || defined(TARGET_MIPS64)
bellard106ec872006-06-27 21:08:10 +00002720
Richard Hendersonff970902013-02-10 10:30:42 -08002721# if defined(TARGET_ABI_MIPSO32)
bellard106ec872006-06-27 21:08:10 +00002722struct target_sigcontext {
2723 uint32_t sc_regmask; /* Unused */
2724 uint32_t sc_status;
2725 uint64_t sc_pc;
2726 uint64_t sc_regs[32];
2727 uint64_t sc_fpregs[32];
2728 uint32_t sc_ownedfp; /* Unused */
2729 uint32_t sc_fpc_csr;
2730 uint32_t sc_fpc_eir; /* Unused */
2731 uint32_t sc_used_math;
2732 uint32_t sc_dsp; /* dsp status, was sc_ssflags */
Paul Brook94c54952009-07-09 18:40:15 +01002733 uint32_t pad0;
bellard106ec872006-06-27 21:08:10 +00002734 uint64_t sc_mdhi;
2735 uint64_t sc_mdlo;
2736 target_ulong sc_hi1; /* Was sc_cause */
2737 target_ulong sc_lo1; /* Was sc_badvaddr */
2738 target_ulong sc_hi2; /* Was sc_sigset[4] */
2739 target_ulong sc_lo2;
2740 target_ulong sc_hi3;
2741 target_ulong sc_lo3;
2742};
Richard Hendersonff970902013-02-10 10:30:42 -08002743# else /* N32 || N64 */
2744struct target_sigcontext {
2745 uint64_t sc_regs[32];
2746 uint64_t sc_fpregs[32];
2747 uint64_t sc_mdhi;
2748 uint64_t sc_hi1;
2749 uint64_t sc_hi2;
2750 uint64_t sc_hi3;
2751 uint64_t sc_mdlo;
2752 uint64_t sc_lo1;
2753 uint64_t sc_lo2;
2754 uint64_t sc_lo3;
2755 uint64_t sc_pc;
2756 uint32_t sc_fpc_csr;
2757 uint32_t sc_used_math;
2758 uint32_t sc_dsp;
2759 uint32_t sc_reserved;
2760};
2761# endif /* O32 */
bellard106ec872006-06-27 21:08:10 +00002762
2763struct sigframe {
2764 uint32_t sf_ass[4]; /* argument save space for o32 */
2765 uint32_t sf_code[2]; /* signal trampoline */
2766 struct target_sigcontext sf_sc;
Anthony Liguoric227f092009-10-01 16:12:16 -05002767 target_sigset_t sf_mask;
bellard106ec872006-06-27 21:08:10 +00002768};
2769
pbrook0b1bcb02009-04-21 01:41:10 +00002770struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02002771 target_ulong tuc_flags;
2772 target_ulong tuc_link;
2773 target_stack_t tuc_stack;
Paul Brook94c54952009-07-09 18:40:15 +01002774 target_ulong pad0;
Aurelien Jarno60e99242010-03-29 02:12:51 +02002775 struct target_sigcontext tuc_mcontext;
2776 target_sigset_t tuc_sigmask;
pbrook0b1bcb02009-04-21 01:41:10 +00002777};
2778
2779struct target_rt_sigframe {
2780 uint32_t rs_ass[4]; /* argument save space for o32 */
2781 uint32_t rs_code[2]; /* signal trampoline */
2782 struct target_siginfo rs_info;
2783 struct target_ucontext rs_uc;
2784};
2785
bellard106ec872006-06-27 21:08:10 +00002786/* Install trampoline to jump back from signal handler */
2787static inline int install_sigtramp(unsigned int *tramp, unsigned int syscall)
2788{
Richard Henderson084d0492013-02-10 10:30:44 -08002789 int err = 0;
bellard106ec872006-06-27 21:08:10 +00002790
2791 /*
Richard Henderson084d0492013-02-10 10:30:44 -08002792 * Set up the return code ...
2793 *
2794 * li v0, __NR__foo_sigreturn
2795 * syscall
2796 */
bellard106ec872006-06-27 21:08:10 +00002797
Riku Voipio1d8b5122014-04-23 10:26:05 +03002798 __put_user(0x24020000 + syscall, tramp + 0);
2799 __put_user(0x0000000c , tramp + 1);
bellard106ec872006-06-27 21:08:10 +00002800 return err;
2801}
2802
Riku Voipio41ecc722014-04-23 11:01:00 +03002803static inline void setup_sigcontext(CPUMIPSState *regs,
2804 struct target_sigcontext *sc)
bellard106ec872006-06-27 21:08:10 +00002805{
Richard Henderson084d0492013-02-10 10:30:44 -08002806 int i;
bellard106ec872006-06-27 21:08:10 +00002807
Riku Voipio1d8b5122014-04-23 10:26:05 +03002808 __put_user(exception_resume_pc(regs), &sc->sc_pc);
Kwok Cheung Yeung1239b472013-05-17 14:51:21 -07002809 regs->hflags &= ~MIPS_HFLAG_BMASK;
bellard106ec872006-06-27 21:08:10 +00002810
Richard Henderson084d0492013-02-10 10:30:44 -08002811 __put_user(0, &sc->sc_regs[0]);
2812 for (i = 1; i < 32; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002813 __put_user(regs->active_tc.gpr[i], &sc->sc_regs[i]);
Richard Henderson084d0492013-02-10 10:30:44 -08002814 }
bellard106ec872006-06-27 21:08:10 +00002815
Riku Voipio1d8b5122014-04-23 10:26:05 +03002816 __put_user(regs->active_tc.HI[0], &sc->sc_mdhi);
2817 __put_user(regs->active_tc.LO[0], &sc->sc_mdlo);
bellard106ec872006-06-27 21:08:10 +00002818
Richard Henderson084d0492013-02-10 10:30:44 -08002819 /* Rather than checking for dsp existence, always copy. The storage
2820 would just be garbage otherwise. */
Riku Voipio1d8b5122014-04-23 10:26:05 +03002821 __put_user(regs->active_tc.HI[1], &sc->sc_hi1);
2822 __put_user(regs->active_tc.HI[2], &sc->sc_hi2);
2823 __put_user(regs->active_tc.HI[3], &sc->sc_hi3);
2824 __put_user(regs->active_tc.LO[1], &sc->sc_lo1);
2825 __put_user(regs->active_tc.LO[2], &sc->sc_lo2);
2826 __put_user(regs->active_tc.LO[3], &sc->sc_lo3);
Richard Henderson084d0492013-02-10 10:30:44 -08002827 {
2828 uint32_t dsp = cpu_rddsp(0x3ff, regs);
Riku Voipio1d8b5122014-04-23 10:26:05 +03002829 __put_user(dsp, &sc->sc_dsp);
bellard106ec872006-06-27 21:08:10 +00002830 }
Richard Henderson084d0492013-02-10 10:30:44 -08002831
Riku Voipio1d8b5122014-04-23 10:26:05 +03002832 __put_user(1, &sc->sc_used_math);
Richard Henderson084d0492013-02-10 10:30:44 -08002833
2834 for (i = 0; i < 32; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002835 __put_user(regs->active_fpu.fpr[i].d, &sc->sc_fpregs[i]);
bellard106ec872006-06-27 21:08:10 +00002836 }
bellard106ec872006-06-27 21:08:10 +00002837}
2838
Riku Voipio016d2e12014-04-23 11:19:48 +03002839static inline void
Andreas Färber05390242012-02-25 03:37:53 +01002840restore_sigcontext(CPUMIPSState *regs, struct target_sigcontext *sc)
bellard106ec872006-06-27 21:08:10 +00002841{
Richard Henderson084d0492013-02-10 10:30:44 -08002842 int i;
bellard106ec872006-06-27 21:08:10 +00002843
Riku Voipio1d8b5122014-04-23 10:26:05 +03002844 __get_user(regs->CP0_EPC, &sc->sc_pc);
bellard106ec872006-06-27 21:08:10 +00002845
Riku Voipio1d8b5122014-04-23 10:26:05 +03002846 __get_user(regs->active_tc.HI[0], &sc->sc_mdhi);
2847 __get_user(regs->active_tc.LO[0], &sc->sc_mdlo);
bellard106ec872006-06-27 21:08:10 +00002848
Richard Henderson084d0492013-02-10 10:30:44 -08002849 for (i = 1; i < 32; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002850 __get_user(regs->active_tc.gpr[i], &sc->sc_regs[i]);
bellard106ec872006-06-27 21:08:10 +00002851 }
2852
Riku Voipio1d8b5122014-04-23 10:26:05 +03002853 __get_user(regs->active_tc.HI[1], &sc->sc_hi1);
2854 __get_user(regs->active_tc.HI[2], &sc->sc_hi2);
2855 __get_user(regs->active_tc.HI[3], &sc->sc_hi3);
2856 __get_user(regs->active_tc.LO[1], &sc->sc_lo1);
2857 __get_user(regs->active_tc.LO[2], &sc->sc_lo2);
2858 __get_user(regs->active_tc.LO[3], &sc->sc_lo3);
Richard Henderson084d0492013-02-10 10:30:44 -08002859 {
2860 uint32_t dsp;
Riku Voipio1d8b5122014-04-23 10:26:05 +03002861 __get_user(dsp, &sc->sc_dsp);
Richard Henderson084d0492013-02-10 10:30:44 -08002862 cpu_wrdsp(dsp, 0x3ff, regs);
2863 }
2864
2865 for (i = 0; i < 32; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002866 __get_user(regs->active_fpu.fpr[i].d, &sc->sc_fpregs[i]);
Richard Henderson084d0492013-02-10 10:30:44 -08002867 }
bellard106ec872006-06-27 21:08:10 +00002868}
Richard Hendersonff970902013-02-10 10:30:42 -08002869
bellard106ec872006-06-27 21:08:10 +00002870/*
2871 * Determine which stack to use..
2872 */
bellard579a97f2007-11-11 14:26:47 +00002873static inline abi_ulong
Andreas Färber05390242012-02-25 03:37:53 +01002874get_sigframe(struct target_sigaction *ka, CPUMIPSState *regs, size_t frame_size)
bellard106ec872006-06-27 21:08:10 +00002875{
2876 unsigned long sp;
2877
2878 /* Default to using normal stack */
thsb5dc7732008-06-27 10:02:35 +00002879 sp = regs->active_tc.gpr[29];
bellard106ec872006-06-27 21:08:10 +00002880
2881 /*
Stefan Weil93148aa2012-02-26 18:46:12 +01002882 * FPU emulator may have its own trampoline active just
bellard106ec872006-06-27 21:08:10 +00002883 * above the user stack, 16-bytes before the next lowest
2884 * 16 byte boundary. Try to avoid trashing it.
2885 */
2886 sp -= 32;
2887
bellard106ec872006-06-27 21:08:10 +00002888 /* This is the X/Open sanctioned signal stack switching. */
pbrook624f7972008-05-31 16:11:38 +00002889 if ((ka->sa_flags & TARGET_SA_ONSTACK) && (sas_ss_flags (sp) == 0)) {
thsa04e1342007-09-27 13:57:58 +00002890 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
2891 }
bellard106ec872006-06-27 21:08:10 +00002892
bellard579a97f2007-11-11 14:26:47 +00002893 return (sp - frame_size) & ~7;
bellard106ec872006-06-27 21:08:10 +00002894}
2895
Kwok Cheung Yeungea3164a2013-05-17 14:51:20 -07002896static void mips_set_hflags_isa_mode_from_pc(CPUMIPSState *env)
2897{
2898 if (env->insn_flags & (ASE_MIPS16 | ASE_MICROMIPS)) {
2899 env->hflags &= ~MIPS_HFLAG_M16;
2900 env->hflags |= (env->active_tc.PC & 1) << MIPS_HFLAG_M16_SHIFT;
2901 env->active_tc.PC &= ~(target_ulong) 1;
2902 }
2903}
2904
Richard Hendersonff970902013-02-10 10:30:42 -08002905# if defined(TARGET_ABI_MIPSO32)
bellard579a97f2007-11-11 14:26:47 +00002906/* compare linux/arch/mips/kernel/signal.c:setup_frame() */
pbrook624f7972008-05-31 16:11:38 +00002907static void setup_frame(int sig, struct target_sigaction * ka,
Andreas Färber05390242012-02-25 03:37:53 +01002908 target_sigset_t *set, CPUMIPSState *regs)
bellard106ec872006-06-27 21:08:10 +00002909{
2910 struct sigframe *frame;
bellard579a97f2007-11-11 14:26:47 +00002911 abi_ulong frame_addr;
bellard106ec872006-06-27 21:08:10 +00002912 int i;
2913
bellard579a97f2007-11-11 14:26:47 +00002914 frame_addr = get_sigframe(ka, regs, sizeof(*frame));
2915 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
bellard106ec872006-06-27 21:08:10 +00002916 goto give_sigsegv;
2917
2918 install_sigtramp(frame->sf_code, TARGET_NR_sigreturn);
2919
Riku Voipio41ecc722014-04-23 11:01:00 +03002920 setup_sigcontext(regs, &frame->sf_sc);
bellard106ec872006-06-27 21:08:10 +00002921
2922 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
Riku Voipio0188fad2014-04-23 13:34:15 +03002923 __put_user(set->sig[i], &frame->sf_mask.sig[i]);
bellard106ec872006-06-27 21:08:10 +00002924 }
2925
2926 /*
2927 * Arguments to signal handler:
2928 *
2929 * a0 = signal number
2930 * a1 = 0 (should be cause)
2931 * a2 = pointer to struct sigcontext
2932 *
2933 * $25 and PC point to the signal handler, $29 points to the
2934 * struct sigframe.
2935 */
thsb5dc7732008-06-27 10:02:35 +00002936 regs->active_tc.gpr[ 4] = sig;
2937 regs->active_tc.gpr[ 5] = 0;
2938 regs->active_tc.gpr[ 6] = frame_addr + offsetof(struct sigframe, sf_sc);
2939 regs->active_tc.gpr[29] = frame_addr;
2940 regs->active_tc.gpr[31] = frame_addr + offsetof(struct sigframe, sf_code);
bellard106ec872006-06-27 21:08:10 +00002941 /* The original kernel code sets CP0_EPC to the handler
2942 * since it returns to userland using eret
2943 * we cannot do this here, and we must set PC directly */
thsb5dc7732008-06-27 10:02:35 +00002944 regs->active_tc.PC = regs->active_tc.gpr[25] = ka->_sa_handler;
Kwok Cheung Yeungea3164a2013-05-17 14:51:20 -07002945 mips_set_hflags_isa_mode_from_pc(regs);
bellard579a97f2007-11-11 14:26:47 +00002946 unlock_user_struct(frame, frame_addr, 1);
bellard106ec872006-06-27 21:08:10 +00002947 return;
2948
2949give_sigsegv:
2950 force_sig(TARGET_SIGSEGV/*, current*/);
bellard106ec872006-06-27 21:08:10 +00002951}
2952
Andreas Färber05390242012-02-25 03:37:53 +01002953long do_sigreturn(CPUMIPSState *regs)
bellard106ec872006-06-27 21:08:10 +00002954{
ths388bb212007-05-13 13:58:00 +00002955 struct sigframe *frame;
bellard579a97f2007-11-11 14:26:47 +00002956 abi_ulong frame_addr;
ths388bb212007-05-13 13:58:00 +00002957 sigset_t blocked;
Anthony Liguoric227f092009-10-01 16:12:16 -05002958 target_sigset_t target_set;
ths388bb212007-05-13 13:58:00 +00002959 int i;
bellard106ec872006-06-27 21:08:10 +00002960
2961#if defined(DEBUG_SIGNAL)
ths388bb212007-05-13 13:58:00 +00002962 fprintf(stderr, "do_sigreturn\n");
bellard106ec872006-06-27 21:08:10 +00002963#endif
thsb5dc7732008-06-27 10:02:35 +00002964 frame_addr = regs->active_tc.gpr[29];
bellard579a97f2007-11-11 14:26:47 +00002965 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
bellard106ec872006-06-27 21:08:10 +00002966 goto badframe;
2967
ths388bb212007-05-13 13:58:00 +00002968 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
Riku Voipiof5f601a2014-04-23 13:00:17 +03002969 __get_user(target_set.sig[i], &frame->sf_mask.sig[i]);
ths388bb212007-05-13 13:58:00 +00002970 }
bellard106ec872006-06-27 21:08:10 +00002971
ths388bb212007-05-13 13:58:00 +00002972 target_to_host_sigset_internal(&blocked, &target_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00002973 do_sigprocmask(SIG_SETMASK, &blocked, NULL);
bellard106ec872006-06-27 21:08:10 +00002974
Riku Voipio016d2e12014-04-23 11:19:48 +03002975 restore_sigcontext(regs, &frame->sf_sc);
bellard106ec872006-06-27 21:08:10 +00002976
2977#if 0
ths388bb212007-05-13 13:58:00 +00002978 /*
2979 * Don't let your children do this ...
2980 */
2981 __asm__ __volatile__(
bellard106ec872006-06-27 21:08:10 +00002982 "move\t$29, %0\n\t"
2983 "j\tsyscall_exit"
2984 :/* no outputs */
2985 :"r" (&regs));
ths388bb212007-05-13 13:58:00 +00002986 /* Unreached */
bellard106ec872006-06-27 21:08:10 +00002987#endif
ths3b46e622007-09-17 08:09:54 +00002988
thsb5dc7732008-06-27 10:02:35 +00002989 regs->active_tc.PC = regs->CP0_EPC;
Kwok Cheung Yeungea3164a2013-05-17 14:51:20 -07002990 mips_set_hflags_isa_mode_from_pc(regs);
ths388bb212007-05-13 13:58:00 +00002991 /* I am not sure this is right, but it seems to work
bellard106ec872006-06-27 21:08:10 +00002992 * maybe a problem with nested signals ? */
2993 regs->CP0_EPC = 0;
pbrook0b1bcb02009-04-21 01:41:10 +00002994 return -TARGET_QEMU_ESIGRETURN;
bellard106ec872006-06-27 21:08:10 +00002995
2996badframe:
ths388bb212007-05-13 13:58:00 +00002997 force_sig(TARGET_SIGSEGV/*, current*/);
2998 return 0;
bellard106ec872006-06-27 21:08:10 +00002999}
Richard Hendersonff970902013-02-10 10:30:42 -08003000# endif /* O32 */
bellard106ec872006-06-27 21:08:10 +00003001
pbrook624f7972008-05-31 16:11:38 +00003002static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05003003 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01003004 target_sigset_t *set, CPUMIPSState *env)
bellard106ec872006-06-27 21:08:10 +00003005{
pbrook0b1bcb02009-04-21 01:41:10 +00003006 struct target_rt_sigframe *frame;
3007 abi_ulong frame_addr;
3008 int i;
3009
3010 frame_addr = get_sigframe(ka, env, sizeof(*frame));
3011 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
3012 goto give_sigsegv;
3013
3014 install_sigtramp(frame->rs_code, TARGET_NR_rt_sigreturn);
3015
3016 copy_siginfo_to_user(&frame->rs_info, info);
3017
Aurelien Jarno60e99242010-03-29 02:12:51 +02003018 __put_user(0, &frame->rs_uc.tuc_flags);
3019 __put_user(0, &frame->rs_uc.tuc_link);
3020 __put_user(target_sigaltstack_used.ss_sp, &frame->rs_uc.tuc_stack.ss_sp);
3021 __put_user(target_sigaltstack_used.ss_size, &frame->rs_uc.tuc_stack.ss_size);
pbrook0b1bcb02009-04-21 01:41:10 +00003022 __put_user(sas_ss_flags(get_sp_from_cpustate(env)),
Aurelien Jarno60e99242010-03-29 02:12:51 +02003023 &frame->rs_uc.tuc_stack.ss_flags);
pbrook0b1bcb02009-04-21 01:41:10 +00003024
Aurelien Jarno60e99242010-03-29 02:12:51 +02003025 setup_sigcontext(env, &frame->rs_uc.tuc_mcontext);
pbrook0b1bcb02009-04-21 01:41:10 +00003026
3027 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
Aurelien Jarno60e99242010-03-29 02:12:51 +02003028 __put_user(set->sig[i], &frame->rs_uc.tuc_sigmask.sig[i]);
pbrook0b1bcb02009-04-21 01:41:10 +00003029 }
3030
3031 /*
3032 * Arguments to signal handler:
3033 *
3034 * a0 = signal number
Richard W.M. Jones02d2bd52012-07-05 03:32:44 +00003035 * a1 = pointer to siginfo_t
pbrook0b1bcb02009-04-21 01:41:10 +00003036 * a2 = pointer to struct ucontext
3037 *
3038 * $25 and PC point to the signal handler, $29 points to the
3039 * struct sigframe.
3040 */
3041 env->active_tc.gpr[ 4] = sig;
3042 env->active_tc.gpr[ 5] = frame_addr
3043 + offsetof(struct target_rt_sigframe, rs_info);
3044 env->active_tc.gpr[ 6] = frame_addr
3045 + offsetof(struct target_rt_sigframe, rs_uc);
3046 env->active_tc.gpr[29] = frame_addr;
3047 env->active_tc.gpr[31] = frame_addr
3048 + offsetof(struct target_rt_sigframe, rs_code);
3049 /* The original kernel code sets CP0_EPC to the handler
3050 * since it returns to userland using eret
3051 * we cannot do this here, and we must set PC directly */
3052 env->active_tc.PC = env->active_tc.gpr[25] = ka->_sa_handler;
Kwok Cheung Yeungea3164a2013-05-17 14:51:20 -07003053 mips_set_hflags_isa_mode_from_pc(env);
pbrook0b1bcb02009-04-21 01:41:10 +00003054 unlock_user_struct(frame, frame_addr, 1);
3055 return;
3056
3057give_sigsegv:
3058 unlock_user_struct(frame, frame_addr, 1);
3059 force_sig(TARGET_SIGSEGV/*, current*/);
bellard106ec872006-06-27 21:08:10 +00003060}
3061
Andreas Färber05390242012-02-25 03:37:53 +01003062long do_rt_sigreturn(CPUMIPSState *env)
bellard106ec872006-06-27 21:08:10 +00003063{
pbrook0b1bcb02009-04-21 01:41:10 +00003064 struct target_rt_sigframe *frame;
3065 abi_ulong frame_addr;
3066 sigset_t blocked;
3067
3068#if defined(DEBUG_SIGNAL)
3069 fprintf(stderr, "do_rt_sigreturn\n");
3070#endif
3071 frame_addr = env->active_tc.gpr[29];
3072 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
3073 goto badframe;
3074
Aurelien Jarno60e99242010-03-29 02:12:51 +02003075 target_to_host_sigset(&blocked, &frame->rs_uc.tuc_sigmask);
Alex Barcelo1c275922014-03-14 14:36:55 +00003076 do_sigprocmask(SIG_SETMASK, &blocked, NULL);
pbrook0b1bcb02009-04-21 01:41:10 +00003077
Riku Voipio016d2e12014-04-23 11:19:48 +03003078 restore_sigcontext(env, &frame->rs_uc.tuc_mcontext);
pbrook0b1bcb02009-04-21 01:41:10 +00003079
3080 if (do_sigaltstack(frame_addr +
Aurelien Jarno60e99242010-03-29 02:12:51 +02003081 offsetof(struct target_rt_sigframe, rs_uc.tuc_stack),
pbrook0b1bcb02009-04-21 01:41:10 +00003082 0, get_sp_from_cpustate(env)) == -EFAULT)
3083 goto badframe;
3084
3085 env->active_tc.PC = env->CP0_EPC;
Kwok Cheung Yeungea3164a2013-05-17 14:51:20 -07003086 mips_set_hflags_isa_mode_from_pc(env);
pbrook0b1bcb02009-04-21 01:41:10 +00003087 /* I am not sure this is right, but it seems to work
3088 * maybe a problem with nested signals ? */
3089 env->CP0_EPC = 0;
3090 return -TARGET_QEMU_ESIGRETURN;
3091
3092badframe:
3093 force_sig(TARGET_SIGSEGV/*, current*/);
3094 return 0;
bellard106ec872006-06-27 21:08:10 +00003095}
bellard6d5e2162004-09-30 22:04:13 +00003096
thsc3b5bc82007-12-02 06:31:25 +00003097#elif defined(TARGET_SH4)
3098
3099/*
3100 * code and data structures from linux kernel:
3101 * include/asm-sh/sigcontext.h
3102 * arch/sh/kernel/signal.c
3103 */
3104
3105struct target_sigcontext {
3106 target_ulong oldmask;
3107
3108 /* CPU registers */
3109 target_ulong sc_gregs[16];
3110 target_ulong sc_pc;
3111 target_ulong sc_pr;
3112 target_ulong sc_sr;
3113 target_ulong sc_gbr;
3114 target_ulong sc_mach;
3115 target_ulong sc_macl;
3116
3117 /* FPU registers */
3118 target_ulong sc_fpregs[16];
3119 target_ulong sc_xfpregs[16];
3120 unsigned int sc_fpscr;
3121 unsigned int sc_fpul;
3122 unsigned int sc_ownedfp;
3123};
3124
3125struct target_sigframe
3126{
3127 struct target_sigcontext sc;
3128 target_ulong extramask[TARGET_NSIG_WORDS-1];
3129 uint16_t retcode[3];
3130};
3131
3132
3133struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02003134 target_ulong tuc_flags;
3135 struct target_ucontext *tuc_link;
3136 target_stack_t tuc_stack;
3137 struct target_sigcontext tuc_mcontext;
3138 target_sigset_t tuc_sigmask; /* mask last for extensibility */
thsc3b5bc82007-12-02 06:31:25 +00003139};
3140
3141struct target_rt_sigframe
3142{
3143 struct target_siginfo info;
3144 struct target_ucontext uc;
3145 uint16_t retcode[3];
3146};
3147
3148
3149#define MOVW(n) (0x9300|((n)-2)) /* Move mem word at PC+n to R3 */
3150#define TRAP_NOARG 0xc310 /* Syscall w/no args (NR in R3) SH3/4 */
3151
pbrook624f7972008-05-31 16:11:38 +00003152static abi_ulong get_sigframe(struct target_sigaction *ka,
thsc3b5bc82007-12-02 06:31:25 +00003153 unsigned long sp, size_t frame_size)
3154{
pbrook624f7972008-05-31 16:11:38 +00003155 if ((ka->sa_flags & TARGET_SA_ONSTACK) && (sas_ss_flags(sp) == 0)) {
thsc3b5bc82007-12-02 06:31:25 +00003156 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
3157 }
3158
3159 return (sp - frame_size) & -8ul;
3160}
3161
Riku Voipio41ecc722014-04-23 11:01:00 +03003162static void setup_sigcontext(struct target_sigcontext *sc,
Andreas Färber05390242012-02-25 03:37:53 +01003163 CPUSH4State *regs, unsigned long mask)
thsc3b5bc82007-12-02 06:31:25 +00003164{
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003165 int i;
thsc3b5bc82007-12-02 06:31:25 +00003166
Riku Voipio1d8b5122014-04-23 10:26:05 +03003167#define COPY(x) __put_user(regs->x, &sc->sc_##x)
thsc3b5bc82007-12-02 06:31:25 +00003168 COPY(gregs[0]); COPY(gregs[1]);
3169 COPY(gregs[2]); COPY(gregs[3]);
3170 COPY(gregs[4]); COPY(gregs[5]);
3171 COPY(gregs[6]); COPY(gregs[7]);
3172 COPY(gregs[8]); COPY(gregs[9]);
3173 COPY(gregs[10]); COPY(gregs[11]);
3174 COPY(gregs[12]); COPY(gregs[13]);
3175 COPY(gregs[14]); COPY(gregs[15]);
3176 COPY(gbr); COPY(mach);
3177 COPY(macl); COPY(pr);
3178 COPY(sr); COPY(pc);
3179#undef COPY
3180
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003181 for (i=0; i<16; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03003182 __put_user(regs->fregs[i], &sc->sc_fpregs[i]);
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003183 }
Riku Voipio1d8b5122014-04-23 10:26:05 +03003184 __put_user(regs->fpscr, &sc->sc_fpscr);
3185 __put_user(regs->fpul, &sc->sc_fpul);
thsc3b5bc82007-12-02 06:31:25 +00003186
3187 /* non-iBCS2 extensions.. */
Riku Voipio1d8b5122014-04-23 10:26:05 +03003188 __put_user(mask, &sc->oldmask);
thsc3b5bc82007-12-02 06:31:25 +00003189}
3190
Riku Voipio016d2e12014-04-23 11:19:48 +03003191static void restore_sigcontext(CPUSH4State *regs, struct target_sigcontext *sc,
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003192 target_ulong *r0_p)
thsc3b5bc82007-12-02 06:31:25 +00003193{
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003194 int i;
thsc3b5bc82007-12-02 06:31:25 +00003195
Riku Voipio1d8b5122014-04-23 10:26:05 +03003196#define COPY(x) __get_user(regs->x, &sc->sc_##x)
thsc3b5bc82007-12-02 06:31:25 +00003197 COPY(gregs[1]);
3198 COPY(gregs[2]); COPY(gregs[3]);
3199 COPY(gregs[4]); COPY(gregs[5]);
3200 COPY(gregs[6]); COPY(gregs[7]);
3201 COPY(gregs[8]); COPY(gregs[9]);
3202 COPY(gregs[10]); COPY(gregs[11]);
3203 COPY(gregs[12]); COPY(gregs[13]);
3204 COPY(gregs[14]); COPY(gregs[15]);
3205 COPY(gbr); COPY(mach);
3206 COPY(macl); COPY(pr);
3207 COPY(sr); COPY(pc);
3208#undef COPY
3209
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003210 for (i=0; i<16; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03003211 __get_user(regs->fregs[i], &sc->sc_fpregs[i]);
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003212 }
Riku Voipio1d8b5122014-04-23 10:26:05 +03003213 __get_user(regs->fpscr, &sc->sc_fpscr);
3214 __get_user(regs->fpul, &sc->sc_fpul);
thsc3b5bc82007-12-02 06:31:25 +00003215
3216 regs->tra = -1; /* disable syscall checks */
Riku Voipio1d8b5122014-04-23 10:26:05 +03003217 __get_user(*r0_p, &sc->sc_gregs[0]);
thsc3b5bc82007-12-02 06:31:25 +00003218}
3219
pbrook624f7972008-05-31 16:11:38 +00003220static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01003221 target_sigset_t *set, CPUSH4State *regs)
thsc3b5bc82007-12-02 06:31:25 +00003222{
3223 struct target_sigframe *frame;
3224 abi_ulong frame_addr;
3225 int i;
3226 int err = 0;
3227 int signal;
3228
3229 frame_addr = get_sigframe(ka, regs->gregs[15], sizeof(*frame));
3230 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
3231 goto give_sigsegv;
3232
3233 signal = current_exec_domain_sig(sig);
3234
Riku Voipio41ecc722014-04-23 11:01:00 +03003235 setup_sigcontext(&frame->sc, regs, set->sig[0]);
thsc3b5bc82007-12-02 06:31:25 +00003236
3237 for (i = 0; i < TARGET_NSIG_WORDS - 1; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03003238 __put_user(set->sig[i + 1], &frame->extramask[i]);
thsc3b5bc82007-12-02 06:31:25 +00003239 }
3240
3241 /* Set up to return from userspace. If provided, use a stub
3242 already in userspace. */
pbrook624f7972008-05-31 16:11:38 +00003243 if (ka->sa_flags & TARGET_SA_RESTORER) {
3244 regs->pr = (unsigned long) ka->sa_restorer;
thsc3b5bc82007-12-02 06:31:25 +00003245 } else {
3246 /* Generate return code (system call to sigreturn) */
Riku Voipio1d8b5122014-04-23 10:26:05 +03003247 __put_user(MOVW(2), &frame->retcode[0]);
3248 __put_user(TRAP_NOARG, &frame->retcode[1]);
3249 __put_user((TARGET_NR_sigreturn), &frame->retcode[2]);
thsc3b5bc82007-12-02 06:31:25 +00003250 regs->pr = (unsigned long) frame->retcode;
3251 }
3252
3253 if (err)
3254 goto give_sigsegv;
3255
3256 /* Set up registers for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003257 regs->gregs[15] = frame_addr;
thsc3b5bc82007-12-02 06:31:25 +00003258 regs->gregs[4] = signal; /* Arg for signal handler */
3259 regs->gregs[5] = 0;
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003260 regs->gregs[6] = frame_addr += offsetof(typeof(*frame), sc);
pbrook624f7972008-05-31 16:11:38 +00003261 regs->pc = (unsigned long) ka->_sa_handler;
thsc3b5bc82007-12-02 06:31:25 +00003262
3263 unlock_user_struct(frame, frame_addr, 1);
3264 return;
3265
3266give_sigsegv:
3267 unlock_user_struct(frame, frame_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02003268 force_sig(TARGET_SIGSEGV);
thsc3b5bc82007-12-02 06:31:25 +00003269}
3270
pbrook624f7972008-05-31 16:11:38 +00003271static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05003272 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01003273 target_sigset_t *set, CPUSH4State *regs)
thsc3b5bc82007-12-02 06:31:25 +00003274{
3275 struct target_rt_sigframe *frame;
3276 abi_ulong frame_addr;
3277 int i;
3278 int err = 0;
3279 int signal;
3280
3281 frame_addr = get_sigframe(ka, regs->gregs[15], sizeof(*frame));
3282 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
3283 goto give_sigsegv;
3284
3285 signal = current_exec_domain_sig(sig);
3286
Riku Voipiob0fd8d12014-04-23 10:46:13 +03003287 copy_siginfo_to_user(&frame->info, info);
thsc3b5bc82007-12-02 06:31:25 +00003288
3289 /* Create the ucontext. */
Riku Voipio1d8b5122014-04-23 10:26:05 +03003290 __put_user(0, &frame->uc.tuc_flags);
3291 __put_user(0, (unsigned long *)&frame->uc.tuc_link);
3292 __put_user((unsigned long)target_sigaltstack_used.ss_sp,
3293 &frame->uc.tuc_stack.ss_sp);
3294 __put_user(sas_ss_flags(regs->gregs[15]),
3295 &frame->uc.tuc_stack.ss_flags);
3296 __put_user(target_sigaltstack_used.ss_size,
3297 &frame->uc.tuc_stack.ss_size);
3298 setup_sigcontext(&frame->uc.tuc_mcontext,
thsc3b5bc82007-12-02 06:31:25 +00003299 regs, set->sig[0]);
3300 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03003301 __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
thsc3b5bc82007-12-02 06:31:25 +00003302 }
3303
3304 /* Set up to return from userspace. If provided, use a stub
3305 already in userspace. */
pbrook624f7972008-05-31 16:11:38 +00003306 if (ka->sa_flags & TARGET_SA_RESTORER) {
3307 regs->pr = (unsigned long) ka->sa_restorer;
thsc3b5bc82007-12-02 06:31:25 +00003308 } else {
3309 /* Generate return code (system call to sigreturn) */
Riku Voipio1d8b5122014-04-23 10:26:05 +03003310 __put_user(MOVW(2), &frame->retcode[0]);
3311 __put_user(TRAP_NOARG, &frame->retcode[1]);
3312 __put_user((TARGET_NR_rt_sigreturn), &frame->retcode[2]);
thsc3b5bc82007-12-02 06:31:25 +00003313 regs->pr = (unsigned long) frame->retcode;
3314 }
3315
3316 if (err)
3317 goto give_sigsegv;
3318
3319 /* Set up registers for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003320 regs->gregs[15] = frame_addr;
thsc3b5bc82007-12-02 06:31:25 +00003321 regs->gregs[4] = signal; /* Arg for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003322 regs->gregs[5] = frame_addr + offsetof(typeof(*frame), info);
3323 regs->gregs[6] = frame_addr + offsetof(typeof(*frame), uc);
pbrook624f7972008-05-31 16:11:38 +00003324 regs->pc = (unsigned long) ka->_sa_handler;
thsc3b5bc82007-12-02 06:31:25 +00003325
3326 unlock_user_struct(frame, frame_addr, 1);
3327 return;
3328
3329give_sigsegv:
3330 unlock_user_struct(frame, frame_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02003331 force_sig(TARGET_SIGSEGV);
thsc3b5bc82007-12-02 06:31:25 +00003332}
3333
Andreas Färber05390242012-02-25 03:37:53 +01003334long do_sigreturn(CPUSH4State *regs)
thsc3b5bc82007-12-02 06:31:25 +00003335{
3336 struct target_sigframe *frame;
3337 abi_ulong frame_addr;
3338 sigset_t blocked;
Anthony Liguoric227f092009-10-01 16:12:16 -05003339 target_sigset_t target_set;
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003340 target_ulong r0;
thsc3b5bc82007-12-02 06:31:25 +00003341 int i;
3342 int err = 0;
3343
3344#if defined(DEBUG_SIGNAL)
3345 fprintf(stderr, "do_sigreturn\n");
3346#endif
3347 frame_addr = regs->gregs[15];
3348 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
3349 goto badframe;
3350
Riku Voipio1d8b5122014-04-23 10:26:05 +03003351 __get_user(target_set.sig[0], &frame->sc.oldmask);
thsc3b5bc82007-12-02 06:31:25 +00003352 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03003353 __get_user(target_set.sig[i], &frame->extramask[i - 1]);
thsc3b5bc82007-12-02 06:31:25 +00003354 }
3355
3356 if (err)
3357 goto badframe;
3358
3359 target_to_host_sigset_internal(&blocked, &target_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00003360 do_sigprocmask(SIG_SETMASK, &blocked, NULL);
thsc3b5bc82007-12-02 06:31:25 +00003361
Riku Voipio016d2e12014-04-23 11:19:48 +03003362 restore_sigcontext(regs, &frame->sc, &r0);
thsc3b5bc82007-12-02 06:31:25 +00003363
3364 unlock_user_struct(frame, frame_addr, 0);
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003365 return r0;
thsc3b5bc82007-12-02 06:31:25 +00003366
3367badframe:
3368 unlock_user_struct(frame, frame_addr, 0);
3369 force_sig(TARGET_SIGSEGV);
3370 return 0;
3371}
3372
Andreas Färber05390242012-02-25 03:37:53 +01003373long do_rt_sigreturn(CPUSH4State *regs)
thsc3b5bc82007-12-02 06:31:25 +00003374{
3375 struct target_rt_sigframe *frame;
3376 abi_ulong frame_addr;
3377 sigset_t blocked;
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003378 target_ulong r0;
thsc3b5bc82007-12-02 06:31:25 +00003379
3380#if defined(DEBUG_SIGNAL)
3381 fprintf(stderr, "do_rt_sigreturn\n");
3382#endif
3383 frame_addr = regs->gregs[15];
3384 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
3385 goto badframe;
3386
Aurelien Jarno60e99242010-03-29 02:12:51 +02003387 target_to_host_sigset(&blocked, &frame->uc.tuc_sigmask);
Alex Barcelo1c275922014-03-14 14:36:55 +00003388 do_sigprocmask(SIG_SETMASK, &blocked, NULL);
thsc3b5bc82007-12-02 06:31:25 +00003389
Riku Voipio016d2e12014-04-23 11:19:48 +03003390 restore_sigcontext(regs, &frame->uc.tuc_mcontext, &r0);
thsc3b5bc82007-12-02 06:31:25 +00003391
3392 if (do_sigaltstack(frame_addr +
Aurelien Jarno60e99242010-03-29 02:12:51 +02003393 offsetof(struct target_rt_sigframe, uc.tuc_stack),
thsc3b5bc82007-12-02 06:31:25 +00003394 0, get_sp_from_cpustate(regs)) == -EFAULT)
3395 goto badframe;
3396
3397 unlock_user_struct(frame, frame_addr, 0);
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003398 return r0;
thsc3b5bc82007-12-02 06:31:25 +00003399
3400badframe:
3401 unlock_user_struct(frame, frame_addr, 0);
3402 force_sig(TARGET_SIGSEGV);
3403 return 0;
3404}
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003405#elif defined(TARGET_MICROBLAZE)
3406
3407struct target_sigcontext {
3408 struct target_pt_regs regs; /* needs to be first */
3409 uint32_t oldmask;
3410};
3411
Edgar E. Iglesiasb2178702010-07-23 09:30:37 +02003412struct target_stack_t {
3413 abi_ulong ss_sp;
3414 int ss_flags;
3415 unsigned int ss_size;
3416};
3417
3418struct target_ucontext {
Richard Hendersonf711df62010-11-22 14:57:52 -08003419 abi_ulong tuc_flags;
3420 abi_ulong tuc_link;
3421 struct target_stack_t tuc_stack;
3422 struct target_sigcontext tuc_mcontext;
3423 uint32_t tuc_extramask[TARGET_NSIG_WORDS - 1];
Edgar E. Iglesiasb2178702010-07-23 09:30:37 +02003424};
3425
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003426/* Signal frames. */
3427struct target_signal_frame {
Edgar E. Iglesiasb2178702010-07-23 09:30:37 +02003428 struct target_ucontext uc;
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003429 uint32_t extramask[TARGET_NSIG_WORDS - 1];
3430 uint32_t tramp[2];
3431};
3432
3433struct rt_signal_frame {
Richard W.M. Jones02d2bd52012-07-05 03:32:44 +00003434 siginfo_t info;
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003435 struct ucontext uc;
3436 uint32_t tramp[2];
3437};
3438
Andreas Färber05390242012-02-25 03:37:53 +01003439static void setup_sigcontext(struct target_sigcontext *sc, CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003440{
3441 __put_user(env->regs[0], &sc->regs.r0);
3442 __put_user(env->regs[1], &sc->regs.r1);
3443 __put_user(env->regs[2], &sc->regs.r2);
3444 __put_user(env->regs[3], &sc->regs.r3);
3445 __put_user(env->regs[4], &sc->regs.r4);
3446 __put_user(env->regs[5], &sc->regs.r5);
3447 __put_user(env->regs[6], &sc->regs.r6);
3448 __put_user(env->regs[7], &sc->regs.r7);
3449 __put_user(env->regs[8], &sc->regs.r8);
3450 __put_user(env->regs[9], &sc->regs.r9);
3451 __put_user(env->regs[10], &sc->regs.r10);
3452 __put_user(env->regs[11], &sc->regs.r11);
3453 __put_user(env->regs[12], &sc->regs.r12);
3454 __put_user(env->regs[13], &sc->regs.r13);
3455 __put_user(env->regs[14], &sc->regs.r14);
3456 __put_user(env->regs[15], &sc->regs.r15);
3457 __put_user(env->regs[16], &sc->regs.r16);
3458 __put_user(env->regs[17], &sc->regs.r17);
3459 __put_user(env->regs[18], &sc->regs.r18);
3460 __put_user(env->regs[19], &sc->regs.r19);
3461 __put_user(env->regs[20], &sc->regs.r20);
3462 __put_user(env->regs[21], &sc->regs.r21);
3463 __put_user(env->regs[22], &sc->regs.r22);
3464 __put_user(env->regs[23], &sc->regs.r23);
3465 __put_user(env->regs[24], &sc->regs.r24);
3466 __put_user(env->regs[25], &sc->regs.r25);
3467 __put_user(env->regs[26], &sc->regs.r26);
3468 __put_user(env->regs[27], &sc->regs.r27);
3469 __put_user(env->regs[28], &sc->regs.r28);
3470 __put_user(env->regs[29], &sc->regs.r29);
3471 __put_user(env->regs[30], &sc->regs.r30);
3472 __put_user(env->regs[31], &sc->regs.r31);
3473 __put_user(env->sregs[SR_PC], &sc->regs.pc);
3474}
3475
Andreas Färber05390242012-02-25 03:37:53 +01003476static void restore_sigcontext(struct target_sigcontext *sc, CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003477{
3478 __get_user(env->regs[0], &sc->regs.r0);
3479 __get_user(env->regs[1], &sc->regs.r1);
3480 __get_user(env->regs[2], &sc->regs.r2);
3481 __get_user(env->regs[3], &sc->regs.r3);
3482 __get_user(env->regs[4], &sc->regs.r4);
3483 __get_user(env->regs[5], &sc->regs.r5);
3484 __get_user(env->regs[6], &sc->regs.r6);
3485 __get_user(env->regs[7], &sc->regs.r7);
3486 __get_user(env->regs[8], &sc->regs.r8);
3487 __get_user(env->regs[9], &sc->regs.r9);
3488 __get_user(env->regs[10], &sc->regs.r10);
3489 __get_user(env->regs[11], &sc->regs.r11);
3490 __get_user(env->regs[12], &sc->regs.r12);
3491 __get_user(env->regs[13], &sc->regs.r13);
3492 __get_user(env->regs[14], &sc->regs.r14);
3493 __get_user(env->regs[15], &sc->regs.r15);
3494 __get_user(env->regs[16], &sc->regs.r16);
3495 __get_user(env->regs[17], &sc->regs.r17);
3496 __get_user(env->regs[18], &sc->regs.r18);
3497 __get_user(env->regs[19], &sc->regs.r19);
3498 __get_user(env->regs[20], &sc->regs.r20);
3499 __get_user(env->regs[21], &sc->regs.r21);
3500 __get_user(env->regs[22], &sc->regs.r22);
3501 __get_user(env->regs[23], &sc->regs.r23);
3502 __get_user(env->regs[24], &sc->regs.r24);
3503 __get_user(env->regs[25], &sc->regs.r25);
3504 __get_user(env->regs[26], &sc->regs.r26);
3505 __get_user(env->regs[27], &sc->regs.r27);
3506 __get_user(env->regs[28], &sc->regs.r28);
3507 __get_user(env->regs[29], &sc->regs.r29);
3508 __get_user(env->regs[30], &sc->regs.r30);
3509 __get_user(env->regs[31], &sc->regs.r31);
3510 __get_user(env->sregs[SR_PC], &sc->regs.pc);
3511}
3512
3513static abi_ulong get_sigframe(struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01003514 CPUMBState *env, int frame_size)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003515{
3516 abi_ulong sp = env->regs[1];
3517
3518 if ((ka->sa_flags & SA_ONSTACK) != 0 && !on_sig_stack(sp))
3519 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
3520
3521 return ((sp - frame_size) & -8UL);
3522}
3523
3524static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01003525 target_sigset_t *set, CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003526{
3527 struct target_signal_frame *frame;
3528 abi_ulong frame_addr;
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003529 int i;
3530
3531 frame_addr = get_sigframe(ka, env, sizeof *frame);
3532 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
3533 goto badframe;
3534
3535 /* Save the mask. */
Riku Voipio1d8b5122014-04-23 10:26:05 +03003536 __put_user(set->sig[0], &frame->uc.tuc_mcontext.oldmask);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003537
3538 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
Riku Voipio0188fad2014-04-23 13:34:15 +03003539 __put_user(set->sig[i], &frame->extramask[i - 1]);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003540 }
3541
Richard Hendersonf711df62010-11-22 14:57:52 -08003542 setup_sigcontext(&frame->uc.tuc_mcontext, env);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003543
3544 /* Set up to return from userspace. If provided, use a stub
3545 already in userspace. */
3546 /* minus 8 is offset to cater for "rtsd r15,8" offset */
3547 if (ka->sa_flags & TARGET_SA_RESTORER) {
3548 env->regs[15] = ((unsigned long)ka->sa_restorer)-8;
3549 } else {
3550 uint32_t t;
3551 /* Note, these encodings are _big endian_! */
3552 /* addi r12, r0, __NR_sigreturn */
3553 t = 0x31800000UL | TARGET_NR_sigreturn;
Riku Voipio1d8b5122014-04-23 10:26:05 +03003554 __put_user(t, frame->tramp + 0);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003555 /* brki r14, 0x8 */
3556 t = 0xb9cc0008UL;
Riku Voipio1d8b5122014-04-23 10:26:05 +03003557 __put_user(t, frame->tramp + 1);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003558
3559 /* Return from sighandler will jump to the tramp.
3560 Negative 8 offset because return is rtsd r15, 8 */
3561 env->regs[15] = ((unsigned long)frame->tramp) - 8;
3562 }
3563
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003564 /* Set up registers for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003565 env->regs[1] = frame_addr;
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003566 /* Signal handler args: */
3567 env->regs[5] = sig; /* Arg 0: signum */
Edgar E. Iglesias187b4e02010-07-15 15:32:51 +02003568 env->regs[6] = 0;
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003569 /* arg 1: sigcontext */
3570 env->regs[7] = frame_addr += offsetof(typeof(*frame), uc);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003571
3572 /* Offset of 4 to handle microblaze rtid r14, 0 */
3573 env->sregs[SR_PC] = (unsigned long)ka->_sa_handler;
3574
3575 unlock_user_struct(frame, frame_addr, 1);
3576 return;
3577 badframe:
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003578 force_sig(TARGET_SIGSEGV);
3579}
3580
3581static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05003582 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01003583 target_sigset_t *set, CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003584{
3585 fprintf(stderr, "Microblaze setup_rt_frame: not implemented\n");
3586}
3587
Andreas Färber05390242012-02-25 03:37:53 +01003588long do_sigreturn(CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003589{
3590 struct target_signal_frame *frame;
3591 abi_ulong frame_addr;
Anthony Liguoric227f092009-10-01 16:12:16 -05003592 target_sigset_t target_set;
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003593 sigset_t set;
3594 int i;
3595
3596 frame_addr = env->regs[R_SP];
3597 /* Make sure the guest isn't playing games. */
3598 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 1))
3599 goto badframe;
3600
3601 /* Restore blocked signals */
Riku Voipiof5f601a2014-04-23 13:00:17 +03003602 __get_user(target_set.sig[0], &frame->uc.tuc_mcontext.oldmask);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003603 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
Riku Voipiof5f601a2014-04-23 13:00:17 +03003604 __get_user(target_set.sig[i], &frame->extramask[i - 1]);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003605 }
3606 target_to_host_sigset_internal(&set, &target_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00003607 do_sigprocmask(SIG_SETMASK, &set, NULL);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003608
Richard Hendersonf711df62010-11-22 14:57:52 -08003609 restore_sigcontext(&frame->uc.tuc_mcontext, env);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003610 /* We got here through a sigreturn syscall, our path back is via an
3611 rtb insn so setup r14 for that. */
3612 env->regs[14] = env->sregs[SR_PC];
3613
3614 unlock_user_struct(frame, frame_addr, 0);
3615 return env->regs[10];
3616 badframe:
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003617 force_sig(TARGET_SIGSEGV);
3618}
3619
Andreas Färber05390242012-02-25 03:37:53 +01003620long do_rt_sigreturn(CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003621{
3622 fprintf(stderr, "Microblaze do_rt_sigreturn: not implemented\n");
3623 return -TARGET_ENOSYS;
3624}
3625
edgar_iglb6d3abd2008-02-28 11:29:27 +00003626#elif defined(TARGET_CRIS)
3627
3628struct target_sigcontext {
3629 struct target_pt_regs regs; /* needs to be first */
3630 uint32_t oldmask;
3631 uint32_t usp; /* usp before stacking this gunk on it */
3632};
3633
3634/* Signal frames. */
3635struct target_signal_frame {
3636 struct target_sigcontext sc;
3637 uint32_t extramask[TARGET_NSIG_WORDS - 1];
Stefan Weil8cfc1142014-02-01 09:41:09 +01003638 uint16_t retcode[4]; /* Trampoline code. */
edgar_iglb6d3abd2008-02-28 11:29:27 +00003639};
3640
3641struct rt_signal_frame {
Richard W.M. Jones02d2bd52012-07-05 03:32:44 +00003642 siginfo_t *pinfo;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003643 void *puc;
Richard W.M. Jones02d2bd52012-07-05 03:32:44 +00003644 siginfo_t info;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003645 struct ucontext uc;
Stefan Weil8cfc1142014-02-01 09:41:09 +01003646 uint16_t retcode[4]; /* Trampoline code. */
edgar_iglb6d3abd2008-02-28 11:29:27 +00003647};
3648
Andreas Färber05390242012-02-25 03:37:53 +01003649static void setup_sigcontext(struct target_sigcontext *sc, CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003650{
edgar_igl9664d922008-03-03 22:23:53 +00003651 __put_user(env->regs[0], &sc->regs.r0);
3652 __put_user(env->regs[1], &sc->regs.r1);
3653 __put_user(env->regs[2], &sc->regs.r2);
3654 __put_user(env->regs[3], &sc->regs.r3);
3655 __put_user(env->regs[4], &sc->regs.r4);
3656 __put_user(env->regs[5], &sc->regs.r5);
3657 __put_user(env->regs[6], &sc->regs.r6);
3658 __put_user(env->regs[7], &sc->regs.r7);
3659 __put_user(env->regs[8], &sc->regs.r8);
3660 __put_user(env->regs[9], &sc->regs.r9);
3661 __put_user(env->regs[10], &sc->regs.r10);
3662 __put_user(env->regs[11], &sc->regs.r11);
3663 __put_user(env->regs[12], &sc->regs.r12);
3664 __put_user(env->regs[13], &sc->regs.r13);
3665 __put_user(env->regs[14], &sc->usp);
3666 __put_user(env->regs[15], &sc->regs.acr);
3667 __put_user(env->pregs[PR_MOF], &sc->regs.mof);
3668 __put_user(env->pregs[PR_SRP], &sc->regs.srp);
3669 __put_user(env->pc, &sc->regs.erp);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003670}
edgar_igl9664d922008-03-03 22:23:53 +00003671
Andreas Färber05390242012-02-25 03:37:53 +01003672static void restore_sigcontext(struct target_sigcontext *sc, CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003673{
edgar_igl9664d922008-03-03 22:23:53 +00003674 __get_user(env->regs[0], &sc->regs.r0);
3675 __get_user(env->regs[1], &sc->regs.r1);
3676 __get_user(env->regs[2], &sc->regs.r2);
3677 __get_user(env->regs[3], &sc->regs.r3);
3678 __get_user(env->regs[4], &sc->regs.r4);
3679 __get_user(env->regs[5], &sc->regs.r5);
3680 __get_user(env->regs[6], &sc->regs.r6);
3681 __get_user(env->regs[7], &sc->regs.r7);
3682 __get_user(env->regs[8], &sc->regs.r8);
3683 __get_user(env->regs[9], &sc->regs.r9);
3684 __get_user(env->regs[10], &sc->regs.r10);
3685 __get_user(env->regs[11], &sc->regs.r11);
3686 __get_user(env->regs[12], &sc->regs.r12);
3687 __get_user(env->regs[13], &sc->regs.r13);
3688 __get_user(env->regs[14], &sc->usp);
3689 __get_user(env->regs[15], &sc->regs.acr);
3690 __get_user(env->pregs[PR_MOF], &sc->regs.mof);
3691 __get_user(env->pregs[PR_SRP], &sc->regs.srp);
3692 __get_user(env->pc, &sc->regs.erp);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003693}
3694
Andreas Färber05390242012-02-25 03:37:53 +01003695static abi_ulong get_sigframe(CPUCRISState *env, int framesize)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003696{
edgar_igl9664d922008-03-03 22:23:53 +00003697 abi_ulong sp;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003698 /* Align the stack downwards to 4. */
edgar_igl9664d922008-03-03 22:23:53 +00003699 sp = (env->regs[R_SP] & ~3);
3700 return sp - framesize;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003701}
3702
pbrook624f7972008-05-31 16:11:38 +00003703static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01003704 target_sigset_t *set, CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003705{
3706 struct target_signal_frame *frame;
edgar_igl9664d922008-03-03 22:23:53 +00003707 abi_ulong frame_addr;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003708 int i;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003709
edgar_igl9664d922008-03-03 22:23:53 +00003710 frame_addr = get_sigframe(env, sizeof *frame);
3711 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
edgar_iglb6d3abd2008-02-28 11:29:27 +00003712 goto badframe;
3713
3714 /*
3715 * The CRIS signal return trampoline. A real linux/CRIS kernel doesn't
3716 * use this trampoline anymore but it sets it up for GDB.
3717 * In QEMU, using the trampoline simplifies things a bit so we use it.
3718 *
3719 * This is movu.w __NR_sigreturn, r9; break 13;
3720 */
Riku Voipio1d8b5122014-04-23 10:26:05 +03003721 __put_user(0x9c5f, frame->retcode+0);
3722 __put_user(TARGET_NR_sigreturn,
3723 frame->retcode + 1);
3724 __put_user(0xe93d, frame->retcode + 2);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003725
3726 /* Save the mask. */
Riku Voipio1d8b5122014-04-23 10:26:05 +03003727 __put_user(set->sig[0], &frame->sc.oldmask);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003728
Riku Voipio0188fad2014-04-23 13:34:15 +03003729 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
3730 __put_user(set->sig[i], &frame->extramask[i - 1]);
3731 }
edgar_iglb6d3abd2008-02-28 11:29:27 +00003732
3733 setup_sigcontext(&frame->sc, env);
3734
3735 /* Move the stack and setup the arguments for the handler. */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003736 env->regs[R_SP] = frame_addr;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003737 env->regs[10] = sig;
pbrook624f7972008-05-31 16:11:38 +00003738 env->pc = (unsigned long) ka->_sa_handler;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003739 /* Link SRP so the guest returns through the trampoline. */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003740 env->pregs[PR_SRP] = frame_addr + offsetof(typeof(*frame), retcode);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003741
edgar_igl9664d922008-03-03 22:23:53 +00003742 unlock_user_struct(frame, frame_addr, 1);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003743 return;
3744 badframe:
edgar_iglb6d3abd2008-02-28 11:29:27 +00003745 force_sig(TARGET_SIGSEGV);
3746}
3747
pbrook624f7972008-05-31 16:11:38 +00003748static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05003749 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01003750 target_sigset_t *set, CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003751{
3752 fprintf(stderr, "CRIS setup_rt_frame: not implemented\n");
3753}
3754
Andreas Färber05390242012-02-25 03:37:53 +01003755long do_sigreturn(CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003756{
3757 struct target_signal_frame *frame;
edgar_igl9664d922008-03-03 22:23:53 +00003758 abi_ulong frame_addr;
Anthony Liguoric227f092009-10-01 16:12:16 -05003759 target_sigset_t target_set;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003760 sigset_t set;
3761 int i;
3762
edgar_igl9664d922008-03-03 22:23:53 +00003763 frame_addr = env->regs[R_SP];
edgar_iglb6d3abd2008-02-28 11:29:27 +00003764 /* Make sure the guest isn't playing games. */
edgar_igl9664d922008-03-03 22:23:53 +00003765 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 1))
edgar_iglb6d3abd2008-02-28 11:29:27 +00003766 goto badframe;
3767
3768 /* Restore blocked signals */
Riku Voipiof5f601a2014-04-23 13:00:17 +03003769 __get_user(target_set.sig[0], &frame->sc.oldmask);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003770 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
Riku Voipiof5f601a2014-04-23 13:00:17 +03003771 __get_user(target_set.sig[i], &frame->extramask[i - 1]);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003772 }
3773 target_to_host_sigset_internal(&set, &target_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00003774 do_sigprocmask(SIG_SETMASK, &set, NULL);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003775
3776 restore_sigcontext(&frame->sc, env);
edgar_igl9664d922008-03-03 22:23:53 +00003777 unlock_user_struct(frame, frame_addr, 0);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003778 return env->regs[10];
3779 badframe:
edgar_iglb6d3abd2008-02-28 11:29:27 +00003780 force_sig(TARGET_SIGSEGV);
3781}
3782
Andreas Färber05390242012-02-25 03:37:53 +01003783long do_rt_sigreturn(CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003784{
3785 fprintf(stderr, "CRIS do_rt_sigreturn: not implemented\n");
3786 return -TARGET_ENOSYS;
3787}
thsc3b5bc82007-12-02 06:31:25 +00003788
Jia Liud9627832012-07-20 15:50:52 +08003789#elif defined(TARGET_OPENRISC)
3790
3791struct target_sigcontext {
3792 struct target_pt_regs regs;
3793 abi_ulong oldmask;
3794 abi_ulong usp;
3795};
3796
3797struct target_ucontext {
3798 abi_ulong tuc_flags;
3799 abi_ulong tuc_link;
3800 target_stack_t tuc_stack;
3801 struct target_sigcontext tuc_mcontext;
3802 target_sigset_t tuc_sigmask; /* mask last for extensibility */
3803};
3804
3805struct target_rt_sigframe {
3806 abi_ulong pinfo;
3807 uint64_t puc;
3808 struct target_siginfo info;
3809 struct target_sigcontext sc;
3810 struct target_ucontext uc;
3811 unsigned char retcode[16]; /* trampoline code */
3812};
3813
3814/* This is the asm-generic/ucontext.h version */
3815#if 0
3816static int restore_sigcontext(CPUOpenRISCState *regs,
3817 struct target_sigcontext *sc)
3818{
3819 unsigned int err = 0;
3820 unsigned long old_usp;
3821
3822 /* Alwys make any pending restarted system call return -EINTR */
3823 current_thread_info()->restart_block.fn = do_no_restart_syscall;
3824
3825 /* restore the regs from &sc->regs (same as sc, since regs is first)
3826 * (sc is already checked for VERIFY_READ since the sigframe was
3827 * checked in sys_sigreturn previously)
3828 */
3829
3830 if (copy_from_user(regs, &sc, sizeof(struct target_pt_regs))) {
3831 goto badframe;
3832 }
3833
3834 /* make sure the U-flag is set so user-mode cannot fool us */
3835
3836 regs->sr &= ~SR_SM;
3837
3838 /* restore the old USP as it was before we stacked the sc etc.
3839 * (we cannot just pop the sigcontext since we aligned the sp and
3840 * stuff after pushing it)
3841 */
3842
Riku Voipio1d8b5122014-04-23 10:26:05 +03003843 __get_user(old_usp, &sc->usp);
Jia Liud9627832012-07-20 15:50:52 +08003844 phx_signal("old_usp 0x%lx", old_usp);
3845
3846 __PHX__ REALLY /* ??? */
3847 wrusp(old_usp);
3848 regs->gpr[1] = old_usp;
3849
3850 /* TODO: the other ports use regs->orig_XX to disable syscall checks
3851 * after this completes, but we don't use that mechanism. maybe we can
3852 * use it now ?
3853 */
3854
3855 return err;
3856
3857badframe:
3858 return 1;
3859}
3860#endif
3861
3862/* Set up a signal frame. */
3863
Riku Voipio41ecc722014-04-23 11:01:00 +03003864static void setup_sigcontext(struct target_sigcontext *sc,
Jia Liud9627832012-07-20 15:50:52 +08003865 CPUOpenRISCState *regs,
3866 unsigned long mask)
3867{
Jia Liud9627832012-07-20 15:50:52 +08003868 unsigned long usp = regs->gpr[1];
3869
3870 /* copy the regs. they are first in sc so we can use sc directly */
3871
Riku Voipio1d8b5122014-04-23 10:26:05 +03003872 /*copy_to_user(&sc, regs, sizeof(struct target_pt_regs));*/
Jia Liud9627832012-07-20 15:50:52 +08003873
3874 /* Set the frametype to CRIS_FRAME_NORMAL for the execution of
3875 the signal handler. The frametype will be restored to its previous
3876 value in restore_sigcontext. */
3877 /*regs->frametype = CRIS_FRAME_NORMAL;*/
3878
3879 /* then some other stuff */
Riku Voipio1d8b5122014-04-23 10:26:05 +03003880 __put_user(mask, &sc->oldmask);
Riku Voipio41ecc722014-04-23 11:01:00 +03003881 __put_user(usp, &sc->usp);
Jia Liud9627832012-07-20 15:50:52 +08003882}
3883
3884static inline unsigned long align_sigframe(unsigned long sp)
3885{
3886 unsigned long i;
3887 i = sp & ~3UL;
3888 return i;
3889}
3890
3891static inline abi_ulong get_sigframe(struct target_sigaction *ka,
3892 CPUOpenRISCState *regs,
3893 size_t frame_size)
3894{
3895 unsigned long sp = regs->gpr[1];
3896 int onsigstack = on_sig_stack(sp);
3897
3898 /* redzone */
3899 /* This is the X/Open sanctioned signal stack switching. */
3900 if ((ka->sa_flags & SA_ONSTACK) != 0 && !onsigstack) {
3901 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
3902 }
3903
3904 sp = align_sigframe(sp - frame_size);
3905
3906 /*
3907 * If we are on the alternate signal stack and would overflow it, don't.
3908 * Return an always-bogus address instead so we will die with SIGSEGV.
3909 */
3910
3911 if (onsigstack && !likely(on_sig_stack(sp))) {
3912 return -1L;
3913 }
3914
3915 return sp;
3916}
3917
3918static void setup_frame(int sig, struct target_sigaction *ka,
3919 target_sigset_t *set, CPUOpenRISCState *env)
3920{
3921 qemu_log("Not implement.\n");
3922}
3923
3924static void setup_rt_frame(int sig, struct target_sigaction *ka,
3925 target_siginfo_t *info,
3926 target_sigset_t *set, CPUOpenRISCState *env)
3927{
3928 int err = 0;
3929 abi_ulong frame_addr;
3930 unsigned long return_ip;
3931 struct target_rt_sigframe *frame;
3932 abi_ulong info_addr, uc_addr;
3933
Jia Liud9627832012-07-20 15:50:52 +08003934 frame_addr = get_sigframe(ka, env, sizeof(*frame));
3935 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
3936 goto give_sigsegv;
3937 }
3938
3939 info_addr = frame_addr + offsetof(struct target_rt_sigframe, info);
Riku Voipio1d8b5122014-04-23 10:26:05 +03003940 __put_user(info_addr, &frame->pinfo);
Jia Liud9627832012-07-20 15:50:52 +08003941 uc_addr = frame_addr + offsetof(struct target_rt_sigframe, uc);
Riku Voipio1d8b5122014-04-23 10:26:05 +03003942 __put_user(uc_addr, &frame->puc);
Jia Liud9627832012-07-20 15:50:52 +08003943
3944 if (ka->sa_flags & SA_SIGINFO) {
Riku Voipiob0fd8d12014-04-23 10:46:13 +03003945 copy_siginfo_to_user(&frame->info, info);
Jia Liud9627832012-07-20 15:50:52 +08003946 }
3947
3948 /*err |= __clear_user(&frame->uc, offsetof(struct ucontext, uc_mcontext));*/
Riku Voipio1d8b5122014-04-23 10:26:05 +03003949 __put_user(0, &frame->uc.tuc_flags);
3950 __put_user(0, &frame->uc.tuc_link);
3951 __put_user(target_sigaltstack_used.ss_sp,
3952 &frame->uc.tuc_stack.ss_sp);
3953 __put_user(sas_ss_flags(env->gpr[1]), &frame->uc.tuc_stack.ss_flags);
3954 __put_user(target_sigaltstack_used.ss_size,
3955 &frame->uc.tuc_stack.ss_size);
Riku Voipio41ecc722014-04-23 11:01:00 +03003956 setup_sigcontext(&frame->sc, env, set->sig[0]);
Jia Liud9627832012-07-20 15:50:52 +08003957
3958 /*err |= copy_to_user(frame->uc.tuc_sigmask, set, sizeof(*set));*/
3959
Jia Liud9627832012-07-20 15:50:52 +08003960 /* trampoline - the desired return ip is the retcode itself */
3961 return_ip = (unsigned long)&frame->retcode;
3962 /* This is l.ori r11,r0,__NR_sigreturn, l.sys 1 */
Riku Voipio1d8b5122014-04-23 10:26:05 +03003963 __put_user(0xa960, (short *)(frame->retcode + 0));
3964 __put_user(TARGET_NR_rt_sigreturn, (short *)(frame->retcode + 2));
3965 __put_user(0x20000001, (unsigned long *)(frame->retcode + 4));
3966 __put_user(0x15000000, (unsigned long *)(frame->retcode + 8));
Jia Liud9627832012-07-20 15:50:52 +08003967
3968 if (err) {
3969 goto give_sigsegv;
3970 }
3971
3972 /* TODO what is the current->exec_domain stuff and invmap ? */
3973
3974 /* Set up registers for signal handler */
3975 env->pc = (unsigned long)ka->_sa_handler; /* what we enter NOW */
3976 env->gpr[9] = (unsigned long)return_ip; /* what we enter LATER */
3977 env->gpr[3] = (unsigned long)sig; /* arg 1: signo */
3978 env->gpr[4] = (unsigned long)&frame->info; /* arg 2: (siginfo_t*) */
3979 env->gpr[5] = (unsigned long)&frame->uc; /* arg 3: ucontext */
3980
3981 /* actually move the usp to reflect the stacked frame */
3982 env->gpr[1] = (unsigned long)frame;
3983
3984 return;
3985
3986give_sigsegv:
3987 unlock_user_struct(frame, frame_addr, 1);
3988 if (sig == TARGET_SIGSEGV) {
3989 ka->_sa_handler = TARGET_SIG_DFL;
3990 }
3991 force_sig(TARGET_SIGSEGV);
3992}
3993
3994long do_sigreturn(CPUOpenRISCState *env)
3995{
3996
3997 qemu_log("do_sigreturn: not implemented\n");
3998 return -TARGET_ENOSYS;
3999}
4000
4001long do_rt_sigreturn(CPUOpenRISCState *env)
4002{
4003 qemu_log("do_rt_sigreturn: not implemented\n");
4004 return -TARGET_ENOSYS;
4005}
4006/* TARGET_OPENRISC */
4007
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004008#elif defined(TARGET_S390X)
4009
4010#define __NUM_GPRS 16
4011#define __NUM_FPRS 16
4012#define __NUM_ACRS 16
4013
4014#define S390_SYSCALL_SIZE 2
4015#define __SIGNAL_FRAMESIZE 160 /* FIXME: 31-bit mode -> 96 */
4016
4017#define _SIGCONTEXT_NSIG 64
4018#define _SIGCONTEXT_NSIG_BPW 64 /* FIXME: 31-bit mode -> 32 */
4019#define _SIGCONTEXT_NSIG_WORDS (_SIGCONTEXT_NSIG / _SIGCONTEXT_NSIG_BPW)
4020#define _SIGMASK_COPY_SIZE (sizeof(unsigned long)*_SIGCONTEXT_NSIG_WORDS)
4021#define PSW_ADDR_AMODE 0x0000000000000000UL /* 0x80000000UL for 31-bit */
4022#define S390_SYSCALL_OPCODE ((uint16_t)0x0a00)
4023
4024typedef struct {
4025 target_psw_t psw;
4026 target_ulong gprs[__NUM_GPRS];
4027 unsigned int acrs[__NUM_ACRS];
4028} target_s390_regs_common;
4029
4030typedef struct {
4031 unsigned int fpc;
4032 double fprs[__NUM_FPRS];
4033} target_s390_fp_regs;
4034
4035typedef struct {
4036 target_s390_regs_common regs;
4037 target_s390_fp_regs fpregs;
4038} target_sigregs;
4039
4040struct target_sigcontext {
4041 target_ulong oldmask[_SIGCONTEXT_NSIG_WORDS];
4042 target_sigregs *sregs;
4043};
4044
4045typedef struct {
4046 uint8_t callee_used_stack[__SIGNAL_FRAMESIZE];
4047 struct target_sigcontext sc;
4048 target_sigregs sregs;
4049 int signo;
4050 uint8_t retcode[S390_SYSCALL_SIZE];
4051} sigframe;
4052
4053struct target_ucontext {
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004054 target_ulong tuc_flags;
4055 struct target_ucontext *tuc_link;
4056 target_stack_t tuc_stack;
4057 target_sigregs tuc_mcontext;
4058 target_sigset_t tuc_sigmask; /* mask last for extensibility */
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004059};
4060
4061typedef struct {
4062 uint8_t callee_used_stack[__SIGNAL_FRAMESIZE];
4063 uint8_t retcode[S390_SYSCALL_SIZE];
4064 struct target_siginfo info;
4065 struct target_ucontext uc;
4066} rt_sigframe;
4067
4068static inline abi_ulong
Andreas Färber05390242012-02-25 03:37:53 +01004069get_sigframe(struct target_sigaction *ka, CPUS390XState *env, size_t frame_size)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004070{
4071 abi_ulong sp;
4072
4073 /* Default to using normal stack */
4074 sp = env->regs[15];
4075
4076 /* This is the X/Open sanctioned signal stack switching. */
4077 if (ka->sa_flags & TARGET_SA_ONSTACK) {
4078 if (!sas_ss_flags(sp)) {
4079 sp = target_sigaltstack_used.ss_sp +
4080 target_sigaltstack_used.ss_size;
4081 }
4082 }
4083
4084 /* This is the legacy signal stack switching. */
4085 else if (/* FIXME !user_mode(regs) */ 0 &&
4086 !(ka->sa_flags & TARGET_SA_RESTORER) &&
4087 ka->sa_restorer) {
4088 sp = (abi_ulong) ka->sa_restorer;
4089 }
4090
4091 return (sp - frame_size) & -8ul;
4092}
4093
Andreas Färber05390242012-02-25 03:37:53 +01004094static void save_sigregs(CPUS390XState *env, target_sigregs *sregs)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004095{
4096 int i;
4097 //save_access_regs(current->thread.acrs); FIXME
4098
4099 /* Copy a 'clean' PSW mask to the user to avoid leaking
4100 information about whether PER is currently on. */
4101 __put_user(env->psw.mask, &sregs->regs.psw.mask);
4102 __put_user(env->psw.addr, &sregs->regs.psw.addr);
4103 for (i = 0; i < 16; i++) {
4104 __put_user(env->regs[i], &sregs->regs.gprs[i]);
4105 }
4106 for (i = 0; i < 16; i++) {
4107 __put_user(env->aregs[i], &sregs->regs.acrs[i]);
4108 }
4109 /*
4110 * We have to store the fp registers to current->thread.fp_regs
4111 * to merge them with the emulated registers.
4112 */
4113 //save_fp_regs(&current->thread.fp_regs); FIXME
4114 for (i = 0; i < 16; i++) {
4115 __put_user(env->fregs[i].ll, &sregs->fpregs.fprs[i]);
4116 }
4117}
4118
4119static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01004120 target_sigset_t *set, CPUS390XState *env)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004121{
4122 sigframe *frame;
4123 abi_ulong frame_addr;
4124
4125 frame_addr = get_sigframe(ka, env, sizeof(*frame));
4126 qemu_log("%s: frame_addr 0x%llx\n", __FUNCTION__,
4127 (unsigned long long)frame_addr);
4128 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
4129 goto give_sigsegv;
4130 }
4131
4132 qemu_log("%s: 1\n", __FUNCTION__);
Riku Voipio0188fad2014-04-23 13:34:15 +03004133 __put_user(set->sig[0], &frame->sc.oldmask[0]);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004134
4135 save_sigregs(env, &frame->sregs);
4136
4137 __put_user((abi_ulong)(unsigned long)&frame->sregs,
4138 (abi_ulong *)&frame->sc.sregs);
4139
4140 /* Set up to return from userspace. If provided, use a stub
4141 already in userspace. */
4142 if (ka->sa_flags & TARGET_SA_RESTORER) {
4143 env->regs[14] = (unsigned long)
4144 ka->sa_restorer | PSW_ADDR_AMODE;
4145 } else {
4146 env->regs[14] = (unsigned long)
4147 frame->retcode | PSW_ADDR_AMODE;
Riku Voipio0188fad2014-04-23 13:34:15 +03004148 __put_user(S390_SYSCALL_OPCODE | TARGET_NR_sigreturn,
4149 (uint16_t *)(frame->retcode));
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004150 }
4151
4152 /* Set up backchain. */
Riku Voipio0188fad2014-04-23 13:34:15 +03004153 __put_user(env->regs[15], (abi_ulong *) frame);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004154
4155 /* Set up registers for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02004156 env->regs[15] = frame_addr;
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004157 env->psw.addr = (target_ulong) ka->_sa_handler | PSW_ADDR_AMODE;
4158
4159 env->regs[2] = sig; //map_signal(sig);
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02004160 env->regs[3] = frame_addr += offsetof(typeof(*frame), sc);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004161
4162 /* We forgot to include these in the sigcontext.
4163 To avoid breaking binary compatibility, they are passed as args. */
4164 env->regs[4] = 0; // FIXME: no clue... current->thread.trap_no;
4165 env->regs[5] = 0; // FIXME: no clue... current->thread.prot_addr;
4166
4167 /* Place signal number on stack to allow backtrace from handler. */
Riku Voipio0188fad2014-04-23 13:34:15 +03004168 __put_user(env->regs[2], (int *) &frame->signo);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004169 unlock_user_struct(frame, frame_addr, 1);
4170 return;
4171
4172give_sigsegv:
4173 qemu_log("%s: give_sigsegv\n", __FUNCTION__);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004174 force_sig(TARGET_SIGSEGV);
4175}
4176
4177static void setup_rt_frame(int sig, struct target_sigaction *ka,
4178 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01004179 target_sigset_t *set, CPUS390XState *env)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004180{
4181 int i;
4182 rt_sigframe *frame;
4183 abi_ulong frame_addr;
4184
4185 frame_addr = get_sigframe(ka, env, sizeof *frame);
4186 qemu_log("%s: frame_addr 0x%llx\n", __FUNCTION__,
4187 (unsigned long long)frame_addr);
4188 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
4189 goto give_sigsegv;
4190 }
4191
4192 qemu_log("%s: 1\n", __FUNCTION__);
Riku Voipiob0fd8d12014-04-23 10:46:13 +03004193 copy_siginfo_to_user(&frame->info, info);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004194
4195 /* Create the ucontext. */
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004196 __put_user(0, &frame->uc.tuc_flags);
4197 __put_user((abi_ulong)0, (abi_ulong *)&frame->uc.tuc_link);
4198 __put_user(target_sigaltstack_used.ss_sp, &frame->uc.tuc_stack.ss_sp);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004199 __put_user(sas_ss_flags(get_sp_from_cpustate(env)),
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004200 &frame->uc.tuc_stack.ss_flags);
4201 __put_user(target_sigaltstack_used.ss_size, &frame->uc.tuc_stack.ss_size);
4202 save_sigregs(env, &frame->uc.tuc_mcontext);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004203 for (i = 0; i < TARGET_NSIG_WORDS; i++) {
4204 __put_user((abi_ulong)set->sig[i],
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004205 (abi_ulong *)&frame->uc.tuc_sigmask.sig[i]);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004206 }
4207
4208 /* Set up to return from userspace. If provided, use a stub
4209 already in userspace. */
4210 if (ka->sa_flags & TARGET_SA_RESTORER) {
4211 env->regs[14] = (unsigned long) ka->sa_restorer | PSW_ADDR_AMODE;
4212 } else {
4213 env->regs[14] = (unsigned long) frame->retcode | PSW_ADDR_AMODE;
Riku Voipio0188fad2014-04-23 13:34:15 +03004214 __put_user(S390_SYSCALL_OPCODE | TARGET_NR_rt_sigreturn,
4215 (uint16_t *)(frame->retcode));
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004216 }
4217
4218 /* Set up backchain. */
Riku Voipio0188fad2014-04-23 13:34:15 +03004219 __put_user(env->regs[15], (abi_ulong *) frame);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004220
4221 /* Set up registers for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02004222 env->regs[15] = frame_addr;
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004223 env->psw.addr = (target_ulong) ka->_sa_handler | PSW_ADDR_AMODE;
4224
4225 env->regs[2] = sig; //map_signal(sig);
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02004226 env->regs[3] = frame_addr + offsetof(typeof(*frame), info);
4227 env->regs[4] = frame_addr + offsetof(typeof(*frame), uc);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004228 return;
4229
4230give_sigsegv:
4231 qemu_log("%s: give_sigsegv\n", __FUNCTION__);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004232 force_sig(TARGET_SIGSEGV);
4233}
4234
4235static int
Andreas Färber05390242012-02-25 03:37:53 +01004236restore_sigregs(CPUS390XState *env, target_sigregs *sc)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004237{
4238 int err = 0;
4239 int i;
4240
4241 for (i = 0; i < 16; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03004242 __get_user(env->regs[i], &sc->regs.gprs[i]);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004243 }
4244
Riku Voipio1d8b5122014-04-23 10:26:05 +03004245 __get_user(env->psw.mask, &sc->regs.psw.mask);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004246 qemu_log("%s: sc->regs.psw.addr 0x%llx env->psw.addr 0x%llx\n",
4247 __FUNCTION__, (unsigned long long)sc->regs.psw.addr,
4248 (unsigned long long)env->psw.addr);
Riku Voipio1d8b5122014-04-23 10:26:05 +03004249 __get_user(env->psw.addr, &sc->regs.psw.addr);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004250 /* FIXME: 31-bit -> | PSW_ADDR_AMODE */
4251
4252 for (i = 0; i < 16; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03004253 __get_user(env->aregs[i], &sc->regs.acrs[i]);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004254 }
4255 for (i = 0; i < 16; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03004256 __get_user(env->fregs[i].ll, &sc->fpregs.fprs[i]);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004257 }
4258
4259 return err;
4260}
4261
Andreas Färber05390242012-02-25 03:37:53 +01004262long do_sigreturn(CPUS390XState *env)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004263{
4264 sigframe *frame;
4265 abi_ulong frame_addr = env->regs[15];
4266 qemu_log("%s: frame_addr 0x%llx\n", __FUNCTION__,
4267 (unsigned long long)frame_addr);
4268 target_sigset_t target_set;
4269 sigset_t set;
4270
4271 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
4272 goto badframe;
4273 }
Riku Voipiof5f601a2014-04-23 13:00:17 +03004274 __get_user(target_set.sig[0], &frame->sc.oldmask[0]);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004275
4276 target_to_host_sigset_internal(&set, &target_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00004277 do_sigprocmask(SIG_SETMASK, &set, NULL); /* ~_BLOCKABLE? */
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004278
4279 if (restore_sigregs(env, &frame->sregs)) {
4280 goto badframe;
4281 }
4282
4283 unlock_user_struct(frame, frame_addr, 0);
4284 return env->regs[2];
4285
4286badframe:
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004287 force_sig(TARGET_SIGSEGV);
4288 return 0;
4289}
4290
Andreas Färber05390242012-02-25 03:37:53 +01004291long do_rt_sigreturn(CPUS390XState *env)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004292{
4293 rt_sigframe *frame;
4294 abi_ulong frame_addr = env->regs[15];
4295 qemu_log("%s: frame_addr 0x%llx\n", __FUNCTION__,
4296 (unsigned long long)frame_addr);
4297 sigset_t set;
4298
4299 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
4300 goto badframe;
4301 }
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004302 target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004303
Alex Barcelo1c275922014-03-14 14:36:55 +00004304 do_sigprocmask(SIG_SETMASK, &set, NULL); /* ~_BLOCKABLE? */
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004305
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004306 if (restore_sigregs(env, &frame->uc.tuc_mcontext)) {
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004307 goto badframe;
4308 }
4309
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004310 if (do_sigaltstack(frame_addr + offsetof(rt_sigframe, uc.tuc_stack), 0,
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004311 get_sp_from_cpustate(env)) == -EFAULT) {
4312 goto badframe;
4313 }
4314 unlock_user_struct(frame, frame_addr, 0);
4315 return env->regs[2];
4316
4317badframe:
4318 unlock_user_struct(frame, frame_addr, 0);
4319 force_sig(TARGET_SIGSEGV);
4320 return 0;
4321}
4322
Nathan Froydbcd49332009-05-12 19:13:18 -07004323#elif defined(TARGET_PPC) && !defined(TARGET_PPC64)
4324
4325/* FIXME: Many of the structures are defined for both PPC and PPC64, but
4326 the signal handling is different enough that we haven't implemented
4327 support for PPC64 yet. Hence the restriction above.
4328
4329 There are various #if'd blocks for code for TARGET_PPC64. These
4330 blocks should go away so that we can successfully run 32-bit and
4331 64-bit binaries on a QEMU configured for PPC64. */
4332
4333/* Size of dummy stack frame allocated when calling signal handler.
4334 See arch/powerpc/include/asm/ptrace.h. */
4335#if defined(TARGET_PPC64)
4336#define SIGNAL_FRAMESIZE 128
4337#else
4338#define SIGNAL_FRAMESIZE 64
4339#endif
4340
4341/* See arch/powerpc/include/asm/sigcontext.h. */
4342struct target_sigcontext {
4343 target_ulong _unused[4];
4344 int32_t signal;
4345#if defined(TARGET_PPC64)
4346 int32_t pad0;
4347#endif
4348 target_ulong handler;
4349 target_ulong oldmask;
4350 target_ulong regs; /* struct pt_regs __user * */
4351 /* TODO: PPC64 includes extra bits here. */
4352};
4353
4354/* Indices for target_mcontext.mc_gregs, below.
4355 See arch/powerpc/include/asm/ptrace.h for details. */
4356enum {
4357 TARGET_PT_R0 = 0,
4358 TARGET_PT_R1 = 1,
4359 TARGET_PT_R2 = 2,
4360 TARGET_PT_R3 = 3,
4361 TARGET_PT_R4 = 4,
4362 TARGET_PT_R5 = 5,
4363 TARGET_PT_R6 = 6,
4364 TARGET_PT_R7 = 7,
4365 TARGET_PT_R8 = 8,
4366 TARGET_PT_R9 = 9,
4367 TARGET_PT_R10 = 10,
4368 TARGET_PT_R11 = 11,
4369 TARGET_PT_R12 = 12,
4370 TARGET_PT_R13 = 13,
4371 TARGET_PT_R14 = 14,
4372 TARGET_PT_R15 = 15,
4373 TARGET_PT_R16 = 16,
4374 TARGET_PT_R17 = 17,
4375 TARGET_PT_R18 = 18,
4376 TARGET_PT_R19 = 19,
4377 TARGET_PT_R20 = 20,
4378 TARGET_PT_R21 = 21,
4379 TARGET_PT_R22 = 22,
4380 TARGET_PT_R23 = 23,
4381 TARGET_PT_R24 = 24,
4382 TARGET_PT_R25 = 25,
4383 TARGET_PT_R26 = 26,
4384 TARGET_PT_R27 = 27,
4385 TARGET_PT_R28 = 28,
4386 TARGET_PT_R29 = 29,
4387 TARGET_PT_R30 = 30,
4388 TARGET_PT_R31 = 31,
4389 TARGET_PT_NIP = 32,
4390 TARGET_PT_MSR = 33,
4391 TARGET_PT_ORIG_R3 = 34,
4392 TARGET_PT_CTR = 35,
4393 TARGET_PT_LNK = 36,
4394 TARGET_PT_XER = 37,
4395 TARGET_PT_CCR = 38,
4396 /* Yes, there are two registers with #39. One is 64-bit only. */
4397 TARGET_PT_MQ = 39,
4398 TARGET_PT_SOFTE = 39,
4399 TARGET_PT_TRAP = 40,
4400 TARGET_PT_DAR = 41,
4401 TARGET_PT_DSISR = 42,
4402 TARGET_PT_RESULT = 43,
4403 TARGET_PT_REGS_COUNT = 44
4404};
4405
4406/* See arch/powerpc/include/asm/ucontext.h. Only used for 32-bit PPC;
4407 on 64-bit PPC, sigcontext and mcontext are one and the same. */
4408struct target_mcontext {
4409 target_ulong mc_gregs[48];
4410 /* Includes fpscr. */
4411 uint64_t mc_fregs[33];
4412 target_ulong mc_pad[2];
4413 /* We need to handle Altivec and SPE at the same time, which no
4414 kernel needs to do. Fortunately, the kernel defines this bit to
4415 be Altivec-register-large all the time, rather than trying to
4416 twiddle it based on the specific platform. */
4417 union {
4418 /* SPE vector registers. One extra for SPEFSCR. */
4419 uint32_t spe[33];
4420 /* Altivec vector registers. The packing of VSCR and VRSAVE
4421 varies depending on whether we're PPC64 or not: PPC64 splits
4422 them apart; PPC32 stuffs them together. */
4423#if defined(TARGET_PPC64)
malc3efa9a62009-07-18 13:10:12 +04004424#define QEMU_NVRREG 34
Nathan Froydbcd49332009-05-12 19:13:18 -07004425#else
malc3efa9a62009-07-18 13:10:12 +04004426#define QEMU_NVRREG 33
Nathan Froydbcd49332009-05-12 19:13:18 -07004427#endif
Anthony Liguoric227f092009-10-01 16:12:16 -05004428 ppc_avr_t altivec[QEMU_NVRREG];
malc3efa9a62009-07-18 13:10:12 +04004429#undef QEMU_NVRREG
Nathan Froydbcd49332009-05-12 19:13:18 -07004430 } mc_vregs __attribute__((__aligned__(16)));
4431};
4432
4433struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02004434 target_ulong tuc_flags;
4435 target_ulong tuc_link; /* struct ucontext __user * */
4436 struct target_sigaltstack tuc_stack;
Nathan Froydbcd49332009-05-12 19:13:18 -07004437#if !defined(TARGET_PPC64)
Aurelien Jarno60e99242010-03-29 02:12:51 +02004438 int32_t tuc_pad[7];
4439 target_ulong tuc_regs; /* struct mcontext __user *
Nathan Froydbcd49332009-05-12 19:13:18 -07004440 points to uc_mcontext field */
4441#endif
Aurelien Jarno60e99242010-03-29 02:12:51 +02004442 target_sigset_t tuc_sigmask;
Nathan Froydbcd49332009-05-12 19:13:18 -07004443#if defined(TARGET_PPC64)
Anthony Liguoric227f092009-10-01 16:12:16 -05004444 target_sigset_t unused[15]; /* Allow for uc_sigmask growth */
Aurelien Jarno60e99242010-03-29 02:12:51 +02004445 struct target_sigcontext tuc_mcontext;
Nathan Froydbcd49332009-05-12 19:13:18 -07004446#else
Aurelien Jarno60e99242010-03-29 02:12:51 +02004447 int32_t tuc_maskext[30];
4448 int32_t tuc_pad2[3];
4449 struct target_mcontext tuc_mcontext;
Nathan Froydbcd49332009-05-12 19:13:18 -07004450#endif
4451};
4452
4453/* See arch/powerpc/kernel/signal_32.c. */
4454struct target_sigframe {
4455 struct target_sigcontext sctx;
4456 struct target_mcontext mctx;
4457 int32_t abigap[56];
4458};
4459
4460struct target_rt_sigframe {
4461 struct target_siginfo info;
4462 struct target_ucontext uc;
4463 int32_t abigap[56];
4464};
4465
4466/* We use the mc_pad field for the signal return trampoline. */
4467#define tramp mc_pad
4468
4469/* See arch/powerpc/kernel/signal.c. */
4470static target_ulong get_sigframe(struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01004471 CPUPPCState *env,
Nathan Froydbcd49332009-05-12 19:13:18 -07004472 int frame_size)
4473{
4474 target_ulong oldsp, newsp;
4475
4476 oldsp = env->gpr[1];
4477
4478 if ((ka->sa_flags & TARGET_SA_ONSTACK) &&
Alex Barcelo32a20032012-02-09 23:55:46 +00004479 (sas_ss_flags(oldsp) == 0)) {
Nathan Froydbcd49332009-05-12 19:13:18 -07004480 oldsp = (target_sigaltstack_used.ss_sp
4481 + target_sigaltstack_used.ss_size);
4482 }
4483
4484 newsp = (oldsp - frame_size) & ~0xFUL;
4485
4486 return newsp;
4487}
4488
Andreas Färber05390242012-02-25 03:37:53 +01004489static int save_user_regs(CPUPPCState *env, struct target_mcontext *frame,
Nathan Froydbcd49332009-05-12 19:13:18 -07004490 int sigret)
4491{
4492 target_ulong msr = env->msr;
4493 int i;
4494 target_ulong ccr = 0;
4495
4496 /* In general, the kernel attempts to be intelligent about what it
4497 needs to save for Altivec/FP/SPE registers. We don't care that
4498 much, so we just go ahead and save everything. */
4499
4500 /* Save general registers. */
4501 for (i = 0; i < ARRAY_SIZE(env->gpr); i++) {
4502 if (__put_user(env->gpr[i], &frame->mc_gregs[i])) {
4503 return 1;
4504 }
4505 }
4506 if (__put_user(env->nip, &frame->mc_gregs[TARGET_PT_NIP])
4507 || __put_user(env->ctr, &frame->mc_gregs[TARGET_PT_CTR])
4508 || __put_user(env->lr, &frame->mc_gregs[TARGET_PT_LNK])
4509 || __put_user(env->xer, &frame->mc_gregs[TARGET_PT_XER]))
4510 return 1;
4511
4512 for (i = 0; i < ARRAY_SIZE(env->crf); i++) {
4513 ccr |= env->crf[i] << (32 - ((i + 1) * 4));
4514 }
4515 if (__put_user(ccr, &frame->mc_gregs[TARGET_PT_CCR]))
4516 return 1;
4517
4518 /* Save Altivec registers if necessary. */
4519 if (env->insns_flags & PPC_ALTIVEC) {
4520 for (i = 0; i < ARRAY_SIZE(env->avr); i++) {
Anthony Liguoric227f092009-10-01 16:12:16 -05004521 ppc_avr_t *avr = &env->avr[i];
4522 ppc_avr_t *vreg = &frame->mc_vregs.altivec[i];
Nathan Froydbcd49332009-05-12 19:13:18 -07004523
4524 if (__put_user(avr->u64[0], &vreg->u64[0]) ||
4525 __put_user(avr->u64[1], &vreg->u64[1])) {
4526 return 1;
4527 }
4528 }
4529 /* Set MSR_VR in the saved MSR value to indicate that
4530 frame->mc_vregs contains valid data. */
4531 msr |= MSR_VR;
4532 if (__put_user((uint32_t)env->spr[SPR_VRSAVE],
4533 &frame->mc_vregs.altivec[32].u32[3]))
4534 return 1;
4535 }
4536
4537 /* Save floating point registers. */
4538 if (env->insns_flags & PPC_FLOAT) {
4539 for (i = 0; i < ARRAY_SIZE(env->fpr); i++) {
4540 if (__put_user(env->fpr[i], &frame->mc_fregs[i])) {
4541 return 1;
4542 }
4543 }
4544 if (__put_user((uint64_t) env->fpscr, &frame->mc_fregs[32]))
4545 return 1;
4546 }
4547
4548 /* Save SPE registers. The kernel only saves the high half. */
4549 if (env->insns_flags & PPC_SPE) {
4550#if defined(TARGET_PPC64)
4551 for (i = 0; i < ARRAY_SIZE(env->gpr); i++) {
4552 if (__put_user(env->gpr[i] >> 32, &frame->mc_vregs.spe[i])) {
4553 return 1;
4554 }
4555 }
4556#else
4557 for (i = 0; i < ARRAY_SIZE(env->gprh); i++) {
4558 if (__put_user(env->gprh[i], &frame->mc_vregs.spe[i])) {
4559 return 1;
4560 }
4561 }
4562#endif
4563 /* Set MSR_SPE in the saved MSR value to indicate that
4564 frame->mc_vregs contains valid data. */
4565 msr |= MSR_SPE;
4566 if (__put_user(env->spe_fscr, &frame->mc_vregs.spe[32]))
4567 return 1;
4568 }
4569
4570 /* Store MSR. */
4571 if (__put_user(msr, &frame->mc_gregs[TARGET_PT_MSR]))
4572 return 1;
4573
4574 /* Set up the sigreturn trampoline: li r0,sigret; sc. */
4575 if (sigret) {
4576 if (__put_user(0x38000000UL | sigret, &frame->tramp[0]) ||
4577 __put_user(0x44000002UL, &frame->tramp[1])) {
4578 return 1;
4579 }
4580 }
4581
4582 return 0;
4583}
4584
Andreas Färber05390242012-02-25 03:37:53 +01004585static int restore_user_regs(CPUPPCState *env,
Nathan Froydbcd49332009-05-12 19:13:18 -07004586 struct target_mcontext *frame, int sig)
4587{
4588 target_ulong save_r2 = 0;
4589 target_ulong msr;
4590 target_ulong ccr;
4591
4592 int i;
4593
4594 if (!sig) {
4595 save_r2 = env->gpr[2];
4596 }
4597
4598 /* Restore general registers. */
4599 for (i = 0; i < ARRAY_SIZE(env->gpr); i++) {
4600 if (__get_user(env->gpr[i], &frame->mc_gregs[i])) {
4601 return 1;
4602 }
4603 }
4604 if (__get_user(env->nip, &frame->mc_gregs[TARGET_PT_NIP])
4605 || __get_user(env->ctr, &frame->mc_gregs[TARGET_PT_CTR])
4606 || __get_user(env->lr, &frame->mc_gregs[TARGET_PT_LNK])
4607 || __get_user(env->xer, &frame->mc_gregs[TARGET_PT_XER]))
4608 return 1;
4609 if (__get_user(ccr, &frame->mc_gregs[TARGET_PT_CCR]))
4610 return 1;
4611
4612 for (i = 0; i < ARRAY_SIZE(env->crf); i++) {
4613 env->crf[i] = (ccr >> (32 - ((i + 1) * 4))) & 0xf;
4614 }
4615
4616 if (!sig) {
4617 env->gpr[2] = save_r2;
4618 }
4619 /* Restore MSR. */
4620 if (__get_user(msr, &frame->mc_gregs[TARGET_PT_MSR]))
4621 return 1;
4622
4623 /* If doing signal return, restore the previous little-endian mode. */
4624 if (sig)
4625 env->msr = (env->msr & ~MSR_LE) | (msr & MSR_LE);
4626
4627 /* Restore Altivec registers if necessary. */
4628 if (env->insns_flags & PPC_ALTIVEC) {
4629 for (i = 0; i < ARRAY_SIZE(env->avr); i++) {
Anthony Liguoric227f092009-10-01 16:12:16 -05004630 ppc_avr_t *avr = &env->avr[i];
4631 ppc_avr_t *vreg = &frame->mc_vregs.altivec[i];
Nathan Froydbcd49332009-05-12 19:13:18 -07004632
4633 if (__get_user(avr->u64[0], &vreg->u64[0]) ||
4634 __get_user(avr->u64[1], &vreg->u64[1])) {
4635 return 1;
4636 }
4637 }
4638 /* Set MSR_VEC in the saved MSR value to indicate that
4639 frame->mc_vregs contains valid data. */
4640 if (__get_user(env->spr[SPR_VRSAVE],
4641 (target_ulong *)(&frame->mc_vregs.altivec[32].u32[3])))
4642 return 1;
4643 }
4644
4645 /* Restore floating point registers. */
4646 if (env->insns_flags & PPC_FLOAT) {
4647 uint64_t fpscr;
4648 for (i = 0; i < ARRAY_SIZE(env->fpr); i++) {
4649 if (__get_user(env->fpr[i], &frame->mc_fregs[i])) {
4650 return 1;
4651 }
4652 }
4653 if (__get_user(fpscr, &frame->mc_fregs[32]))
4654 return 1;
4655 env->fpscr = (uint32_t) fpscr;
4656 }
4657
4658 /* Save SPE registers. The kernel only saves the high half. */
4659 if (env->insns_flags & PPC_SPE) {
4660#if defined(TARGET_PPC64)
4661 for (i = 0; i < ARRAY_SIZE(env->gpr); i++) {
4662 uint32_t hi;
4663
4664 if (__get_user(hi, &frame->mc_vregs.spe[i])) {
4665 return 1;
4666 }
4667 env->gpr[i] = ((uint64_t)hi << 32) | ((uint32_t) env->gpr[i]);
4668 }
4669#else
4670 for (i = 0; i < ARRAY_SIZE(env->gprh); i++) {
4671 if (__get_user(env->gprh[i], &frame->mc_vregs.spe[i])) {
4672 return 1;
4673 }
4674 }
4675#endif
4676 if (__get_user(env->spe_fscr, &frame->mc_vregs.spe[32]))
4677 return 1;
4678 }
4679
4680 return 0;
4681}
4682
4683static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01004684 target_sigset_t *set, CPUPPCState *env)
Nathan Froydbcd49332009-05-12 19:13:18 -07004685{
4686 struct target_sigframe *frame;
4687 struct target_sigcontext *sc;
4688 target_ulong frame_addr, newsp;
4689 int err = 0;
4690 int signal;
4691
4692 frame_addr = get_sigframe(ka, env, sizeof(*frame));
4693 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 1))
4694 goto sigsegv;
4695 sc = &frame->sctx;
4696
4697 signal = current_exec_domain_sig(sig);
4698
Riku Voipio1d8b5122014-04-23 10:26:05 +03004699 __put_user(ka->_sa_handler, &sc->handler);
4700 __put_user(set->sig[0], &sc->oldmask);
Nathan Froydbcd49332009-05-12 19:13:18 -07004701#if defined(TARGET_PPC64)
Riku Voipio1d8b5122014-04-23 10:26:05 +03004702 __put_user(set->sig[0] >> 32, &sc->_unused[3]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004703#else
Riku Voipio1d8b5122014-04-23 10:26:05 +03004704 __put_user(set->sig[1], &sc->_unused[3]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004705#endif
Riku Voipio1d8b5122014-04-23 10:26:05 +03004706 __put_user(h2g(&frame->mctx), &sc->regs);
4707 __put_user(sig, &sc->signal);
Nathan Froydbcd49332009-05-12 19:13:18 -07004708
4709 /* Save user regs. */
4710 err |= save_user_regs(env, &frame->mctx, TARGET_NR_sigreturn);
4711
4712 /* The kernel checks for the presence of a VDSO here. We don't
4713 emulate a vdso, so use a sigreturn system call. */
4714 env->lr = (target_ulong) h2g(frame->mctx.tramp);
4715
4716 /* Turn off all fp exceptions. */
4717 env->fpscr = 0;
4718
4719 /* Create a stack frame for the caller of the handler. */
4720 newsp = frame_addr - SIGNAL_FRAMESIZE;
Samuel Seaybeb526b2013-01-02 10:53:46 +00004721 err |= put_user(env->gpr[1], newsp, target_ulong);
Nathan Froydbcd49332009-05-12 19:13:18 -07004722
4723 if (err)
4724 goto sigsegv;
4725
4726 /* Set up registers for signal handler. */
4727 env->gpr[1] = newsp;
4728 env->gpr[3] = signal;
Samuel Seay61993a62013-01-04 14:35:48 +00004729 env->gpr[4] = frame_addr + offsetof(struct target_sigframe, sctx);
Nathan Froydbcd49332009-05-12 19:13:18 -07004730 env->nip = (target_ulong) ka->_sa_handler;
4731 /* Signal handlers are entered in big-endian mode. */
4732 env->msr &= ~MSR_LE;
4733
4734 unlock_user_struct(frame, frame_addr, 1);
4735 return;
4736
4737sigsegv:
4738 unlock_user_struct(frame, frame_addr, 1);
Blue Swirleeacee42012-06-03 16:35:32 +00004739 qemu_log("segfaulting from setup_frame\n");
Riku Voipio66393fb2009-12-04 15:16:32 +02004740 force_sig(TARGET_SIGSEGV);
Nathan Froydbcd49332009-05-12 19:13:18 -07004741}
4742
4743static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05004744 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01004745 target_sigset_t *set, CPUPPCState *env)
Nathan Froydbcd49332009-05-12 19:13:18 -07004746{
4747 struct target_rt_sigframe *rt_sf;
4748 struct target_mcontext *frame;
4749 target_ulong rt_sf_addr, newsp = 0;
4750 int i, err = 0;
4751 int signal;
4752
4753 rt_sf_addr = get_sigframe(ka, env, sizeof(*rt_sf));
4754 if (!lock_user_struct(VERIFY_WRITE, rt_sf, rt_sf_addr, 1))
4755 goto sigsegv;
4756
4757 signal = current_exec_domain_sig(sig);
4758
Riku Voipiob0fd8d12014-04-23 10:46:13 +03004759 copy_siginfo_to_user(&rt_sf->info, info);
Nathan Froydbcd49332009-05-12 19:13:18 -07004760
Riku Voipio1d8b5122014-04-23 10:26:05 +03004761 __put_user(0, &rt_sf->uc.tuc_flags);
4762 __put_user(0, &rt_sf->uc.tuc_link);
4763 __put_user((target_ulong)target_sigaltstack_used.ss_sp,
4764 &rt_sf->uc.tuc_stack.ss_sp);
4765 __put_user(sas_ss_flags(env->gpr[1]),
4766 &rt_sf->uc.tuc_stack.ss_flags);
4767 __put_user(target_sigaltstack_used.ss_size,
4768 &rt_sf->uc.tuc_stack.ss_size);
4769 __put_user(h2g (&rt_sf->uc.tuc_mcontext),
4770 &rt_sf->uc.tuc_regs);
Nathan Froydbcd49332009-05-12 19:13:18 -07004771 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03004772 __put_user(set->sig[i], &rt_sf->uc.tuc_sigmask.sig[i]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004773 }
4774
Aurelien Jarno60e99242010-03-29 02:12:51 +02004775 frame = &rt_sf->uc.tuc_mcontext;
Nathan Froydbcd49332009-05-12 19:13:18 -07004776 err |= save_user_regs(env, frame, TARGET_NR_rt_sigreturn);
4777
4778 /* The kernel checks for the presence of a VDSO here. We don't
4779 emulate a vdso, so use a sigreturn system call. */
4780 env->lr = (target_ulong) h2g(frame->tramp);
4781
4782 /* Turn off all fp exceptions. */
4783 env->fpscr = 0;
4784
4785 /* Create a stack frame for the caller of the handler. */
4786 newsp = rt_sf_addr - (SIGNAL_FRAMESIZE + 16);
Riku Voipio1d8b5122014-04-23 10:26:05 +03004787 __put_user(env->gpr[1], (target_ulong *)(uintptr_t) newsp);
Nathan Froydbcd49332009-05-12 19:13:18 -07004788
4789 if (err)
4790 goto sigsegv;
4791
4792 /* Set up registers for signal handler. */
4793 env->gpr[1] = newsp;
4794 env->gpr[3] = (target_ulong) signal;
4795 env->gpr[4] = (target_ulong) h2g(&rt_sf->info);
4796 env->gpr[5] = (target_ulong) h2g(&rt_sf->uc);
4797 env->gpr[6] = (target_ulong) h2g(rt_sf);
4798 env->nip = (target_ulong) ka->_sa_handler;
4799 /* Signal handlers are entered in big-endian mode. */
4800 env->msr &= ~MSR_LE;
4801
4802 unlock_user_struct(rt_sf, rt_sf_addr, 1);
4803 return;
4804
4805sigsegv:
4806 unlock_user_struct(rt_sf, rt_sf_addr, 1);
Blue Swirleeacee42012-06-03 16:35:32 +00004807 qemu_log("segfaulting from setup_rt_frame\n");
Riku Voipio66393fb2009-12-04 15:16:32 +02004808 force_sig(TARGET_SIGSEGV);
Nathan Froydbcd49332009-05-12 19:13:18 -07004809
4810}
4811
Andreas Färber05390242012-02-25 03:37:53 +01004812long do_sigreturn(CPUPPCState *env)
Nathan Froydbcd49332009-05-12 19:13:18 -07004813{
4814 struct target_sigcontext *sc = NULL;
4815 struct target_mcontext *sr = NULL;
Peter Maydellb04636f2013-07-29 12:00:31 +01004816 target_ulong sr_addr = 0, sc_addr;
Nathan Froydbcd49332009-05-12 19:13:18 -07004817 sigset_t blocked;
Anthony Liguoric227f092009-10-01 16:12:16 -05004818 target_sigset_t set;
Nathan Froydbcd49332009-05-12 19:13:18 -07004819
4820 sc_addr = env->gpr[1] + SIGNAL_FRAMESIZE;
4821 if (!lock_user_struct(VERIFY_READ, sc, sc_addr, 1))
4822 goto sigsegv;
4823
4824#if defined(TARGET_PPC64)
4825 set.sig[0] = sc->oldmask + ((long)(sc->_unused[3]) << 32);
4826#else
Riku Voipiof5f601a2014-04-23 13:00:17 +03004827 __get_user(set.sig[0], &sc->oldmask);
4828 __get_user(set.sig[1], &sc->_unused[3]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004829#endif
4830 target_to_host_sigset_internal(&blocked, &set);
Alex Barcelo1c275922014-03-14 14:36:55 +00004831 do_sigprocmask(SIG_SETMASK, &blocked, NULL);
Nathan Froydbcd49332009-05-12 19:13:18 -07004832
Riku Voipiof5f601a2014-04-23 13:00:17 +03004833 __get_user(sr_addr, &sc->regs);
Nathan Froydbcd49332009-05-12 19:13:18 -07004834 if (!lock_user_struct(VERIFY_READ, sr, sr_addr, 1))
4835 goto sigsegv;
4836 if (restore_user_regs(env, sr, 1))
4837 goto sigsegv;
4838
4839 unlock_user_struct(sr, sr_addr, 1);
4840 unlock_user_struct(sc, sc_addr, 1);
4841 return -TARGET_QEMU_ESIGRETURN;
4842
4843sigsegv:
4844 unlock_user_struct(sr, sr_addr, 1);
4845 unlock_user_struct(sc, sc_addr, 1);
Blue Swirleeacee42012-06-03 16:35:32 +00004846 qemu_log("segfaulting from do_sigreturn\n");
Riku Voipio66393fb2009-12-04 15:16:32 +02004847 force_sig(TARGET_SIGSEGV);
Nathan Froydbcd49332009-05-12 19:13:18 -07004848 return 0;
4849}
4850
4851/* See arch/powerpc/kernel/signal_32.c. */
Andreas Färber05390242012-02-25 03:37:53 +01004852static int do_setcontext(struct target_ucontext *ucp, CPUPPCState *env, int sig)
Nathan Froydbcd49332009-05-12 19:13:18 -07004853{
4854 struct target_mcontext *mcp;
4855 target_ulong mcp_addr;
4856 sigset_t blocked;
Anthony Liguoric227f092009-10-01 16:12:16 -05004857 target_sigset_t set;
Nathan Froydbcd49332009-05-12 19:13:18 -07004858
Aurelien Jarno60e99242010-03-29 02:12:51 +02004859 if (copy_from_user(&set, h2g(ucp) + offsetof(struct target_ucontext, tuc_sigmask),
Nathan Froydbcd49332009-05-12 19:13:18 -07004860 sizeof (set)))
4861 return 1;
4862
4863#if defined(TARGET_PPC64)
4864 fprintf (stderr, "do_setcontext: not implemented\n");
4865 return 0;
4866#else
Aurelien Jarno60e99242010-03-29 02:12:51 +02004867 if (__get_user(mcp_addr, &ucp->tuc_regs))
Nathan Froydbcd49332009-05-12 19:13:18 -07004868 return 1;
4869
4870 if (!lock_user_struct(VERIFY_READ, mcp, mcp_addr, 1))
4871 return 1;
4872
4873 target_to_host_sigset_internal(&blocked, &set);
Alex Barcelo1c275922014-03-14 14:36:55 +00004874 do_sigprocmask(SIG_SETMASK, &blocked, NULL);
Nathan Froydbcd49332009-05-12 19:13:18 -07004875 if (restore_user_regs(env, mcp, sig))
4876 goto sigsegv;
4877
4878 unlock_user_struct(mcp, mcp_addr, 1);
4879 return 0;
4880
4881sigsegv:
4882 unlock_user_struct(mcp, mcp_addr, 1);
4883 return 1;
4884#endif
4885}
4886
Andreas Färber05390242012-02-25 03:37:53 +01004887long do_rt_sigreturn(CPUPPCState *env)
Nathan Froydbcd49332009-05-12 19:13:18 -07004888{
4889 struct target_rt_sigframe *rt_sf = NULL;
4890 target_ulong rt_sf_addr;
4891
4892 rt_sf_addr = env->gpr[1] + SIGNAL_FRAMESIZE + 16;
4893 if (!lock_user_struct(VERIFY_READ, rt_sf, rt_sf_addr, 1))
4894 goto sigsegv;
4895
4896 if (do_setcontext(&rt_sf->uc, env, 1))
4897 goto sigsegv;
4898
4899 do_sigaltstack(rt_sf_addr
Aurelien Jarno60e99242010-03-29 02:12:51 +02004900 + offsetof(struct target_rt_sigframe, uc.tuc_stack),
Nathan Froydbcd49332009-05-12 19:13:18 -07004901 0, env->gpr[1]);
4902
4903 unlock_user_struct(rt_sf, rt_sf_addr, 1);
4904 return -TARGET_QEMU_ESIGRETURN;
4905
4906sigsegv:
4907 unlock_user_struct(rt_sf, rt_sf_addr, 1);
Blue Swirleeacee42012-06-03 16:35:32 +00004908 qemu_log("segfaulting from do_rt_sigreturn\n");
Riku Voipio66393fb2009-12-04 15:16:32 +02004909 force_sig(TARGET_SIGSEGV);
Nathan Froydbcd49332009-05-12 19:13:18 -07004910 return 0;
4911}
4912
Laurent Vivier492a8742009-08-03 16:12:17 +02004913#elif defined(TARGET_M68K)
4914
4915struct target_sigcontext {
4916 abi_ulong sc_mask;
4917 abi_ulong sc_usp;
4918 abi_ulong sc_d0;
4919 abi_ulong sc_d1;
4920 abi_ulong sc_a0;
4921 abi_ulong sc_a1;
4922 unsigned short sc_sr;
4923 abi_ulong sc_pc;
4924};
4925
4926struct target_sigframe
4927{
4928 abi_ulong pretcode;
4929 int sig;
4930 int code;
4931 abi_ulong psc;
4932 char retcode[8];
4933 abi_ulong extramask[TARGET_NSIG_WORDS-1];
4934 struct target_sigcontext sc;
4935};
Laurent Vivier71811552009-08-03 16:12:18 +02004936
Anthony Liguoric227f092009-10-01 16:12:16 -05004937typedef int target_greg_t;
Laurent Vivier71811552009-08-03 16:12:18 +02004938#define TARGET_NGREG 18
Anthony Liguoric227f092009-10-01 16:12:16 -05004939typedef target_greg_t target_gregset_t[TARGET_NGREG];
Laurent Vivier71811552009-08-03 16:12:18 +02004940
4941typedef struct target_fpregset {
4942 int f_fpcntl[3];
4943 int f_fpregs[8*3];
Anthony Liguoric227f092009-10-01 16:12:16 -05004944} target_fpregset_t;
Laurent Vivier71811552009-08-03 16:12:18 +02004945
4946struct target_mcontext {
4947 int version;
Anthony Liguoric227f092009-10-01 16:12:16 -05004948 target_gregset_t gregs;
4949 target_fpregset_t fpregs;
Laurent Vivier71811552009-08-03 16:12:18 +02004950};
4951
4952#define TARGET_MCONTEXT_VERSION 2
4953
4954struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02004955 abi_ulong tuc_flags;
4956 abi_ulong tuc_link;
4957 target_stack_t tuc_stack;
4958 struct target_mcontext tuc_mcontext;
4959 abi_long tuc_filler[80];
4960 target_sigset_t tuc_sigmask;
Laurent Vivier71811552009-08-03 16:12:18 +02004961};
4962
4963struct target_rt_sigframe
4964{
4965 abi_ulong pretcode;
4966 int sig;
4967 abi_ulong pinfo;
4968 abi_ulong puc;
4969 char retcode[8];
4970 struct target_siginfo info;
4971 struct target_ucontext uc;
4972};
Laurent Vivier492a8742009-08-03 16:12:17 +02004973
Riku Voipio41ecc722014-04-23 11:01:00 +03004974static void setup_sigcontext(struct target_sigcontext *sc, CPUM68KState *env,
4975 abi_ulong mask)
Laurent Vivier492a8742009-08-03 16:12:17 +02004976{
Riku Voipio1d8b5122014-04-23 10:26:05 +03004977 __put_user(mask, &sc->sc_mask);
4978 __put_user(env->aregs[7], &sc->sc_usp);
4979 __put_user(env->dregs[0], &sc->sc_d0);
4980 __put_user(env->dregs[1], &sc->sc_d1);
4981 __put_user(env->aregs[0], &sc->sc_a0);
4982 __put_user(env->aregs[1], &sc->sc_a1);
4983 __put_user(env->sr, &sc->sc_sr);
4984 __put_user(env->pc, &sc->sc_pc);
Laurent Vivier492a8742009-08-03 16:12:17 +02004985}
4986
Riku Voipio016d2e12014-04-23 11:19:48 +03004987static void
Andreas Färber05390242012-02-25 03:37:53 +01004988restore_sigcontext(CPUM68KState *env, struct target_sigcontext *sc, int *pd0)
Laurent Vivier492a8742009-08-03 16:12:17 +02004989{
Laurent Vivier492a8742009-08-03 16:12:17 +02004990 int temp;
4991
Riku Voipio1d8b5122014-04-23 10:26:05 +03004992 __get_user(env->aregs[7], &sc->sc_usp);
4993 __get_user(env->dregs[1], &sc->sc_d1);
4994 __get_user(env->aregs[0], &sc->sc_a0);
4995 __get_user(env->aregs[1], &sc->sc_a1);
4996 __get_user(env->pc, &sc->sc_pc);
4997 __get_user(temp, &sc->sc_sr);
Laurent Vivier492a8742009-08-03 16:12:17 +02004998 env->sr = (env->sr & 0xff00) | (temp & 0xff);
4999
5000 *pd0 = tswapl(sc->sc_d0);
Laurent Vivier492a8742009-08-03 16:12:17 +02005001}
5002
5003/*
5004 * Determine which stack to use..
5005 */
5006static inline abi_ulong
Andreas Färber05390242012-02-25 03:37:53 +01005007get_sigframe(struct target_sigaction *ka, CPUM68KState *regs,
5008 size_t frame_size)
Laurent Vivier492a8742009-08-03 16:12:17 +02005009{
5010 unsigned long sp;
5011
5012 sp = regs->aregs[7];
5013
5014 /* This is the X/Open sanctioned signal stack switching. */
5015 if ((ka->sa_flags & TARGET_SA_ONSTACK) && (sas_ss_flags (sp) == 0)) {
5016 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
5017 }
5018
5019 return ((sp - frame_size) & -8UL);
5020}
5021
5022static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01005023 target_sigset_t *set, CPUM68KState *env)
Laurent Vivier492a8742009-08-03 16:12:17 +02005024{
5025 struct target_sigframe *frame;
5026 abi_ulong frame_addr;
5027 abi_ulong retcode_addr;
5028 abi_ulong sc_addr;
Laurent Vivier492a8742009-08-03 16:12:17 +02005029 int i;
5030
5031 frame_addr = get_sigframe(ka, env, sizeof *frame);
5032 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
5033 goto give_sigsegv;
5034
Riku Voipio1d8b5122014-04-23 10:26:05 +03005035 __put_user(sig, &frame->sig);
Laurent Vivier492a8742009-08-03 16:12:17 +02005036
5037 sc_addr = frame_addr + offsetof(struct target_sigframe, sc);
Riku Voipio1d8b5122014-04-23 10:26:05 +03005038 __put_user(sc_addr, &frame->psc);
Laurent Vivier492a8742009-08-03 16:12:17 +02005039
Riku Voipio41ecc722014-04-23 11:01:00 +03005040 setup_sigcontext(&frame->sc, env, set->sig[0]);
Laurent Vivier492a8742009-08-03 16:12:17 +02005041
5042 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
Riku Voipio0188fad2014-04-23 13:34:15 +03005043 __put_user(set->sig[i], &frame->extramask[i - 1]);
Laurent Vivier492a8742009-08-03 16:12:17 +02005044 }
5045
5046 /* Set up to return from userspace. */
5047
5048 retcode_addr = frame_addr + offsetof(struct target_sigframe, retcode);
Riku Voipio1d8b5122014-04-23 10:26:05 +03005049 __put_user(retcode_addr, &frame->pretcode);
Laurent Vivier492a8742009-08-03 16:12:17 +02005050
5051 /* moveq #,d0; trap #0 */
5052
Riku Voipio1d8b5122014-04-23 10:26:05 +03005053 __put_user(0x70004e40 + (TARGET_NR_sigreturn << 16),
Laurent Vivier492a8742009-08-03 16:12:17 +02005054 (long *)(frame->retcode));
5055
Laurent Vivier492a8742009-08-03 16:12:17 +02005056 /* Set up to return from userspace */
5057
5058 env->aregs[7] = frame_addr;
5059 env->pc = ka->_sa_handler;
5060
5061 unlock_user_struct(frame, frame_addr, 1);
5062 return;
5063
5064give_sigsegv:
Riku Voipio66393fb2009-12-04 15:16:32 +02005065 force_sig(TARGET_SIGSEGV);
Laurent Vivier492a8742009-08-03 16:12:17 +02005066}
5067
Laurent Vivier71811552009-08-03 16:12:18 +02005068static inline int target_rt_setup_ucontext(struct target_ucontext *uc,
Andreas Färber05390242012-02-25 03:37:53 +01005069 CPUM68KState *env)
Laurent Vivier71811552009-08-03 16:12:18 +02005070{
Aurelien Jarno60e99242010-03-29 02:12:51 +02005071 target_greg_t *gregs = uc->tuc_mcontext.gregs;
Laurent Vivier71811552009-08-03 16:12:18 +02005072
Riku Voipio1d8b5122014-04-23 10:26:05 +03005073 __put_user(TARGET_MCONTEXT_VERSION, &uc->tuc_mcontext.version);
5074 __put_user(env->dregs[0], &gregs[0]);
5075 __put_user(env->dregs[1], &gregs[1]);
5076 __put_user(env->dregs[2], &gregs[2]);
5077 __put_user(env->dregs[3], &gregs[3]);
5078 __put_user(env->dregs[4], &gregs[4]);
5079 __put_user(env->dregs[5], &gregs[5]);
5080 __put_user(env->dregs[6], &gregs[6]);
5081 __put_user(env->dregs[7], &gregs[7]);
5082 __put_user(env->aregs[0], &gregs[8]);
5083 __put_user(env->aregs[1], &gregs[9]);
5084 __put_user(env->aregs[2], &gregs[10]);
5085 __put_user(env->aregs[3], &gregs[11]);
5086 __put_user(env->aregs[4], &gregs[12]);
5087 __put_user(env->aregs[5], &gregs[13]);
5088 __put_user(env->aregs[6], &gregs[14]);
5089 __put_user(env->aregs[7], &gregs[15]);
5090 __put_user(env->pc, &gregs[16]);
5091 __put_user(env->sr, &gregs[17]);
Laurent Vivier71811552009-08-03 16:12:18 +02005092
Riku Voipio1d8b5122014-04-23 10:26:05 +03005093 return 0;
Laurent Vivier71811552009-08-03 16:12:18 +02005094}
5095
Andreas Färber05390242012-02-25 03:37:53 +01005096static inline int target_rt_restore_ucontext(CPUM68KState *env,
Laurent Vivier71811552009-08-03 16:12:18 +02005097 struct target_ucontext *uc,
5098 int *pd0)
5099{
5100 int temp;
Aurelien Jarno60e99242010-03-29 02:12:51 +02005101 target_greg_t *gregs = uc->tuc_mcontext.gregs;
Laurent Vivier71811552009-08-03 16:12:18 +02005102
Riku Voipio1d8b5122014-04-23 10:26:05 +03005103 __get_user(temp, &uc->tuc_mcontext.version);
Laurent Vivier71811552009-08-03 16:12:18 +02005104 if (temp != TARGET_MCONTEXT_VERSION)
5105 goto badframe;
5106
5107 /* restore passed registers */
Riku Voipio1d8b5122014-04-23 10:26:05 +03005108 __get_user(env->dregs[0], &gregs[0]);
5109 __get_user(env->dregs[1], &gregs[1]);
5110 __get_user(env->dregs[2], &gregs[2]);
5111 __get_user(env->dregs[3], &gregs[3]);
5112 __get_user(env->dregs[4], &gregs[4]);
5113 __get_user(env->dregs[5], &gregs[5]);
5114 __get_user(env->dregs[6], &gregs[6]);
5115 __get_user(env->dregs[7], &gregs[7]);
5116 __get_user(env->aregs[0], &gregs[8]);
5117 __get_user(env->aregs[1], &gregs[9]);
5118 __get_user(env->aregs[2], &gregs[10]);
5119 __get_user(env->aregs[3], &gregs[11]);
5120 __get_user(env->aregs[4], &gregs[12]);
5121 __get_user(env->aregs[5], &gregs[13]);
5122 __get_user(env->aregs[6], &gregs[14]);
5123 __get_user(env->aregs[7], &gregs[15]);
5124 __get_user(env->pc, &gregs[16]);
5125 __get_user(temp, &gregs[17]);
Laurent Vivier71811552009-08-03 16:12:18 +02005126 env->sr = (env->sr & 0xff00) | (temp & 0xff);
5127
5128 *pd0 = env->dregs[0];
Riku Voipio1d8b5122014-04-23 10:26:05 +03005129 return 0;
Laurent Vivier71811552009-08-03 16:12:18 +02005130
5131badframe:
5132 return 1;
5133}
5134
Laurent Vivier492a8742009-08-03 16:12:17 +02005135static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05005136 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01005137 target_sigset_t *set, CPUM68KState *env)
Laurent Vivier492a8742009-08-03 16:12:17 +02005138{
Laurent Vivier71811552009-08-03 16:12:18 +02005139 struct target_rt_sigframe *frame;
5140 abi_ulong frame_addr;
5141 abi_ulong retcode_addr;
5142 abi_ulong info_addr;
5143 abi_ulong uc_addr;
5144 int err = 0;
5145 int i;
5146
5147 frame_addr = get_sigframe(ka, env, sizeof *frame);
5148 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
5149 goto give_sigsegv;
5150
Riku Voipio1d8b5122014-04-23 10:26:05 +03005151 __put_user(sig, &frame->sig);
Laurent Vivier71811552009-08-03 16:12:18 +02005152
5153 info_addr = frame_addr + offsetof(struct target_rt_sigframe, info);
Riku Voipio1d8b5122014-04-23 10:26:05 +03005154 __put_user(info_addr, &frame->pinfo);
Laurent Vivier71811552009-08-03 16:12:18 +02005155
5156 uc_addr = frame_addr + offsetof(struct target_rt_sigframe, uc);
Riku Voipio1d8b5122014-04-23 10:26:05 +03005157 __put_user(uc_addr, &frame->puc);
Laurent Vivier71811552009-08-03 16:12:18 +02005158
Riku Voipiob0fd8d12014-04-23 10:46:13 +03005159 copy_siginfo_to_user(&frame->info, info);
Laurent Vivier71811552009-08-03 16:12:18 +02005160
5161 /* Create the ucontext */
5162
Riku Voipio1d8b5122014-04-23 10:26:05 +03005163 __put_user(0, &frame->uc.tuc_flags);
5164 __put_user(0, &frame->uc.tuc_link);
5165 __put_user(target_sigaltstack_used.ss_sp,
5166 &frame->uc.tuc_stack.ss_sp);
5167 __put_user(sas_ss_flags(env->aregs[7]),
5168 &frame->uc.tuc_stack.ss_flags);
5169 __put_user(target_sigaltstack_used.ss_size,
5170 &frame->uc.tuc_stack.ss_size);
Laurent Vivier71811552009-08-03 16:12:18 +02005171 err |= target_rt_setup_ucontext(&frame->uc, env);
5172
5173 if (err)
5174 goto give_sigsegv;
5175
5176 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
Riku Voipio0188fad2014-04-23 13:34:15 +03005177 __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
Laurent Vivier71811552009-08-03 16:12:18 +02005178 }
5179
5180 /* Set up to return from userspace. */
5181
5182 retcode_addr = frame_addr + offsetof(struct target_sigframe, retcode);
Riku Voipio1d8b5122014-04-23 10:26:05 +03005183 __put_user(retcode_addr, &frame->pretcode);
Laurent Vivier71811552009-08-03 16:12:18 +02005184
5185 /* moveq #,d0; notb d0; trap #0 */
5186
Riku Voipio1d8b5122014-04-23 10:26:05 +03005187 __put_user(0x70004600 + ((TARGET_NR_rt_sigreturn ^ 0xff) << 16),
5188 (long *)(frame->retcode + 0));
5189 __put_user(0x4e40, (short *)(frame->retcode + 4));
Laurent Vivier71811552009-08-03 16:12:18 +02005190
5191 if (err)
5192 goto give_sigsegv;
5193
5194 /* Set up to return from userspace */
5195
5196 env->aregs[7] = frame_addr;
5197 env->pc = ka->_sa_handler;
5198
5199 unlock_user_struct(frame, frame_addr, 1);
5200 return;
5201
5202give_sigsegv:
5203 unlock_user_struct(frame, frame_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02005204 force_sig(TARGET_SIGSEGV);
Laurent Vivier492a8742009-08-03 16:12:17 +02005205}
5206
Andreas Färber05390242012-02-25 03:37:53 +01005207long do_sigreturn(CPUM68KState *env)
Laurent Vivier492a8742009-08-03 16:12:17 +02005208{
5209 struct target_sigframe *frame;
5210 abi_ulong frame_addr = env->aregs[7] - 4;
Anthony Liguoric227f092009-10-01 16:12:16 -05005211 target_sigset_t target_set;
Laurent Vivier492a8742009-08-03 16:12:17 +02005212 sigset_t set;
5213 int d0, i;
5214
5215 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
5216 goto badframe;
5217
5218 /* set blocked signals */
5219
Riku Voipiof5f601a2014-04-23 13:00:17 +03005220 __get_user(target_set.sig[0], &frame->sc.sc_mask);
Laurent Vivier492a8742009-08-03 16:12:17 +02005221
5222 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
Riku Voipiof5f601a2014-04-23 13:00:17 +03005223 __get_user(target_set.sig[i], &frame->extramask[i - 1]);
Laurent Vivier492a8742009-08-03 16:12:17 +02005224 }
5225
5226 target_to_host_sigset_internal(&set, &target_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00005227 do_sigprocmask(SIG_SETMASK, &set, NULL);
Laurent Vivier492a8742009-08-03 16:12:17 +02005228
5229 /* restore registers */
5230
Riku Voipio016d2e12014-04-23 11:19:48 +03005231 restore_sigcontext(env, &frame->sc, &d0);
Laurent Vivier492a8742009-08-03 16:12:17 +02005232
5233 unlock_user_struct(frame, frame_addr, 0);
5234 return d0;
5235
5236badframe:
Laurent Vivier492a8742009-08-03 16:12:17 +02005237 force_sig(TARGET_SIGSEGV);
5238 return 0;
5239}
5240
Andreas Färber05390242012-02-25 03:37:53 +01005241long do_rt_sigreturn(CPUM68KState *env)
Laurent Vivier492a8742009-08-03 16:12:17 +02005242{
Laurent Vivier71811552009-08-03 16:12:18 +02005243 struct target_rt_sigframe *frame;
5244 abi_ulong frame_addr = env->aregs[7] - 4;
Anthony Liguoric227f092009-10-01 16:12:16 -05005245 target_sigset_t target_set;
Laurent Vivier71811552009-08-03 16:12:18 +02005246 sigset_t set;
5247 int d0;
5248
5249 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
5250 goto badframe;
5251
5252 target_to_host_sigset_internal(&set, &target_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00005253 do_sigprocmask(SIG_SETMASK, &set, NULL);
Laurent Vivier71811552009-08-03 16:12:18 +02005254
5255 /* restore registers */
5256
5257 if (target_rt_restore_ucontext(env, &frame->uc, &d0))
5258 goto badframe;
5259
5260 if (do_sigaltstack(frame_addr +
Aurelien Jarno60e99242010-03-29 02:12:51 +02005261 offsetof(struct target_rt_sigframe, uc.tuc_stack),
Laurent Vivier71811552009-08-03 16:12:18 +02005262 0, get_sp_from_cpustate(env)) == -EFAULT)
5263 goto badframe;
5264
5265 unlock_user_struct(frame, frame_addr, 0);
5266 return d0;
5267
5268badframe:
5269 unlock_user_struct(frame, frame_addr, 0);
5270 force_sig(TARGET_SIGSEGV);
5271 return 0;
Laurent Vivier492a8742009-08-03 16:12:17 +02005272}
5273
Richard Henderson6049f4f2009-12-27 18:30:03 -08005274#elif defined(TARGET_ALPHA)
5275
5276struct target_sigcontext {
5277 abi_long sc_onstack;
5278 abi_long sc_mask;
5279 abi_long sc_pc;
5280 abi_long sc_ps;
5281 abi_long sc_regs[32];
5282 abi_long sc_ownedfp;
5283 abi_long sc_fpregs[32];
5284 abi_ulong sc_fpcr;
5285 abi_ulong sc_fp_control;
5286 abi_ulong sc_reserved1;
5287 abi_ulong sc_reserved2;
5288 abi_ulong sc_ssize;
5289 abi_ulong sc_sbase;
5290 abi_ulong sc_traparg_a0;
5291 abi_ulong sc_traparg_a1;
5292 abi_ulong sc_traparg_a2;
5293 abi_ulong sc_fp_trap_pc;
5294 abi_ulong sc_fp_trigger_sum;
5295 abi_ulong sc_fp_trigger_inst;
5296};
5297
5298struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02005299 abi_ulong tuc_flags;
5300 abi_ulong tuc_link;
5301 abi_ulong tuc_osf_sigmask;
5302 target_stack_t tuc_stack;
5303 struct target_sigcontext tuc_mcontext;
5304 target_sigset_t tuc_sigmask;
Richard Henderson6049f4f2009-12-27 18:30:03 -08005305};
5306
5307struct target_sigframe {
5308 struct target_sigcontext sc;
5309 unsigned int retcode[3];
5310};
5311
5312struct target_rt_sigframe {
5313 target_siginfo_t info;
5314 struct target_ucontext uc;
5315 unsigned int retcode[3];
5316};
5317
5318#define INSN_MOV_R30_R16 0x47fe0410
5319#define INSN_LDI_R0 0x201f0000
5320#define INSN_CALLSYS 0x00000083
5321
Riku Voipio41ecc722014-04-23 11:01:00 +03005322static void setup_sigcontext(struct target_sigcontext *sc, CPUAlphaState *env,
Richard Henderson6049f4f2009-12-27 18:30:03 -08005323 abi_ulong frame_addr, target_sigset_t *set)
5324{
Riku Voipio41ecc722014-04-23 11:01:00 +03005325 int i;
Richard Henderson6049f4f2009-12-27 18:30:03 -08005326
Riku Voipio1d8b5122014-04-23 10:26:05 +03005327 __put_user(on_sig_stack(frame_addr), &sc->sc_onstack);
5328 __put_user(set->sig[0], &sc->sc_mask);
5329 __put_user(env->pc, &sc->sc_pc);
5330 __put_user(8, &sc->sc_ps);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005331
5332 for (i = 0; i < 31; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03005333 __put_user(env->ir[i], &sc->sc_regs[i]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005334 }
Riku Voipio1d8b5122014-04-23 10:26:05 +03005335 __put_user(0, &sc->sc_regs[31]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005336
5337 for (i = 0; i < 31; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03005338 __put_user(env->fir[i], &sc->sc_fpregs[i]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005339 }
Riku Voipio1d8b5122014-04-23 10:26:05 +03005340 __put_user(0, &sc->sc_fpregs[31]);
5341 __put_user(cpu_alpha_load_fpcr(env), &sc->sc_fpcr);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005342
Riku Voipio1d8b5122014-04-23 10:26:05 +03005343 __put_user(0, &sc->sc_traparg_a0); /* FIXME */
5344 __put_user(0, &sc->sc_traparg_a1); /* FIXME */
5345 __put_user(0, &sc->sc_traparg_a2); /* FIXME */
Richard Henderson6049f4f2009-12-27 18:30:03 -08005346}
5347
Riku Voipio016d2e12014-04-23 11:19:48 +03005348static void restore_sigcontext(CPUAlphaState *env,
Andreas Färber05390242012-02-25 03:37:53 +01005349 struct target_sigcontext *sc)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005350{
5351 uint64_t fpcr;
Riku Voipio016d2e12014-04-23 11:19:48 +03005352 int i;
Richard Henderson6049f4f2009-12-27 18:30:03 -08005353
Riku Voipio1d8b5122014-04-23 10:26:05 +03005354 __get_user(env->pc, &sc->sc_pc);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005355
5356 for (i = 0; i < 31; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03005357 __get_user(env->ir[i], &sc->sc_regs[i]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005358 }
5359 for (i = 0; i < 31; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03005360 __get_user(env->fir[i], &sc->sc_fpregs[i]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005361 }
5362
Riku Voipio1d8b5122014-04-23 10:26:05 +03005363 __get_user(fpcr, &sc->sc_fpcr);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005364 cpu_alpha_store_fpcr(env, fpcr);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005365}
5366
5367static inline abi_ulong get_sigframe(struct target_sigaction *sa,
Andreas Färber05390242012-02-25 03:37:53 +01005368 CPUAlphaState *env,
5369 unsigned long framesize)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005370{
5371 abi_ulong sp = env->ir[IR_SP];
5372
5373 /* This is the X/Open sanctioned signal stack switching. */
5374 if ((sa->sa_flags & TARGET_SA_ONSTACK) != 0 && !sas_ss_flags(sp)) {
5375 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
5376 }
5377 return (sp - framesize) & -32;
5378}
5379
5380static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01005381 target_sigset_t *set, CPUAlphaState *env)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005382{
5383 abi_ulong frame_addr, r26;
5384 struct target_sigframe *frame;
5385 int err = 0;
5386
5387 frame_addr = get_sigframe(ka, env, sizeof(*frame));
5388 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
5389 goto give_sigsegv;
5390 }
5391
Riku Voipio41ecc722014-04-23 11:01:00 +03005392 setup_sigcontext(&frame->sc, env, frame_addr, set);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005393
5394 if (ka->sa_restorer) {
5395 r26 = ka->sa_restorer;
5396 } else {
Riku Voipio1d8b5122014-04-23 10:26:05 +03005397 __put_user(INSN_MOV_R30_R16, &frame->retcode[0]);
5398 __put_user(INSN_LDI_R0 + TARGET_NR_sigreturn,
5399 &frame->retcode[1]);
5400 __put_user(INSN_CALLSYS, &frame->retcode[2]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005401 /* imb() */
5402 r26 = frame_addr;
5403 }
5404
5405 unlock_user_struct(frame, frame_addr, 1);
5406
5407 if (err) {
5408 give_sigsegv:
5409 if (sig == TARGET_SIGSEGV) {
5410 ka->_sa_handler = TARGET_SIG_DFL;
5411 }
5412 force_sig(TARGET_SIGSEGV);
5413 }
5414
5415 env->ir[IR_RA] = r26;
5416 env->ir[IR_PV] = env->pc = ka->_sa_handler;
5417 env->ir[IR_A0] = sig;
5418 env->ir[IR_A1] = 0;
5419 env->ir[IR_A2] = frame_addr + offsetof(struct target_sigframe, sc);
5420 env->ir[IR_SP] = frame_addr;
5421}
5422
5423static void setup_rt_frame(int sig, struct target_sigaction *ka,
5424 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01005425 target_sigset_t *set, CPUAlphaState *env)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005426{
5427 abi_ulong frame_addr, r26;
5428 struct target_rt_sigframe *frame;
5429 int i, err = 0;
5430
5431 frame_addr = get_sigframe(ka, env, sizeof(*frame));
5432 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
5433 goto give_sigsegv;
5434 }
5435
Riku Voipiob0fd8d12014-04-23 10:46:13 +03005436 copy_siginfo_to_user(&frame->info, info);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005437
Riku Voipio1d8b5122014-04-23 10:26:05 +03005438 __put_user(0, &frame->uc.tuc_flags);
5439 __put_user(0, &frame->uc.tuc_link);
5440 __put_user(set->sig[0], &frame->uc.tuc_osf_sigmask);
5441 __put_user(target_sigaltstack_used.ss_sp,
5442 &frame->uc.tuc_stack.ss_sp);
5443 __put_user(sas_ss_flags(env->ir[IR_SP]),
5444 &frame->uc.tuc_stack.ss_flags);
5445 __put_user(target_sigaltstack_used.ss_size,
5446 &frame->uc.tuc_stack.ss_size);
Riku Voipio41ecc722014-04-23 11:01:00 +03005447 setup_sigcontext(&frame->uc.tuc_mcontext, env, frame_addr, set);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005448 for (i = 0; i < TARGET_NSIG_WORDS; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03005449 __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005450 }
5451
5452 if (ka->sa_restorer) {
5453 r26 = ka->sa_restorer;
5454 } else {
Riku Voipio1d8b5122014-04-23 10:26:05 +03005455 __put_user(INSN_MOV_R30_R16, &frame->retcode[0]);
5456 __put_user(INSN_LDI_R0 + TARGET_NR_rt_sigreturn,
5457 &frame->retcode[1]);
5458 __put_user(INSN_CALLSYS, &frame->retcode[2]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005459 /* imb(); */
5460 r26 = frame_addr;
5461 }
5462
5463 if (err) {
5464 give_sigsegv:
5465 if (sig == TARGET_SIGSEGV) {
5466 ka->_sa_handler = TARGET_SIG_DFL;
5467 }
5468 force_sig(TARGET_SIGSEGV);
5469 }
5470
5471 env->ir[IR_RA] = r26;
5472 env->ir[IR_PV] = env->pc = ka->_sa_handler;
5473 env->ir[IR_A0] = sig;
5474 env->ir[IR_A1] = frame_addr + offsetof(struct target_rt_sigframe, info);
5475 env->ir[IR_A2] = frame_addr + offsetof(struct target_rt_sigframe, uc);
5476 env->ir[IR_SP] = frame_addr;
5477}
5478
Andreas Färber05390242012-02-25 03:37:53 +01005479long do_sigreturn(CPUAlphaState *env)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005480{
5481 struct target_sigcontext *sc;
5482 abi_ulong sc_addr = env->ir[IR_A0];
5483 target_sigset_t target_set;
5484 sigset_t set;
5485
5486 if (!lock_user_struct(VERIFY_READ, sc, sc_addr, 1)) {
5487 goto badframe;
5488 }
5489
5490 target_sigemptyset(&target_set);
Riku Voipiof5f601a2014-04-23 13:00:17 +03005491 __get_user(target_set.sig[0], &sc->sc_mask);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005492
5493 target_to_host_sigset_internal(&set, &target_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00005494 do_sigprocmask(SIG_SETMASK, &set, NULL);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005495
Riku Voipio016d2e12014-04-23 11:19:48 +03005496 restore_sigcontext(env, sc);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005497 unlock_user_struct(sc, sc_addr, 0);
5498 return env->ir[IR_V0];
5499
5500 badframe:
Richard Henderson6049f4f2009-12-27 18:30:03 -08005501 force_sig(TARGET_SIGSEGV);
5502}
5503
Andreas Färber05390242012-02-25 03:37:53 +01005504long do_rt_sigreturn(CPUAlphaState *env)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005505{
5506 abi_ulong frame_addr = env->ir[IR_A0];
5507 struct target_rt_sigframe *frame;
5508 sigset_t set;
5509
5510 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
5511 goto badframe;
5512 }
Aurelien Jarno60e99242010-03-29 02:12:51 +02005513 target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
Alex Barcelo1c275922014-03-14 14:36:55 +00005514 do_sigprocmask(SIG_SETMASK, &set, NULL);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005515
Riku Voipio016d2e12014-04-23 11:19:48 +03005516 restore_sigcontext(env, &frame->uc.tuc_mcontext);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005517 if (do_sigaltstack(frame_addr + offsetof(struct target_rt_sigframe,
Aurelien Jarno60e99242010-03-29 02:12:51 +02005518 uc.tuc_stack),
Richard Henderson6049f4f2009-12-27 18:30:03 -08005519 0, env->ir[IR_SP]) == -EFAULT) {
5520 goto badframe;
5521 }
5522
5523 unlock_user_struct(frame, frame_addr, 0);
5524 return env->ir[IR_V0];
5525
5526
5527 badframe:
5528 unlock_user_struct(frame, frame_addr, 0);
5529 force_sig(TARGET_SIGSEGV);
5530}
5531
bellardb346ff42003-06-15 20:05:50 +00005532#else
5533
pbrook624f7972008-05-31 16:11:38 +00005534static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber9349b4f2012-03-14 01:38:32 +01005535 target_sigset_t *set, CPUArchState *env)
bellardb346ff42003-06-15 20:05:50 +00005536{
5537 fprintf(stderr, "setup_frame: not implemented\n");
5538}
5539
pbrook624f7972008-05-31 16:11:38 +00005540static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05005541 target_siginfo_t *info,
Andreas Färber9349b4f2012-03-14 01:38:32 +01005542 target_sigset_t *set, CPUArchState *env)
bellardb346ff42003-06-15 20:05:50 +00005543{
5544 fprintf(stderr, "setup_rt_frame: not implemented\n");
5545}
5546
Andreas Färber9349b4f2012-03-14 01:38:32 +01005547long do_sigreturn(CPUArchState *env)
bellardb346ff42003-06-15 20:05:50 +00005548{
5549 fprintf(stderr, "do_sigreturn: not implemented\n");
bellardf8b0aa22007-11-11 23:03:42 +00005550 return -TARGET_ENOSYS;
bellardb346ff42003-06-15 20:05:50 +00005551}
5552
Andreas Färber9349b4f2012-03-14 01:38:32 +01005553long do_rt_sigreturn(CPUArchState *env)
bellardb346ff42003-06-15 20:05:50 +00005554{
5555 fprintf(stderr, "do_rt_sigreturn: not implemented\n");
bellardf8b0aa22007-11-11 23:03:42 +00005556 return -TARGET_ENOSYS;
bellardb346ff42003-06-15 20:05:50 +00005557}
5558
bellard66fb9762003-03-23 01:06:05 +00005559#endif
5560
Andreas Färber9349b4f2012-03-14 01:38:32 +01005561void process_pending_signals(CPUArchState *cpu_env)
bellard66fb9762003-03-23 01:06:05 +00005562{
Andreas Färberdb6b81d2013-06-27 19:49:31 +02005563 CPUState *cpu = ENV_GET_CPU(cpu_env);
bellard66fb9762003-03-23 01:06:05 +00005564 int sig;
blueswir1992f48a2007-10-14 16:27:31 +00005565 abi_ulong handler;
bellard9de5e442003-03-23 16:49:39 +00005566 sigset_t set, old_set;
Anthony Liguoric227f092009-10-01 16:12:16 -05005567 target_sigset_t target_old_set;
pbrook624f7972008-05-31 16:11:38 +00005568 struct emulated_sigtable *k;
5569 struct target_sigaction *sa;
bellard66fb9762003-03-23 01:06:05 +00005570 struct sigqueue *q;
Andreas Färber0429a972013-08-26 18:14:44 +02005571 TaskState *ts = cpu->opaque;
ths3b46e622007-09-17 08:09:54 +00005572
pbrook624f7972008-05-31 16:11:38 +00005573 if (!ts->signal_pending)
bellard31e31b82003-02-18 22:55:36 +00005574 return;
5575
pbrook624f7972008-05-31 16:11:38 +00005576 /* FIXME: This is not threadsafe. */
5577 k = ts->sigtab;
bellard66fb9762003-03-23 01:06:05 +00005578 for(sig = 1; sig <= TARGET_NSIG; sig++) {
5579 if (k->pending)
bellard31e31b82003-02-18 22:55:36 +00005580 goto handle_signal;
bellard66fb9762003-03-23 01:06:05 +00005581 k++;
bellard31e31b82003-02-18 22:55:36 +00005582 }
5583 /* if no signal is pending, just return */
pbrook624f7972008-05-31 16:11:38 +00005584 ts->signal_pending = 0;
bellard31e31b82003-02-18 22:55:36 +00005585 return;
bellard66fb9762003-03-23 01:06:05 +00005586
bellard31e31b82003-02-18 22:55:36 +00005587 handle_signal:
bellard66fb9762003-03-23 01:06:05 +00005588#ifdef DEBUG_SIGNAL
bellardbc8a22c2003-03-30 21:02:40 +00005589 fprintf(stderr, "qemu: process signal %d\n", sig);
bellard66fb9762003-03-23 01:06:05 +00005590#endif
5591 /* dequeue signal */
5592 q = k->first;
5593 k->first = q->next;
5594 if (!k->first)
5595 k->pending = 0;
ths3b46e622007-09-17 08:09:54 +00005596
Andreas Färberdb6b81d2013-06-27 19:49:31 +02005597 sig = gdb_handlesig(cpu, sig);
bellard1fddef42005-04-17 19:16:13 +00005598 if (!sig) {
aurel32ca587a82008-12-18 22:44:13 +00005599 sa = NULL;
5600 handler = TARGET_SIG_IGN;
5601 } else {
5602 sa = &sigact_table[sig - 1];
5603 handler = sa->_sa_handler;
bellard1fddef42005-04-17 19:16:13 +00005604 }
bellard66fb9762003-03-23 01:06:05 +00005605
Peter Maydella7ec0f92014-03-14 14:36:56 +00005606 if (ts->sigsegv_blocked && sig == TARGET_SIGSEGV) {
5607 /* Guest has blocked SIGSEGV but we got one anyway. Assume this
5608 * is a forced SIGSEGV (ie one the kernel handles via force_sig_info
5609 * because it got a real MMU fault), and treat as if default handler.
5610 */
5611 handler = TARGET_SIG_DFL;
5612 }
5613
bellard66fb9762003-03-23 01:06:05 +00005614 if (handler == TARGET_SIG_DFL) {
aurel32ca587a82008-12-18 22:44:13 +00005615 /* default handler : ignore some signal. The other are job control or fatal */
5616 if (sig == TARGET_SIGTSTP || sig == TARGET_SIGTTIN || sig == TARGET_SIGTTOU) {
5617 kill(getpid(),SIGSTOP);
5618 } else if (sig != TARGET_SIGCHLD &&
5619 sig != TARGET_SIGURG &&
5620 sig != TARGET_SIGWINCH &&
5621 sig != TARGET_SIGCONT) {
bellard66fb9762003-03-23 01:06:05 +00005622 force_sig(sig);
5623 }
5624 } else if (handler == TARGET_SIG_IGN) {
5625 /* ignore sig */
5626 } else if (handler == TARGET_SIG_ERR) {
5627 force_sig(sig);
5628 } else {
bellard9de5e442003-03-23 16:49:39 +00005629 /* compute the blocked signals during the handler execution */
pbrook624f7972008-05-31 16:11:38 +00005630 target_to_host_sigset(&set, &sa->sa_mask);
bellard9de5e442003-03-23 16:49:39 +00005631 /* SA_NODEFER indicates that the current signal should not be
5632 blocked during the handler */
pbrook624f7972008-05-31 16:11:38 +00005633 if (!(sa->sa_flags & TARGET_SA_NODEFER))
bellard9de5e442003-03-23 16:49:39 +00005634 sigaddset(&set, target_to_host_signal(sig));
ths3b46e622007-09-17 08:09:54 +00005635
bellard9de5e442003-03-23 16:49:39 +00005636 /* block signals in the handler using Linux */
Alex Barcelo1c275922014-03-14 14:36:55 +00005637 do_sigprocmask(SIG_BLOCK, &set, &old_set);
bellard9de5e442003-03-23 16:49:39 +00005638 /* save the previous blocked signal state to restore it at the
5639 end of the signal execution (see do_sigreturn) */
bellard92319442004-06-19 16:58:13 +00005640 host_to_target_sigset_internal(&target_old_set, &old_set);
bellard9de5e442003-03-23 16:49:39 +00005641
bellardbc8a22c2003-03-30 21:02:40 +00005642 /* if the CPU is in VM86 mode, we restore the 32 bit values */
j_mayer84409dd2007-04-06 08:56:50 +00005643#if defined(TARGET_I386) && !defined(TARGET_X86_64)
bellardbc8a22c2003-03-30 21:02:40 +00005644 {
5645 CPUX86State *env = cpu_env;
5646 if (env->eflags & VM_MASK)
5647 save_v86_state(env);
5648 }
5649#endif
bellard9de5e442003-03-23 16:49:39 +00005650 /* prepare the stack frame of the virtual CPU */
Richard Hendersonff970902013-02-10 10:30:42 -08005651#if defined(TARGET_ABI_MIPSN32) || defined(TARGET_ABI_MIPSN64)
5652 /* These targets do not have traditional signals. */
5653 setup_rt_frame(sig, sa, &q->info, &target_old_set, cpu_env);
5654#else
pbrook624f7972008-05-31 16:11:38 +00005655 if (sa->sa_flags & TARGET_SA_SIGINFO)
5656 setup_rt_frame(sig, sa, &q->info, &target_old_set, cpu_env);
bellard66fb9762003-03-23 01:06:05 +00005657 else
pbrook624f7972008-05-31 16:11:38 +00005658 setup_frame(sig, sa, &target_old_set, cpu_env);
Richard Hendersonff970902013-02-10 10:30:42 -08005659#endif
pbrook624f7972008-05-31 16:11:38 +00005660 if (sa->sa_flags & TARGET_SA_RESETHAND)
5661 sa->_sa_handler = TARGET_SIG_DFL;
bellard31e31b82003-02-18 22:55:36 +00005662 }
bellard66fb9762003-03-23 01:06:05 +00005663 if (q != &k->info)
pbrook624f7972008-05-31 16:11:38 +00005664 free_sigqueue(cpu_env, q);
bellard31e31b82003-02-18 22:55:36 +00005665}