blob: 2a1c681c7da349a8a134c80edb845bd46c17be96 [file] [log] [blame]
bellard31e31b82003-02-18 22:55:36 +00001/*
bellard66fb9762003-03-23 01:06:05 +00002 * Emulation of Linux signals
ths5fafdf22007-09-16 21:08:06 +00003 *
bellard31e31b82003-02-18 22:55:36 +00004 * Copyright (c) 2003 Fabrice Bellard
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
Blue Swirl8167ee82009-07-16 20:47:01 +000017 * along with this program; if not, see <http://www.gnu.org/licenses/>.
bellard31e31b82003-02-18 22:55:36 +000018 */
19#include <stdlib.h>
20#include <stdio.h>
bellard66fb9762003-03-23 01:06:05 +000021#include <string.h>
bellard31e31b82003-02-18 22:55:36 +000022#include <stdarg.h>
bellard2677e102003-04-10 00:03:27 +000023#include <unistd.h>
bellard66fb9762003-03-23 01:06:05 +000024#include <errno.h>
aurel32603e4fd2009-04-15 16:18:38 +000025#include <assert.h>
bellard31e31b82003-02-18 22:55:36 +000026#include <sys/ucontext.h>
Mika Westerbergedf8e2a2009-04-07 09:57:11 +030027#include <sys/resource.h>
bellard31e31b82003-02-18 22:55:36 +000028
bellard3ef693a2003-03-23 20:17:16 +000029#include "qemu.h"
blueswir17d99a002009-01-14 19:00:36 +000030#include "qemu-common.h"
blueswir1992f48a2007-10-14 16:27:31 +000031#include "target_signal.h"
bellard66fb9762003-03-23 01:06:05 +000032
33//#define DEBUG_SIGNAL
34
blueswir1249c4c32008-10-05 11:09:37 +000035static struct target_sigaltstack target_sigaltstack_used = {
thsa04e1342007-09-27 13:57:58 +000036 .ss_sp = 0,
37 .ss_size = 0,
38 .ss_flags = TARGET_SS_DISABLE,
39};
40
pbrook624f7972008-05-31 16:11:38 +000041static struct target_sigaction sigact_table[TARGET_NSIG];
bellard31e31b82003-02-18 22:55:36 +000042
ths5fafdf22007-09-16 21:08:06 +000043static void host_signal_handler(int host_signum, siginfo_t *info,
bellard66fb9762003-03-23 01:06:05 +000044 void *puc);
45
Arnaud Patard3ca05582009-03-30 01:18:20 +020046static uint8_t host_to_target_signal_table[_NSIG] = {
bellard9e5f5282003-07-13 17:33:54 +000047 [SIGHUP] = TARGET_SIGHUP,
48 [SIGINT] = TARGET_SIGINT,
49 [SIGQUIT] = TARGET_SIGQUIT,
50 [SIGILL] = TARGET_SIGILL,
51 [SIGTRAP] = TARGET_SIGTRAP,
52 [SIGABRT] = TARGET_SIGABRT,
bellard01e3b762003-09-30 21:10:14 +000053/* [SIGIOT] = TARGET_SIGIOT,*/
bellard9e5f5282003-07-13 17:33:54 +000054 [SIGBUS] = TARGET_SIGBUS,
55 [SIGFPE] = TARGET_SIGFPE,
56 [SIGKILL] = TARGET_SIGKILL,
57 [SIGUSR1] = TARGET_SIGUSR1,
58 [SIGSEGV] = TARGET_SIGSEGV,
59 [SIGUSR2] = TARGET_SIGUSR2,
60 [SIGPIPE] = TARGET_SIGPIPE,
61 [SIGALRM] = TARGET_SIGALRM,
62 [SIGTERM] = TARGET_SIGTERM,
63#ifdef SIGSTKFLT
64 [SIGSTKFLT] = TARGET_SIGSTKFLT,
65#endif
66 [SIGCHLD] = TARGET_SIGCHLD,
67 [SIGCONT] = TARGET_SIGCONT,
68 [SIGSTOP] = TARGET_SIGSTOP,
69 [SIGTSTP] = TARGET_SIGTSTP,
70 [SIGTTIN] = TARGET_SIGTTIN,
71 [SIGTTOU] = TARGET_SIGTTOU,
72 [SIGURG] = TARGET_SIGURG,
73 [SIGXCPU] = TARGET_SIGXCPU,
74 [SIGXFSZ] = TARGET_SIGXFSZ,
75 [SIGVTALRM] = TARGET_SIGVTALRM,
76 [SIGPROF] = TARGET_SIGPROF,
77 [SIGWINCH] = TARGET_SIGWINCH,
78 [SIGIO] = TARGET_SIGIO,
79 [SIGPWR] = TARGET_SIGPWR,
80 [SIGSYS] = TARGET_SIGSYS,
81 /* next signals stay the same */
pbrook624f7972008-05-31 16:11:38 +000082 /* Nasty hack: Reverse SIGRTMIN and SIGRTMAX to avoid overlap with
Dong Xu Wangb4916d72011-11-22 18:06:17 +080083 host libpthread signals. This assumes no one actually uses SIGRTMAX :-/
pbrook624f7972008-05-31 16:11:38 +000084 To fix this properly we need to do manual signal delivery multiplexed
85 over a single host signal. */
86 [__SIGRTMIN] = __SIGRTMAX,
87 [__SIGRTMAX] = __SIGRTMIN,
bellard9e5f5282003-07-13 17:33:54 +000088};
Arnaud Patard3ca05582009-03-30 01:18:20 +020089static uint8_t target_to_host_signal_table[_NSIG];
bellard9e5f5282003-07-13 17:33:54 +000090
thsa04e1342007-09-27 13:57:58 +000091static inline int on_sig_stack(unsigned long sp)
92{
93 return (sp - target_sigaltstack_used.ss_sp
94 < target_sigaltstack_used.ss_size);
95}
96
97static inline int sas_ss_flags(unsigned long sp)
98{
99 return (target_sigaltstack_used.ss_size == 0 ? SS_DISABLE
100 : on_sig_stack(sp) ? SS_ONSTACK : 0);
101}
102
pbrook1d9d8b52009-04-16 15:17:02 +0000103int host_to_target_signal(int sig)
bellard31e31b82003-02-18 22:55:36 +0000104{
Andreas Schwab167c50d2013-07-02 14:04:12 +0100105 if (sig < 0 || sig >= _NSIG)
pbrook4cb05962008-05-30 18:05:19 +0000106 return sig;
bellard9e5f5282003-07-13 17:33:54 +0000107 return host_to_target_signal_table[sig];
bellard31e31b82003-02-18 22:55:36 +0000108}
109
pbrook4cb05962008-05-30 18:05:19 +0000110int target_to_host_signal(int sig)
bellard31e31b82003-02-18 22:55:36 +0000111{
Andreas Schwab167c50d2013-07-02 14:04:12 +0100112 if (sig < 0 || sig >= _NSIG)
pbrook4cb05962008-05-30 18:05:19 +0000113 return sig;
bellard9e5f5282003-07-13 17:33:54 +0000114 return target_to_host_signal_table[sig];
bellard31e31b82003-02-18 22:55:36 +0000115}
116
Anthony Liguoric227f092009-10-01 16:12:16 -0500117static inline void target_sigemptyset(target_sigset_t *set)
pbrookf5545b52008-05-30 22:37:07 +0000118{
119 memset(set, 0, sizeof(*set));
120}
121
Anthony Liguoric227f092009-10-01 16:12:16 -0500122static inline void target_sigaddset(target_sigset_t *set, int signum)
pbrookf5545b52008-05-30 22:37:07 +0000123{
124 signum--;
125 abi_ulong mask = (abi_ulong)1 << (signum % TARGET_NSIG_BPW);
126 set->sig[signum / TARGET_NSIG_BPW] |= mask;
127}
128
Anthony Liguoric227f092009-10-01 16:12:16 -0500129static inline int target_sigismember(const target_sigset_t *set, int signum)
pbrookf5545b52008-05-30 22:37:07 +0000130{
131 signum--;
132 abi_ulong mask = (abi_ulong)1 << (signum % TARGET_NSIG_BPW);
133 return ((set->sig[signum / TARGET_NSIG_BPW] & mask) != 0);
134}
135
Anthony Liguoric227f092009-10-01 16:12:16 -0500136static void host_to_target_sigset_internal(target_sigset_t *d,
bellard92319442004-06-19 16:58:13 +0000137 const sigset_t *s)
bellard66fb9762003-03-23 01:06:05 +0000138{
139 int i;
pbrookf5545b52008-05-30 22:37:07 +0000140 target_sigemptyset(d);
141 for (i = 1; i <= TARGET_NSIG; i++) {
142 if (sigismember(s, i)) {
143 target_sigaddset(d, host_to_target_signal(i));
144 }
bellard9e5f5282003-07-13 17:33:54 +0000145 }
bellard66fb9762003-03-23 01:06:05 +0000146}
147
Anthony Liguoric227f092009-10-01 16:12:16 -0500148void host_to_target_sigset(target_sigset_t *d, const sigset_t *s)
bellard92319442004-06-19 16:58:13 +0000149{
Anthony Liguoric227f092009-10-01 16:12:16 -0500150 target_sigset_t d1;
bellard92319442004-06-19 16:58:13 +0000151 int i;
152
153 host_to_target_sigset_internal(&d1, s);
154 for(i = 0;i < TARGET_NSIG_WORDS; i++)
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200155 d->sig[i] = tswapal(d1.sig[i]);
bellard92319442004-06-19 16:58:13 +0000156}
157
blueswir18fcd3692008-08-17 20:26:25 +0000158static void target_to_host_sigset_internal(sigset_t *d,
Anthony Liguoric227f092009-10-01 16:12:16 -0500159 const target_sigset_t *s)
bellard66fb9762003-03-23 01:06:05 +0000160{
161 int i;
pbrookf5545b52008-05-30 22:37:07 +0000162 sigemptyset(d);
163 for (i = 1; i <= TARGET_NSIG; i++) {
164 if (target_sigismember(s, i)) {
165 sigaddset(d, target_to_host_signal(i));
166 }
167 }
bellard66fb9762003-03-23 01:06:05 +0000168}
169
Anthony Liguoric227f092009-10-01 16:12:16 -0500170void target_to_host_sigset(sigset_t *d, const target_sigset_t *s)
bellard92319442004-06-19 16:58:13 +0000171{
Anthony Liguoric227f092009-10-01 16:12:16 -0500172 target_sigset_t s1;
bellard92319442004-06-19 16:58:13 +0000173 int i;
174
175 for(i = 0;i < TARGET_NSIG_WORDS; i++)
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200176 s1.sig[i] = tswapal(s->sig[i]);
bellard92319442004-06-19 16:58:13 +0000177 target_to_host_sigset_internal(d, &s1);
178}
ths3b46e622007-09-17 08:09:54 +0000179
blueswir1992f48a2007-10-14 16:27:31 +0000180void host_to_target_old_sigset(abi_ulong *old_sigset,
bellard66fb9762003-03-23 01:06:05 +0000181 const sigset_t *sigset)
182{
Anthony Liguoric227f092009-10-01 16:12:16 -0500183 target_sigset_t d;
bellard9e5f5282003-07-13 17:33:54 +0000184 host_to_target_sigset(&d, sigset);
185 *old_sigset = d.sig[0];
bellard66fb9762003-03-23 01:06:05 +0000186}
187
ths5fafdf22007-09-16 21:08:06 +0000188void target_to_host_old_sigset(sigset_t *sigset,
blueswir1992f48a2007-10-14 16:27:31 +0000189 const abi_ulong *old_sigset)
bellard66fb9762003-03-23 01:06:05 +0000190{
Anthony Liguoric227f092009-10-01 16:12:16 -0500191 target_sigset_t d;
bellard9e5f5282003-07-13 17:33:54 +0000192 int i;
193
194 d.sig[0] = *old_sigset;
195 for(i = 1;i < TARGET_NSIG_WORDS; i++)
196 d.sig[i] = 0;
197 target_to_host_sigset(sigset, &d);
bellard66fb9762003-03-23 01:06:05 +0000198}
199
Alex Barcelo1c275922014-03-14 14:36:55 +0000200/* Wrapper for sigprocmask function
201 * Emulates a sigprocmask in a safe way for the guest. Note that set and oldset
202 * are host signal set, not guest ones. This wraps the sigprocmask host calls
203 * that should be protected (calls originated from guest)
204 */
205int do_sigprocmask(int how, const sigset_t *set, sigset_t *oldset)
206{
Peter Maydella7ec0f92014-03-14 14:36:56 +0000207 int ret;
208 sigset_t val;
209 sigset_t *temp = NULL;
210 CPUState *cpu = thread_cpu;
211 TaskState *ts = (TaskState *)cpu->opaque;
212 bool segv_was_blocked = ts->sigsegv_blocked;
213
214 if (set) {
215 bool has_sigsegv = sigismember(set, SIGSEGV);
216 val = *set;
217 temp = &val;
218
219 sigdelset(temp, SIGSEGV);
220
221 switch (how) {
222 case SIG_BLOCK:
223 if (has_sigsegv) {
224 ts->sigsegv_blocked = true;
225 }
226 break;
227 case SIG_UNBLOCK:
228 if (has_sigsegv) {
229 ts->sigsegv_blocked = false;
230 }
231 break;
232 case SIG_SETMASK:
233 ts->sigsegv_blocked = has_sigsegv;
234 break;
235 default:
236 g_assert_not_reached();
237 }
238 }
239
240 ret = sigprocmask(how, temp, oldset);
241
242 if (oldset && segv_was_blocked) {
243 sigaddset(oldset, SIGSEGV);
244 }
245
246 return ret;
Alex Barcelo1c275922014-03-14 14:36:55 +0000247}
248
bellard9de5e442003-03-23 16:49:39 +0000249/* siginfo conversion */
250
Anthony Liguoric227f092009-10-01 16:12:16 -0500251static inline void host_to_target_siginfo_noswap(target_siginfo_t *tinfo,
bellard9de5e442003-03-23 16:49:39 +0000252 const siginfo_t *info)
bellard66fb9762003-03-23 01:06:05 +0000253{
Richard Hendersona05c6402012-09-15 11:34:20 -0700254 int sig = host_to_target_signal(info->si_signo);
bellard9de5e442003-03-23 16:49:39 +0000255 tinfo->si_signo = sig;
256 tinfo->si_errno = 0;
pbrookafd7cd92008-05-31 12:14:21 +0000257 tinfo->si_code = info->si_code;
Richard Hendersona05c6402012-09-15 11:34:20 -0700258
259 if (sig == TARGET_SIGILL || sig == TARGET_SIGFPE || sig == TARGET_SIGSEGV
260 || sig == TARGET_SIGBUS || sig == TARGET_SIGTRAP) {
261 /* Should never come here, but who knows. The information for
262 the target is irrelevant. */
bellard9de5e442003-03-23 16:49:39 +0000263 tinfo->_sifields._sigfault._addr = 0;
Richard Hendersona05c6402012-09-15 11:34:20 -0700264 } else if (sig == TARGET_SIGIO) {
265 tinfo->_sifields._sigpoll._band = info->si_band;
ths7f7f7c82007-07-12 11:02:46 +0000266 tinfo->_sifields._sigpoll._fd = info->si_fd;
Richard Hendersona05c6402012-09-15 11:34:20 -0700267 } else if (sig == TARGET_SIGCHLD) {
268 tinfo->_sifields._sigchld._pid = info->si_pid;
269 tinfo->_sifields._sigchld._uid = info->si_uid;
270 tinfo->_sifields._sigchld._status
271 = host_to_target_waitstatus(info->si_status);
272 tinfo->_sifields._sigchld._utime = info->si_utime;
273 tinfo->_sifields._sigchld._stime = info->si_stime;
bellard9de5e442003-03-23 16:49:39 +0000274 } else if (sig >= TARGET_SIGRTMIN) {
275 tinfo->_sifields._rt._pid = info->si_pid;
276 tinfo->_sifields._rt._uid = info->si_uid;
277 /* XXX: potential problem if 64 bit */
Richard Hendersona05c6402012-09-15 11:34:20 -0700278 tinfo->_sifields._rt._sigval.sival_ptr
279 = (abi_ulong)(unsigned long)info->si_value.sival_ptr;
bellard9de5e442003-03-23 16:49:39 +0000280 }
bellard66fb9762003-03-23 01:06:05 +0000281}
282
Anthony Liguoric227f092009-10-01 16:12:16 -0500283static void tswap_siginfo(target_siginfo_t *tinfo,
284 const target_siginfo_t *info)
bellard9de5e442003-03-23 16:49:39 +0000285{
Richard Hendersona05c6402012-09-15 11:34:20 -0700286 int sig = info->si_signo;
bellard9de5e442003-03-23 16:49:39 +0000287 tinfo->si_signo = tswap32(sig);
288 tinfo->si_errno = tswap32(info->si_errno);
289 tinfo->si_code = tswap32(info->si_code);
Richard Hendersona05c6402012-09-15 11:34:20 -0700290
291 if (sig == TARGET_SIGILL || sig == TARGET_SIGFPE || sig == TARGET_SIGSEGV
292 || sig == TARGET_SIGBUS || sig == TARGET_SIGTRAP) {
293 tinfo->_sifields._sigfault._addr
294 = tswapal(info->_sifields._sigfault._addr);
295 } else if (sig == TARGET_SIGIO) {
296 tinfo->_sifields._sigpoll._band
297 = tswap32(info->_sifields._sigpoll._band);
298 tinfo->_sifields._sigpoll._fd = tswap32(info->_sifields._sigpoll._fd);
299 } else if (sig == TARGET_SIGCHLD) {
300 tinfo->_sifields._sigchld._pid
301 = tswap32(info->_sifields._sigchld._pid);
302 tinfo->_sifields._sigchld._uid
303 = tswap32(info->_sifields._sigchld._uid);
304 tinfo->_sifields._sigchld._status
305 = tswap32(info->_sifields._sigchld._status);
306 tinfo->_sifields._sigchld._utime
307 = tswapal(info->_sifields._sigchld._utime);
308 tinfo->_sifields._sigchld._stime
309 = tswapal(info->_sifields._sigchld._stime);
bellard9de5e442003-03-23 16:49:39 +0000310 } else if (sig >= TARGET_SIGRTMIN) {
311 tinfo->_sifields._rt._pid = tswap32(info->_sifields._rt._pid);
312 tinfo->_sifields._rt._uid = tswap32(info->_sifields._rt._uid);
Richard Hendersona05c6402012-09-15 11:34:20 -0700313 tinfo->_sifields._rt._sigval.sival_ptr
314 = tswapal(info->_sifields._rt._sigval.sival_ptr);
bellard9de5e442003-03-23 16:49:39 +0000315 }
316}
317
318
Anthony Liguoric227f092009-10-01 16:12:16 -0500319void host_to_target_siginfo(target_siginfo_t *tinfo, const siginfo_t *info)
bellard9de5e442003-03-23 16:49:39 +0000320{
321 host_to_target_siginfo_noswap(tinfo, info);
322 tswap_siginfo(tinfo, tinfo);
323}
324
325/* XXX: we support only POSIX RT signals are used. */
thsaa1f17c2007-07-11 22:48:58 +0000326/* XXX: find a solution for 64 bit (additional malloced data is needed) */
Anthony Liguoric227f092009-10-01 16:12:16 -0500327void target_to_host_siginfo(siginfo_t *info, const target_siginfo_t *tinfo)
bellard66fb9762003-03-23 01:06:05 +0000328{
329 info->si_signo = tswap32(tinfo->si_signo);
330 info->si_errno = tswap32(tinfo->si_errno);
331 info->si_code = tswap32(tinfo->si_code);
bellard9de5e442003-03-23 16:49:39 +0000332 info->si_pid = tswap32(tinfo->_sifields._rt._pid);
333 info->si_uid = tswap32(tinfo->_sifields._rt._uid);
ths5fafdf22007-09-16 21:08:06 +0000334 info->si_value.sival_ptr =
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200335 (void *)(long)tswapal(tinfo->_sifields._rt._sigval.sival_ptr);
bellard66fb9762003-03-23 01:06:05 +0000336}
337
aurel32ca587a82008-12-18 22:44:13 +0000338static int fatal_signal (int sig)
339{
340 switch (sig) {
341 case TARGET_SIGCHLD:
342 case TARGET_SIGURG:
343 case TARGET_SIGWINCH:
344 /* Ignored by default. */
345 return 0;
346 case TARGET_SIGCONT:
347 case TARGET_SIGSTOP:
348 case TARGET_SIGTSTP:
349 case TARGET_SIGTTIN:
350 case TARGET_SIGTTOU:
351 /* Job control signals. */
352 return 0;
353 default:
354 return 1;
355 }
356}
357
Mika Westerbergedf8e2a2009-04-07 09:57:11 +0300358/* returns 1 if given signal should dump core if not handled */
359static int core_dump_signal(int sig)
360{
361 switch (sig) {
362 case TARGET_SIGABRT:
363 case TARGET_SIGFPE:
364 case TARGET_SIGILL:
365 case TARGET_SIGQUIT:
366 case TARGET_SIGSEGV:
367 case TARGET_SIGTRAP:
368 case TARGET_SIGBUS:
369 return (1);
370 default:
371 return (0);
372 }
373}
374
bellard31e31b82003-02-18 22:55:36 +0000375void signal_init(void)
376{
377 struct sigaction act;
pbrook624f7972008-05-31 16:11:38 +0000378 struct sigaction oact;
bellard9e5f5282003-07-13 17:33:54 +0000379 int i, j;
pbrook624f7972008-05-31 16:11:38 +0000380 int host_sig;
bellard31e31b82003-02-18 22:55:36 +0000381
bellard9e5f5282003-07-13 17:33:54 +0000382 /* generate signal conversion tables */
Arnaud Patard3ca05582009-03-30 01:18:20 +0200383 for(i = 1; i < _NSIG; i++) {
bellard9e5f5282003-07-13 17:33:54 +0000384 if (host_to_target_signal_table[i] == 0)
385 host_to_target_signal_table[i] = i;
386 }
Arnaud Patard3ca05582009-03-30 01:18:20 +0200387 for(i = 1; i < _NSIG; i++) {
bellard9e5f5282003-07-13 17:33:54 +0000388 j = host_to_target_signal_table[i];
389 target_to_host_signal_table[j] = i;
390 }
ths3b46e622007-09-17 08:09:54 +0000391
bellard9de5e442003-03-23 16:49:39 +0000392 /* set all host signal handlers. ALL signals are blocked during
393 the handlers to serialize them. */
pbrook624f7972008-05-31 16:11:38 +0000394 memset(sigact_table, 0, sizeof(sigact_table));
395
bellard9de5e442003-03-23 16:49:39 +0000396 sigfillset(&act.sa_mask);
bellard31e31b82003-02-18 22:55:36 +0000397 act.sa_flags = SA_SIGINFO;
398 act.sa_sigaction = host_signal_handler;
pbrook624f7972008-05-31 16:11:38 +0000399 for(i = 1; i <= TARGET_NSIG; i++) {
400 host_sig = target_to_host_signal(i);
401 sigaction(host_sig, NULL, &oact);
402 if (oact.sa_sigaction == (void *)SIG_IGN) {
403 sigact_table[i - 1]._sa_handler = TARGET_SIG_IGN;
404 } else if (oact.sa_sigaction == (void *)SIG_DFL) {
405 sigact_table[i - 1]._sa_handler = TARGET_SIG_DFL;
406 }
407 /* If there's already a handler installed then something has
408 gone horribly wrong, so don't even try to handle that case. */
aurel32ca587a82008-12-18 22:44:13 +0000409 /* Install some handlers for our own use. We need at least
410 SIGSEGV and SIGBUS, to detect exceptions. We can not just
411 trap all signals because it affects syscall interrupt
412 behavior. But do trap all default-fatal signals. */
413 if (fatal_signal (i))
pbrook624f7972008-05-31 16:11:38 +0000414 sigaction(host_sig, &act, NULL);
bellard31e31b82003-02-18 22:55:36 +0000415 }
bellard31e31b82003-02-18 22:55:36 +0000416}
417
bellard66fb9762003-03-23 01:06:05 +0000418/* signal queue handling */
419
Andreas Färber9349b4f2012-03-14 01:38:32 +0100420static inline struct sigqueue *alloc_sigqueue(CPUArchState *env)
bellard66fb9762003-03-23 01:06:05 +0000421{
Andreas Färber0429a972013-08-26 18:14:44 +0200422 CPUState *cpu = ENV_GET_CPU(env);
423 TaskState *ts = cpu->opaque;
pbrook624f7972008-05-31 16:11:38 +0000424 struct sigqueue *q = ts->first_free;
bellard66fb9762003-03-23 01:06:05 +0000425 if (!q)
426 return NULL;
pbrook624f7972008-05-31 16:11:38 +0000427 ts->first_free = q->next;
bellard66fb9762003-03-23 01:06:05 +0000428 return q;
429}
430
Andreas Färber9349b4f2012-03-14 01:38:32 +0100431static inline void free_sigqueue(CPUArchState *env, struct sigqueue *q)
bellard66fb9762003-03-23 01:06:05 +0000432{
Andreas Färber0429a972013-08-26 18:14:44 +0200433 CPUState *cpu = ENV_GET_CPU(env);
434 TaskState *ts = cpu->opaque;
435
pbrook624f7972008-05-31 16:11:38 +0000436 q->next = ts->first_free;
437 ts->first_free = q;
bellard66fb9762003-03-23 01:06:05 +0000438}
439
bellard9de5e442003-03-23 16:49:39 +0000440/* abort execution with signal */
Riku Voipio66393fb2009-12-04 15:16:32 +0200441static void QEMU_NORETURN force_sig(int target_sig)
bellard66fb9762003-03-23 01:06:05 +0000442{
Andreas Färber0429a972013-08-26 18:14:44 +0200443 CPUState *cpu = thread_cpu;
444 CPUArchState *env = cpu->env_ptr;
445 TaskState *ts = (TaskState *)cpu->opaque;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +0300446 int host_sig, core_dumped = 0;
aurel32603e4fd2009-04-15 16:18:38 +0000447 struct sigaction act;
Riku Voipio66393fb2009-12-04 15:16:32 +0200448 host_sig = target_to_host_signal(target_sig);
Andreas Färbera2247f82013-06-09 19:47:04 +0200449 gdb_signalled(env, target_sig);
aurel32603e4fd2009-04-15 16:18:38 +0000450
Mika Westerbergedf8e2a2009-04-07 09:57:11 +0300451 /* dump core if supported by target binary format */
Riku Voipio66393fb2009-12-04 15:16:32 +0200452 if (core_dump_signal(target_sig) && (ts->bprm->core_dump != NULL)) {
Mika Westerbergedf8e2a2009-04-07 09:57:11 +0300453 stop_all_tasks();
454 core_dumped =
Andreas Färbera2247f82013-06-09 19:47:04 +0200455 ((*ts->bprm->core_dump)(target_sig, env) == 0);
Mika Westerbergedf8e2a2009-04-07 09:57:11 +0300456 }
457 if (core_dumped) {
458 /* we already dumped the core of target process, we don't want
459 * a coredump of qemu itself */
460 struct rlimit nodump;
461 getrlimit(RLIMIT_CORE, &nodump);
462 nodump.rlim_cur=0;
463 setrlimit(RLIMIT_CORE, &nodump);
464 (void) fprintf(stderr, "qemu: uncaught target signal %d (%s) - %s\n",
Riku Voipio66393fb2009-12-04 15:16:32 +0200465 target_sig, strsignal(host_sig), "core dumped" );
Mika Westerbergedf8e2a2009-04-07 09:57:11 +0300466 }
467
Stefan Weil0c587512011-04-28 17:20:32 +0200468 /* The proper exit code for dying from an uncaught signal is
aurel32603e4fd2009-04-15 16:18:38 +0000469 * -<signal>. The kernel doesn't allow exit() or _exit() to pass
470 * a negative value. To get the proper exit code we need to
471 * actually die from an uncaught signal. Here the default signal
472 * handler is installed, we send ourself a signal and we wait for
473 * it to arrive. */
474 sigfillset(&act.sa_mask);
475 act.sa_handler = SIG_DFL;
Peter Maydell3a5d30b2014-02-17 18:55:32 +0000476 act.sa_flags = 0;
aurel32603e4fd2009-04-15 16:18:38 +0000477 sigaction(host_sig, &act, NULL);
478
479 /* For some reason raise(host_sig) doesn't send the signal when
480 * statically linked on x86-64. */
481 kill(getpid(), host_sig);
482
483 /* Make sure the signal isn't masked (just reuse the mask inside
484 of act) */
485 sigdelset(&act.sa_mask, host_sig);
486 sigsuspend(&act.sa_mask);
487
488 /* unreachable */
Blue Swirla6c6f762010-03-13 14:18:50 +0000489 abort();
bellard66fb9762003-03-23 01:06:05 +0000490}
491
bellard9de5e442003-03-23 16:49:39 +0000492/* queue a signal so that it will be send to the virtual CPU as soon
493 as possible */
Andreas Färber9349b4f2012-03-14 01:38:32 +0100494int queue_signal(CPUArchState *env, int sig, target_siginfo_t *info)
bellard31e31b82003-02-18 22:55:36 +0000495{
Andreas Färber0429a972013-08-26 18:14:44 +0200496 CPUState *cpu = ENV_GET_CPU(env);
497 TaskState *ts = cpu->opaque;
pbrook624f7972008-05-31 16:11:38 +0000498 struct emulated_sigtable *k;
bellard9de5e442003-03-23 16:49:39 +0000499 struct sigqueue *q, **pq;
blueswir1992f48a2007-10-14 16:27:31 +0000500 abi_ulong handler;
aurel32ca587a82008-12-18 22:44:13 +0000501 int queue;
bellard66fb9762003-03-23 01:06:05 +0000502
bellard9de5e442003-03-23 16:49:39 +0000503#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000504 fprintf(stderr, "queue_signal: sig=%d\n",
bellard9de5e442003-03-23 16:49:39 +0000505 sig);
bellard66fb9762003-03-23 01:06:05 +0000506#endif
pbrook624f7972008-05-31 16:11:38 +0000507 k = &ts->sigtab[sig - 1];
aurel32ca587a82008-12-18 22:44:13 +0000508 queue = gdb_queuesig ();
pbrook624f7972008-05-31 16:11:38 +0000509 handler = sigact_table[sig - 1]._sa_handler;
Peter Maydella7ec0f92014-03-14 14:36:56 +0000510
511 if (ts->sigsegv_blocked && sig == TARGET_SIGSEGV) {
512 /* Guest has blocked SIGSEGV but we got one anyway. Assume this
513 * is a forced SIGSEGV (ie one the kernel handles via force_sig_info
514 * because it got a real MMU fault). A blocked SIGSEGV in that
515 * situation is treated as if using the default handler. This is
516 * not correct if some other process has randomly sent us a SIGSEGV
517 * via kill(), but that is not easy to distinguish at this point,
518 * so we assume it doesn't happen.
519 */
520 handler = TARGET_SIG_DFL;
521 }
522
aurel32ca587a82008-12-18 22:44:13 +0000523 if (!queue && handler == TARGET_SIG_DFL) {
ths60b19692008-11-27 15:47:15 +0000524 if (sig == TARGET_SIGTSTP || sig == TARGET_SIGTTIN || sig == TARGET_SIGTTOU) {
525 kill(getpid(),SIGSTOP);
526 return 0;
527 } else
bellard66fb9762003-03-23 01:06:05 +0000528 /* default handler : ignore some signal. The other are fatal */
ths5fafdf22007-09-16 21:08:06 +0000529 if (sig != TARGET_SIGCHLD &&
530 sig != TARGET_SIGURG &&
ths60b19692008-11-27 15:47:15 +0000531 sig != TARGET_SIGWINCH &&
532 sig != TARGET_SIGCONT) {
bellard66fb9762003-03-23 01:06:05 +0000533 force_sig(sig);
bellard9de5e442003-03-23 16:49:39 +0000534 } else {
535 return 0; /* indicate ignored */
bellard66fb9762003-03-23 01:06:05 +0000536 }
aurel32ca587a82008-12-18 22:44:13 +0000537 } else if (!queue && handler == TARGET_SIG_IGN) {
bellard66fb9762003-03-23 01:06:05 +0000538 /* ignore signal */
bellard9de5e442003-03-23 16:49:39 +0000539 return 0;
aurel32ca587a82008-12-18 22:44:13 +0000540 } else if (!queue && handler == TARGET_SIG_ERR) {
bellard66fb9762003-03-23 01:06:05 +0000541 force_sig(sig);
542 } else {
bellard9de5e442003-03-23 16:49:39 +0000543 pq = &k->first;
544 if (sig < TARGET_SIGRTMIN) {
545 /* if non real time signal, we queue exactly one signal */
546 if (!k->pending)
547 q = &k->info;
548 else
549 return 0;
550 } else {
551 if (!k->pending) {
552 /* first signal */
553 q = &k->info;
554 } else {
pbrook624f7972008-05-31 16:11:38 +0000555 q = alloc_sigqueue(env);
bellard9de5e442003-03-23 16:49:39 +0000556 if (!q)
557 return -EAGAIN;
558 while (*pq != NULL)
559 pq = &(*pq)->next;
560 }
561 }
562 *pq = q;
563 q->info = *info;
564 q->next = NULL;
565 k->pending = 1;
566 /* signal that a new signal is pending */
pbrook624f7972008-05-31 16:11:38 +0000567 ts->signal_pending = 1;
bellard9de5e442003-03-23 16:49:39 +0000568 return 1; /* indicates that the signal was queued */
569 }
570}
571
ths5fafdf22007-09-16 21:08:06 +0000572static void host_signal_handler(int host_signum, siginfo_t *info,
bellard9de5e442003-03-23 16:49:39 +0000573 void *puc)
574{
Andreas Färbera2247f82013-06-09 19:47:04 +0200575 CPUArchState *env = thread_cpu->env_ptr;
bellard9de5e442003-03-23 16:49:39 +0000576 int sig;
Anthony Liguoric227f092009-10-01 16:12:16 -0500577 target_siginfo_t tinfo;
bellard9de5e442003-03-23 16:49:39 +0000578
579 /* the CPU emulator uses some host signals to detect exceptions,
aurel32eaa449b2009-01-03 13:14:52 +0000580 we forward to it some signals */
aurel32ca587a82008-12-18 22:44:13 +0000581 if ((host_signum == SIGSEGV || host_signum == SIGBUS)
aurel32eaa449b2009-01-03 13:14:52 +0000582 && info->si_code > 0) {
bellardb346ff42003-06-15 20:05:50 +0000583 if (cpu_signal_handler(host_signum, info, puc))
bellard9de5e442003-03-23 16:49:39 +0000584 return;
585 }
586
587 /* get target signal number */
588 sig = host_to_target_signal(host_signum);
589 if (sig < 1 || sig > TARGET_NSIG)
590 return;
591#if defined(DEBUG_SIGNAL)
bellardbc8a22c2003-03-30 21:02:40 +0000592 fprintf(stderr, "qemu: got signal %d\n", sig);
bellard9de5e442003-03-23 16:49:39 +0000593#endif
594 host_to_target_siginfo_noswap(&tinfo, info);
Andreas Färbera2247f82013-06-09 19:47:04 +0200595 if (queue_signal(env, sig, &tinfo) == 1) {
bellard9de5e442003-03-23 16:49:39 +0000596 /* interrupt the virtual CPU as soon as possible */
Andreas Färbera2247f82013-06-09 19:47:04 +0200597 cpu_exit(thread_cpu);
bellard66fb9762003-03-23 01:06:05 +0000598 }
bellard31e31b82003-02-18 22:55:36 +0000599}
600
ths0da46a62007-10-20 20:23:07 +0000601/* do_sigaltstack() returns target values and errnos. */
bellard579a97f2007-11-11 14:26:47 +0000602/* compare linux/kernel/signal.c:do_sigaltstack() */
603abi_long do_sigaltstack(abi_ulong uss_addr, abi_ulong uoss_addr, abi_ulong sp)
thsa04e1342007-09-27 13:57:58 +0000604{
605 int ret;
606 struct target_sigaltstack oss;
607
608 /* XXX: test errors */
bellard579a97f2007-11-11 14:26:47 +0000609 if(uoss_addr)
thsa04e1342007-09-27 13:57:58 +0000610 {
611 __put_user(target_sigaltstack_used.ss_sp, &oss.ss_sp);
612 __put_user(target_sigaltstack_used.ss_size, &oss.ss_size);
613 __put_user(sas_ss_flags(sp), &oss.ss_flags);
614 }
615
bellard579a97f2007-11-11 14:26:47 +0000616 if(uss_addr)
thsa04e1342007-09-27 13:57:58 +0000617 {
bellard579a97f2007-11-11 14:26:47 +0000618 struct target_sigaltstack *uss;
619 struct target_sigaltstack ss;
thsa04e1342007-09-27 13:57:58 +0000620
ths0da46a62007-10-20 20:23:07 +0000621 ret = -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +0000622 if (!lock_user_struct(VERIFY_READ, uss, uss_addr, 1)
thsa04e1342007-09-27 13:57:58 +0000623 || __get_user(ss.ss_sp, &uss->ss_sp)
624 || __get_user(ss.ss_size, &uss->ss_size)
625 || __get_user(ss.ss_flags, &uss->ss_flags))
626 goto out;
bellard579a97f2007-11-11 14:26:47 +0000627 unlock_user_struct(uss, uss_addr, 0);
thsa04e1342007-09-27 13:57:58 +0000628
ths0da46a62007-10-20 20:23:07 +0000629 ret = -TARGET_EPERM;
thsa04e1342007-09-27 13:57:58 +0000630 if (on_sig_stack(sp))
631 goto out;
632
ths0da46a62007-10-20 20:23:07 +0000633 ret = -TARGET_EINVAL;
thsa04e1342007-09-27 13:57:58 +0000634 if (ss.ss_flags != TARGET_SS_DISABLE
635 && ss.ss_flags != TARGET_SS_ONSTACK
636 && ss.ss_flags != 0)
637 goto out;
638
639 if (ss.ss_flags == TARGET_SS_DISABLE) {
640 ss.ss_size = 0;
641 ss.ss_sp = 0;
642 } else {
ths0da46a62007-10-20 20:23:07 +0000643 ret = -TARGET_ENOMEM;
thsa04e1342007-09-27 13:57:58 +0000644 if (ss.ss_size < MINSIGSTKSZ)
645 goto out;
646 }
647
648 target_sigaltstack_used.ss_sp = ss.ss_sp;
649 target_sigaltstack_used.ss_size = ss.ss_size;
650 }
651
bellard579a97f2007-11-11 14:26:47 +0000652 if (uoss_addr) {
ths0da46a62007-10-20 20:23:07 +0000653 ret = -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +0000654 if (copy_to_user(uoss_addr, &oss, sizeof(oss)))
thsa04e1342007-09-27 13:57:58 +0000655 goto out;
thsa04e1342007-09-27 13:57:58 +0000656 }
657
658 ret = 0;
659out:
660 return ret;
661}
662
ths0da46a62007-10-20 20:23:07 +0000663/* do_sigaction() return host values and errnos */
bellard66fb9762003-03-23 01:06:05 +0000664int do_sigaction(int sig, const struct target_sigaction *act,
665 struct target_sigaction *oact)
bellard31e31b82003-02-18 22:55:36 +0000666{
pbrook624f7972008-05-31 16:11:38 +0000667 struct target_sigaction *k;
bellard773b93e2004-01-04 17:15:59 +0000668 struct sigaction act1;
669 int host_sig;
ths0da46a62007-10-20 20:23:07 +0000670 int ret = 0;
bellard31e31b82003-02-18 22:55:36 +0000671
ths2a913eb2008-11-27 15:46:25 +0000672 if (sig < 1 || sig > TARGET_NSIG || sig == TARGET_SIGKILL || sig == TARGET_SIGSTOP)
bellard66fb9762003-03-23 01:06:05 +0000673 return -EINVAL;
674 k = &sigact_table[sig - 1];
bellard773b93e2004-01-04 17:15:59 +0000675#if defined(DEBUG_SIGNAL)
Blue Swirl0bf9e312009-07-20 17:19:25 +0000676 fprintf(stderr, "sigaction sig=%d act=0x%p, oact=0x%p\n",
677 sig, act, oact);
bellard66fb9762003-03-23 01:06:05 +0000678#endif
679 if (oact) {
Richard Hendersond2565872013-01-04 16:39:32 -0800680 __put_user(k->_sa_handler, &oact->_sa_handler);
681 __put_user(k->sa_flags, &oact->sa_flags);
ths388bb212007-05-13 13:58:00 +0000682#if !defined(TARGET_MIPS)
Richard Hendersond2565872013-01-04 16:39:32 -0800683 __put_user(k->sa_restorer, &oact->sa_restorer);
ths388bb212007-05-13 13:58:00 +0000684#endif
Richard Hendersond2565872013-01-04 16:39:32 -0800685 /* Not swapped. */
pbrook624f7972008-05-31 16:11:38 +0000686 oact->sa_mask = k->sa_mask;
bellard66fb9762003-03-23 01:06:05 +0000687 }
688 if (act) {
pbrook624f7972008-05-31 16:11:38 +0000689 /* FIXME: This is not threadsafe. */
Richard Hendersond2565872013-01-04 16:39:32 -0800690 __get_user(k->_sa_handler, &act->_sa_handler);
691 __get_user(k->sa_flags, &act->sa_flags);
ths388bb212007-05-13 13:58:00 +0000692#if !defined(TARGET_MIPS)
Richard Hendersond2565872013-01-04 16:39:32 -0800693 __get_user(k->sa_restorer, &act->sa_restorer);
ths388bb212007-05-13 13:58:00 +0000694#endif
Richard Hendersond2565872013-01-04 16:39:32 -0800695 /* To be swapped in target_to_host_sigset. */
pbrook624f7972008-05-31 16:11:38 +0000696 k->sa_mask = act->sa_mask;
bellard773b93e2004-01-04 17:15:59 +0000697
698 /* we update the host linux signal state */
699 host_sig = target_to_host_signal(sig);
700 if (host_sig != SIGSEGV && host_sig != SIGBUS) {
701 sigfillset(&act1.sa_mask);
702 act1.sa_flags = SA_SIGINFO;
pbrook624f7972008-05-31 16:11:38 +0000703 if (k->sa_flags & TARGET_SA_RESTART)
bellard773b93e2004-01-04 17:15:59 +0000704 act1.sa_flags |= SA_RESTART;
705 /* NOTE: it is important to update the host kernel signal
706 ignore state to avoid getting unexpected interrupted
707 syscalls */
pbrook624f7972008-05-31 16:11:38 +0000708 if (k->_sa_handler == TARGET_SIG_IGN) {
bellard773b93e2004-01-04 17:15:59 +0000709 act1.sa_sigaction = (void *)SIG_IGN;
pbrook624f7972008-05-31 16:11:38 +0000710 } else if (k->_sa_handler == TARGET_SIG_DFL) {
aurel32ca587a82008-12-18 22:44:13 +0000711 if (fatal_signal (sig))
712 act1.sa_sigaction = host_signal_handler;
713 else
714 act1.sa_sigaction = (void *)SIG_DFL;
bellard773b93e2004-01-04 17:15:59 +0000715 } else {
716 act1.sa_sigaction = host_signal_handler;
717 }
ths0da46a62007-10-20 20:23:07 +0000718 ret = sigaction(host_sig, &act1, NULL);
bellard773b93e2004-01-04 17:15:59 +0000719 }
bellard66fb9762003-03-23 01:06:05 +0000720 }
ths0da46a62007-10-20 20:23:07 +0000721 return ret;
bellard66fb9762003-03-23 01:06:05 +0000722}
bellard31e31b82003-02-18 22:55:36 +0000723
Riku Voipiob0fd8d12014-04-23 10:46:13 +0300724static inline void copy_siginfo_to_user(target_siginfo_t *tinfo,
Anthony Liguoric227f092009-10-01 16:12:16 -0500725 const target_siginfo_t *info)
bellard43fff232003-07-09 19:31:39 +0000726{
727 tswap_siginfo(tinfo, info);
bellard43fff232003-07-09 19:31:39 +0000728}
729
thsc3b5bc82007-12-02 06:31:25 +0000730static inline int current_exec_domain_sig(int sig)
731{
732 return /* current->exec_domain && current->exec_domain->signal_invmap
733 && sig < 32 ? current->exec_domain->signal_invmap[sig] : */ sig;
734}
735
bellard459a4012007-11-11 19:45:10 +0000736#if defined(TARGET_I386) && TARGET_ABI_BITS == 32
bellard66fb9762003-03-23 01:06:05 +0000737
738/* from the Linux kernel */
739
740struct target_fpreg {
741 uint16_t significand[4];
742 uint16_t exponent;
743};
744
745struct target_fpxreg {
746 uint16_t significand[4];
747 uint16_t exponent;
748 uint16_t padding[3];
749};
750
751struct target_xmmreg {
blueswir1992f48a2007-10-14 16:27:31 +0000752 abi_ulong element[4];
bellard66fb9762003-03-23 01:06:05 +0000753};
754
755struct target_fpstate {
756 /* Regular FPU environment */
blueswir1992f48a2007-10-14 16:27:31 +0000757 abi_ulong cw;
758 abi_ulong sw;
759 abi_ulong tag;
760 abi_ulong ipoff;
761 abi_ulong cssel;
762 abi_ulong dataoff;
763 abi_ulong datasel;
bellard66fb9762003-03-23 01:06:05 +0000764 struct target_fpreg _st[8];
765 uint16_t status;
766 uint16_t magic; /* 0xffff = regular FPU data only */
767
768 /* FXSR FPU environment */
blueswir1992f48a2007-10-14 16:27:31 +0000769 abi_ulong _fxsr_env[6]; /* FXSR FPU env is ignored */
770 abi_ulong mxcsr;
771 abi_ulong reserved;
bellard66fb9762003-03-23 01:06:05 +0000772 struct target_fpxreg _fxsr_st[8]; /* FXSR FPU reg data is ignored */
773 struct target_xmmreg _xmm[8];
blueswir1992f48a2007-10-14 16:27:31 +0000774 abi_ulong padding[56];
bellard66fb9762003-03-23 01:06:05 +0000775};
776
777#define X86_FXSR_MAGIC 0x0000
778
779struct target_sigcontext {
780 uint16_t gs, __gsh;
781 uint16_t fs, __fsh;
782 uint16_t es, __esh;
783 uint16_t ds, __dsh;
blueswir1992f48a2007-10-14 16:27:31 +0000784 abi_ulong edi;
785 abi_ulong esi;
786 abi_ulong ebp;
787 abi_ulong esp;
788 abi_ulong ebx;
789 abi_ulong edx;
790 abi_ulong ecx;
791 abi_ulong eax;
792 abi_ulong trapno;
793 abi_ulong err;
794 abi_ulong eip;
bellard66fb9762003-03-23 01:06:05 +0000795 uint16_t cs, __csh;
blueswir1992f48a2007-10-14 16:27:31 +0000796 abi_ulong eflags;
797 abi_ulong esp_at_signal;
bellard66fb9762003-03-23 01:06:05 +0000798 uint16_t ss, __ssh;
blueswir1992f48a2007-10-14 16:27:31 +0000799 abi_ulong fpstate; /* pointer */
800 abi_ulong oldmask;
801 abi_ulong cr2;
bellard66fb9762003-03-23 01:06:05 +0000802};
803
bellard66fb9762003-03-23 01:06:05 +0000804struct target_ucontext {
blueswir1992f48a2007-10-14 16:27:31 +0000805 abi_ulong tuc_flags;
806 abi_ulong tuc_link;
Anthony Liguoric227f092009-10-01 16:12:16 -0500807 target_stack_t tuc_stack;
bellardb8076a72005-04-07 22:20:31 +0000808 struct target_sigcontext tuc_mcontext;
Anthony Liguoric227f092009-10-01 16:12:16 -0500809 target_sigset_t tuc_sigmask; /* mask last for extensibility */
bellard66fb9762003-03-23 01:06:05 +0000810};
811
812struct sigframe
813{
blueswir1992f48a2007-10-14 16:27:31 +0000814 abi_ulong pretcode;
bellard66fb9762003-03-23 01:06:05 +0000815 int sig;
816 struct target_sigcontext sc;
817 struct target_fpstate fpstate;
blueswir1992f48a2007-10-14 16:27:31 +0000818 abi_ulong extramask[TARGET_NSIG_WORDS-1];
bellard66fb9762003-03-23 01:06:05 +0000819 char retcode[8];
820};
821
822struct rt_sigframe
823{
blueswir1992f48a2007-10-14 16:27:31 +0000824 abi_ulong pretcode;
bellard66fb9762003-03-23 01:06:05 +0000825 int sig;
blueswir1992f48a2007-10-14 16:27:31 +0000826 abi_ulong pinfo;
827 abi_ulong puc;
bellard66fb9762003-03-23 01:06:05 +0000828 struct target_siginfo info;
829 struct target_ucontext uc;
830 struct target_fpstate fpstate;
831 char retcode[8];
832};
833
834/*
835 * Set up a signal frame.
836 */
837
bellard66fb9762003-03-23 01:06:05 +0000838/* XXX: save x87 state */
Riku Voipio41ecc722014-04-23 11:01:00 +0300839static void setup_sigcontext(struct target_sigcontext *sc,
840 struct target_fpstate *fpstate, CPUX86State *env, abi_ulong mask,
841 abi_ulong fpstate_addr)
bellard66fb9762003-03-23 01:06:05 +0000842{
Andreas Färber27103422013-08-26 08:31:06 +0200843 CPUState *cs = CPU(x86_env_get_cpu(env));
Andreas Färber27103422013-08-26 08:31:06 +0200844 uint16_t magic;
bellard66fb9762003-03-23 01:06:05 +0000845
bellard579a97f2007-11-11 14:26:47 +0000846 /* already locked in setup_frame() */
Riku Voipio1d8b5122014-04-23 10:26:05 +0300847 __put_user(env->segs[R_GS].selector, (unsigned int *)&sc->gs);
848 __put_user(env->segs[R_FS].selector, (unsigned int *)&sc->fs);
849 __put_user(env->segs[R_ES].selector, (unsigned int *)&sc->es);
850 __put_user(env->segs[R_DS].selector, (unsigned int *)&sc->ds);
851 __put_user(env->regs[R_EDI], &sc->edi);
852 __put_user(env->regs[R_ESI], &sc->esi);
853 __put_user(env->regs[R_EBP], &sc->ebp);
854 __put_user(env->regs[R_ESP], &sc->esp);
855 __put_user(env->regs[R_EBX], &sc->ebx);
856 __put_user(env->regs[R_EDX], &sc->edx);
857 __put_user(env->regs[R_ECX], &sc->ecx);
858 __put_user(env->regs[R_EAX], &sc->eax);
859 __put_user(cs->exception_index, &sc->trapno);
860 __put_user(env->error_code, &sc->err);
861 __put_user(env->eip, &sc->eip);
862 __put_user(env->segs[R_CS].selector, (unsigned int *)&sc->cs);
863 __put_user(env->eflags, &sc->eflags);
864 __put_user(env->regs[R_ESP], &sc->esp_at_signal);
865 __put_user(env->segs[R_SS].selector, (unsigned int *)&sc->ss);
bellarded2dcdf2003-05-29 20:06:27 +0000866
bellard28be6232007-11-11 22:23:38 +0000867 cpu_x86_fsave(env, fpstate_addr, 1);
bellarded2dcdf2003-05-29 20:06:27 +0000868 fpstate->status = fpstate->sw;
bellard775b58d2007-11-11 16:22:17 +0000869 magic = 0xffff;
Riku Voipio1d8b5122014-04-23 10:26:05 +0300870 __put_user(magic, &fpstate->magic);
871 __put_user(fpstate_addr, &sc->fpstate);
bellarded2dcdf2003-05-29 20:06:27 +0000872
bellard66fb9762003-03-23 01:06:05 +0000873 /* non-iBCS2 extensions.. */
Riku Voipio1d8b5122014-04-23 10:26:05 +0300874 __put_user(mask, &sc->oldmask);
875 __put_user(env->cr[2], &sc->cr2);
bellard66fb9762003-03-23 01:06:05 +0000876}
877
878/*
879 * Determine which stack to use..
880 */
881
bellard579a97f2007-11-11 14:26:47 +0000882static inline abi_ulong
pbrook624f7972008-05-31 16:11:38 +0000883get_sigframe(struct target_sigaction *ka, CPUX86State *env, size_t frame_size)
bellard66fb9762003-03-23 01:06:05 +0000884{
885 unsigned long esp;
886
887 /* Default to using normal stack */
888 esp = env->regs[R_ESP];
bellard66fb9762003-03-23 01:06:05 +0000889 /* This is the X/Open sanctioned signal stack switching. */
pbrook624f7972008-05-31 16:11:38 +0000890 if (ka->sa_flags & TARGET_SA_ONSTACK) {
thsa04e1342007-09-27 13:57:58 +0000891 if (sas_ss_flags(esp) == 0)
892 esp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
893 }
bellard66fb9762003-03-23 01:06:05 +0000894
895 /* This is the legacy signal stack switching. */
ths5fafdf22007-09-16 21:08:06 +0000896 else
bellarda52c7572003-06-21 13:14:12 +0000897 if ((env->segs[R_SS].selector & 0xffff) != __USER_DS &&
pbrook624f7972008-05-31 16:11:38 +0000898 !(ka->sa_flags & TARGET_SA_RESTORER) &&
899 ka->sa_restorer) {
900 esp = (unsigned long) ka->sa_restorer;
bellarda52c7572003-06-21 13:14:12 +0000901 }
bellard579a97f2007-11-11 14:26:47 +0000902 return (esp - frame_size) & -8ul;
bellard66fb9762003-03-23 01:06:05 +0000903}
904
bellard579a97f2007-11-11 14:26:47 +0000905/* compare linux/arch/i386/kernel/signal.c:setup_frame() */
pbrook624f7972008-05-31 16:11:38 +0000906static void setup_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -0500907 target_sigset_t *set, CPUX86State *env)
bellard66fb9762003-03-23 01:06:05 +0000908{
bellard579a97f2007-11-11 14:26:47 +0000909 abi_ulong frame_addr;
bellard66fb9762003-03-23 01:06:05 +0000910 struct sigframe *frame;
Riku Voipio7df2fa32014-04-23 10:34:53 +0300911 int i;
bellard66fb9762003-03-23 01:06:05 +0000912
bellard579a97f2007-11-11 14:26:47 +0000913 frame_addr = get_sigframe(ka, env, sizeof(*frame));
bellard66fb9762003-03-23 01:06:05 +0000914
bellard579a97f2007-11-11 14:26:47 +0000915 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
bellard66fb9762003-03-23 01:06:05 +0000916 goto give_sigsegv;
bellard579a97f2007-11-11 14:26:47 +0000917
Riku Voipio1d8b5122014-04-23 10:26:05 +0300918 __put_user(current_exec_domain_sig(sig),
919 &frame->sig);
bellard66fb9762003-03-23 01:06:05 +0000920
bellard28be6232007-11-11 22:23:38 +0000921 setup_sigcontext(&frame->sc, &frame->fpstate, env, set->sig[0],
922 frame_addr + offsetof(struct sigframe, fpstate));
bellard66fb9762003-03-23 01:06:05 +0000923
Riku Voipio7df2fa32014-04-23 10:34:53 +0300924 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
925 __put_user(set->sig[i], &frame->extramask[i - 1]);
926 }
bellard66fb9762003-03-23 01:06:05 +0000927
928 /* Set up to return from userspace. If provided, use a stub
929 already in userspace. */
pbrook624f7972008-05-31 16:11:38 +0000930 if (ka->sa_flags & TARGET_SA_RESTORER) {
Riku Voipio1d8b5122014-04-23 10:26:05 +0300931 __put_user(ka->sa_restorer, &frame->pretcode);
bellard66fb9762003-03-23 01:06:05 +0000932 } else {
bellard775b58d2007-11-11 16:22:17 +0000933 uint16_t val16;
bellard28be6232007-11-11 22:23:38 +0000934 abi_ulong retcode_addr;
935 retcode_addr = frame_addr + offsetof(struct sigframe, retcode);
Riku Voipio1d8b5122014-04-23 10:26:05 +0300936 __put_user(retcode_addr, &frame->pretcode);
bellard66fb9762003-03-23 01:06:05 +0000937 /* This is popl %eax ; movl $,%eax ; int $0x80 */
bellard775b58d2007-11-11 16:22:17 +0000938 val16 = 0xb858;
Riku Voipio1d8b5122014-04-23 10:26:05 +0300939 __put_user(val16, (uint16_t *)(frame->retcode+0));
940 __put_user(TARGET_NR_sigreturn, (int *)(frame->retcode+2));
bellard775b58d2007-11-11 16:22:17 +0000941 val16 = 0x80cd;
Riku Voipio1d8b5122014-04-23 10:26:05 +0300942 __put_user(val16, (uint16_t *)(frame->retcode+6));
bellard66fb9762003-03-23 01:06:05 +0000943 }
944
bellard66fb9762003-03-23 01:06:05 +0000945
946 /* Set up registers for signal handler */
bellard28be6232007-11-11 22:23:38 +0000947 env->regs[R_ESP] = frame_addr;
pbrook624f7972008-05-31 16:11:38 +0000948 env->eip = ka->_sa_handler;
bellard66fb9762003-03-23 01:06:05 +0000949
950 cpu_x86_load_seg(env, R_DS, __USER_DS);
951 cpu_x86_load_seg(env, R_ES, __USER_DS);
952 cpu_x86_load_seg(env, R_SS, __USER_DS);
953 cpu_x86_load_seg(env, R_CS, __USER_CS);
954 env->eflags &= ~TF_MASK;
955
bellard579a97f2007-11-11 14:26:47 +0000956 unlock_user_struct(frame, frame_addr, 1);
957
bellard66fb9762003-03-23 01:06:05 +0000958 return;
959
960give_sigsegv:
961 if (sig == TARGET_SIGSEGV)
pbrook624f7972008-05-31 16:11:38 +0000962 ka->_sa_handler = TARGET_SIG_DFL;
bellard66fb9762003-03-23 01:06:05 +0000963 force_sig(TARGET_SIGSEGV /* , current */);
964}
965
bellard579a97f2007-11-11 14:26:47 +0000966/* compare linux/arch/i386/kernel/signal.c:setup_rt_frame() */
pbrook624f7972008-05-31 16:11:38 +0000967static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -0500968 target_siginfo_t *info,
969 target_sigset_t *set, CPUX86State *env)
bellard66fb9762003-03-23 01:06:05 +0000970{
bellard28be6232007-11-11 22:23:38 +0000971 abi_ulong frame_addr, addr;
bellard66fb9762003-03-23 01:06:05 +0000972 struct rt_sigframe *frame;
bellard92319442004-06-19 16:58:13 +0000973 int i, err = 0;
bellard66fb9762003-03-23 01:06:05 +0000974
bellard579a97f2007-11-11 14:26:47 +0000975 frame_addr = get_sigframe(ka, env, sizeof(*frame));
bellard66fb9762003-03-23 01:06:05 +0000976
bellard579a97f2007-11-11 14:26:47 +0000977 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
bellard66fb9762003-03-23 01:06:05 +0000978 goto give_sigsegv;
bellard66fb9762003-03-23 01:06:05 +0000979
Riku Voipio1d8b5122014-04-23 10:26:05 +0300980 __put_user(current_exec_domain_sig(sig), &frame->sig);
bellard28be6232007-11-11 22:23:38 +0000981 addr = frame_addr + offsetof(struct rt_sigframe, info);
Riku Voipio1d8b5122014-04-23 10:26:05 +0300982 __put_user(addr, &frame->pinfo);
bellard28be6232007-11-11 22:23:38 +0000983 addr = frame_addr + offsetof(struct rt_sigframe, uc);
Riku Voipio1d8b5122014-04-23 10:26:05 +0300984 __put_user(addr, &frame->puc);
Riku Voipiob0fd8d12014-04-23 10:46:13 +0300985 copy_siginfo_to_user(&frame->info, info);
bellard66fb9762003-03-23 01:06:05 +0000986
987 /* Create the ucontext. */
Riku Voipio1d8b5122014-04-23 10:26:05 +0300988 __put_user(0, &frame->uc.tuc_flags);
989 __put_user(0, &frame->uc.tuc_link);
990 __put_user(target_sigaltstack_used.ss_sp, &frame->uc.tuc_stack.ss_sp);
991 __put_user(sas_ss_flags(get_sp_from_cpustate(env)),
992 &frame->uc.tuc_stack.ss_flags);
993 __put_user(target_sigaltstack_used.ss_size,
994 &frame->uc.tuc_stack.ss_size);
Riku Voipio41ecc722014-04-23 11:01:00 +0300995 setup_sigcontext(&frame->uc.tuc_mcontext, &frame->fpstate, env,
996 set->sig[0], frame_addr + offsetof(struct rt_sigframe, fpstate));
997
bellard92319442004-06-19 16:58:13 +0000998 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
bellardb8076a72005-04-07 22:20:31 +0000999 if (__put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]))
bellard92319442004-06-19 16:58:13 +00001000 goto give_sigsegv;
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
1018 if (err)
1019 goto give_sigsegv;
1020
1021 /* Set up registers for signal handler */
bellard28be6232007-11-11 22:23:38 +00001022 env->regs[R_ESP] = frame_addr;
pbrook624f7972008-05-31 16:11:38 +00001023 env->eip = ka->_sa_handler;
bellard66fb9762003-03-23 01:06:05 +00001024
1025 cpu_x86_load_seg(env, R_DS, __USER_DS);
1026 cpu_x86_load_seg(env, R_ES, __USER_DS);
1027 cpu_x86_load_seg(env, R_SS, __USER_DS);
1028 cpu_x86_load_seg(env, R_CS, __USER_CS);
1029 env->eflags &= ~TF_MASK;
1030
bellard579a97f2007-11-11 14:26:47 +00001031 unlock_user_struct(frame, frame_addr, 1);
1032
bellard66fb9762003-03-23 01:06:05 +00001033 return;
1034
1035give_sigsegv:
bellard579a97f2007-11-11 14:26:47 +00001036 unlock_user_struct(frame, frame_addr, 1);
bellard66fb9762003-03-23 01:06:05 +00001037 if (sig == TARGET_SIGSEGV)
pbrook624f7972008-05-31 16:11:38 +00001038 ka->_sa_handler = TARGET_SIG_DFL;
bellard66fb9762003-03-23 01:06:05 +00001039 force_sig(TARGET_SIGSEGV /* , current */);
1040}
1041
1042static int
1043restore_sigcontext(CPUX86State *env, struct target_sigcontext *sc, int *peax)
1044{
1045 unsigned int err = 0;
bellard28be6232007-11-11 22:23:38 +00001046 abi_ulong fpstate_addr;
1047 unsigned int tmpflags;
bellard66fb9762003-03-23 01:06:05 +00001048
bellard28be6232007-11-11 22:23:38 +00001049 cpu_x86_load_seg(env, R_GS, tswap16(sc->gs));
1050 cpu_x86_load_seg(env, R_FS, tswap16(sc->fs));
1051 cpu_x86_load_seg(env, R_ES, tswap16(sc->es));
1052 cpu_x86_load_seg(env, R_DS, tswap16(sc->ds));
bellard66fb9762003-03-23 01:06:05 +00001053
bellard28be6232007-11-11 22:23:38 +00001054 env->regs[R_EDI] = tswapl(sc->edi);
1055 env->regs[R_ESI] = tswapl(sc->esi);
1056 env->regs[R_EBP] = tswapl(sc->ebp);
1057 env->regs[R_ESP] = tswapl(sc->esp);
1058 env->regs[R_EBX] = tswapl(sc->ebx);
1059 env->regs[R_EDX] = tswapl(sc->edx);
1060 env->regs[R_ECX] = tswapl(sc->ecx);
1061 env->eip = tswapl(sc->eip);
bellard66fb9762003-03-23 01:06:05 +00001062
Mike McCormack9a826d72011-06-01 15:14:37 +09001063 cpu_x86_load_seg(env, R_CS, lduw_p(&sc->cs) | 3);
1064 cpu_x86_load_seg(env, R_SS, lduw_p(&sc->ss) | 3);
ths5fafdf22007-09-16 21:08:06 +00001065
bellard28be6232007-11-11 22:23:38 +00001066 tmpflags = tswapl(sc->eflags);
1067 env->eflags = (env->eflags & ~0x40DD5) | (tmpflags & 0x40DD5);
1068 // regs->orig_eax = -1; /* disable syscall checks */
1069
1070 fpstate_addr = tswapl(sc->fpstate);
1071 if (fpstate_addr != 0) {
1072 if (!access_ok(VERIFY_READ, fpstate_addr,
1073 sizeof(struct target_fpstate)))
1074 goto badframe;
1075 cpu_x86_frstor(env, fpstate_addr, 1);
bellard66fb9762003-03-23 01:06:05 +00001076 }
1077
bellard28be6232007-11-11 22:23:38 +00001078 *peax = tswapl(sc->eax);
bellard66fb9762003-03-23 01:06:05 +00001079 return err;
bellard66fb9762003-03-23 01:06:05 +00001080badframe:
1081 return 1;
bellard66fb9762003-03-23 01:06:05 +00001082}
1083
1084long do_sigreturn(CPUX86State *env)
1085{
bellard579a97f2007-11-11 14:26:47 +00001086 struct sigframe *frame;
1087 abi_ulong frame_addr = env->regs[R_ESP] - 8;
Anthony Liguoric227f092009-10-01 16:12:16 -05001088 target_sigset_t target_set;
bellard66fb9762003-03-23 01:06:05 +00001089 sigset_t set;
1090 int eax, i;
1091
bellard447db212003-05-10 15:10:36 +00001092#if defined(DEBUG_SIGNAL)
1093 fprintf(stderr, "do_sigreturn\n");
1094#endif
bellard579a97f2007-11-11 14:26:47 +00001095 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
1096 goto badframe;
bellard66fb9762003-03-23 01:06:05 +00001097 /* set blocked signals */
bellard92319442004-06-19 16:58:13 +00001098 if (__get_user(target_set.sig[0], &frame->sc.oldmask))
1099 goto badframe;
1100 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
1101 if (__get_user(target_set.sig[i], &frame->extramask[i - 1]))
1102 goto badframe;
1103 }
bellard66fb9762003-03-23 01:06:05 +00001104
bellard92319442004-06-19 16:58:13 +00001105 target_to_host_sigset_internal(&set, &target_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00001106 do_sigprocmask(SIG_SETMASK, &set, NULL);
ths3b46e622007-09-17 08:09:54 +00001107
bellard66fb9762003-03-23 01:06:05 +00001108 /* restore registers */
1109 if (restore_sigcontext(env, &frame->sc, &eax))
1110 goto badframe;
bellard579a97f2007-11-11 14:26:47 +00001111 unlock_user_struct(frame, frame_addr, 0);
bellard66fb9762003-03-23 01:06:05 +00001112 return eax;
1113
1114badframe:
bellard579a97f2007-11-11 14:26:47 +00001115 unlock_user_struct(frame, frame_addr, 0);
bellard66fb9762003-03-23 01:06:05 +00001116 force_sig(TARGET_SIGSEGV);
1117 return 0;
1118}
1119
1120long do_rt_sigreturn(CPUX86State *env)
1121{
bellard28be6232007-11-11 22:23:38 +00001122 abi_ulong frame_addr;
1123 struct rt_sigframe *frame;
bellard66fb9762003-03-23 01:06:05 +00001124 sigset_t set;
bellard66fb9762003-03-23 01:06:05 +00001125 int eax;
1126
bellard28be6232007-11-11 22:23:38 +00001127 frame_addr = env->regs[R_ESP] - 4;
1128 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
1129 goto badframe;
bellardb8076a72005-04-07 22:20:31 +00001130 target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
Alex Barcelo1c275922014-03-14 14:36:55 +00001131 do_sigprocmask(SIG_SETMASK, &set, NULL);
ths5fafdf22007-09-16 21:08:06 +00001132
bellardb8076a72005-04-07 22:20:31 +00001133 if (restore_sigcontext(env, &frame->uc.tuc_mcontext, &eax))
bellard66fb9762003-03-23 01:06:05 +00001134 goto badframe;
1135
bellard28be6232007-11-11 22:23:38 +00001136 if (do_sigaltstack(frame_addr + offsetof(struct rt_sigframe, uc.tuc_stack), 0,
1137 get_sp_from_cpustate(env)) == -EFAULT)
bellard66fb9762003-03-23 01:06:05 +00001138 goto badframe;
thsa04e1342007-09-27 13:57:58 +00001139
bellard28be6232007-11-11 22:23:38 +00001140 unlock_user_struct(frame, frame_addr, 0);
bellard66fb9762003-03-23 01:06:05 +00001141 return eax;
1142
1143badframe:
bellard28be6232007-11-11 22:23:38 +00001144 unlock_user_struct(frame, frame_addr, 0);
1145 force_sig(TARGET_SIGSEGV);
bellard66fb9762003-03-23 01:06:05 +00001146 return 0;
1147}
1148
Andreas Schwab1744aea2013-09-03 20:12:16 +01001149#elif defined(TARGET_AARCH64)
1150
1151struct target_sigcontext {
1152 uint64_t fault_address;
1153 /* AArch64 registers */
1154 uint64_t regs[31];
1155 uint64_t sp;
1156 uint64_t pc;
1157 uint64_t pstate;
1158 /* 4K reserved for FP/SIMD state and future expansion */
1159 char __reserved[4096] __attribute__((__aligned__(16)));
1160};
1161
1162struct target_ucontext {
1163 abi_ulong tuc_flags;
1164 abi_ulong tuc_link;
1165 target_stack_t tuc_stack;
1166 target_sigset_t tuc_sigmask;
1167 /* glibc uses a 1024-bit sigset_t */
1168 char __unused[1024 / 8 - sizeof(target_sigset_t)];
1169 /* last for future expansion */
1170 struct target_sigcontext tuc_mcontext;
1171};
1172
1173/*
1174 * Header to be used at the beginning of structures extending the user
1175 * context. Such structures must be placed after the rt_sigframe on the stack
1176 * and be 16-byte aligned. The last structure must be a dummy one with the
1177 * magic and size set to 0.
1178 */
1179struct target_aarch64_ctx {
1180 uint32_t magic;
1181 uint32_t size;
1182};
1183
1184#define TARGET_FPSIMD_MAGIC 0x46508001
1185
1186struct target_fpsimd_context {
1187 struct target_aarch64_ctx head;
1188 uint32_t fpsr;
1189 uint32_t fpcr;
1190 uint64_t vregs[32 * 2]; /* really uint128_t vregs[32] */
1191};
1192
1193/*
1194 * Auxiliary context saved in the sigcontext.__reserved array. Not exported to
1195 * user space as it will change with the addition of new context. User space
1196 * should check the magic/size information.
1197 */
1198struct target_aux_context {
1199 struct target_fpsimd_context fpsimd;
1200 /* additional context to be added before "end" */
1201 struct target_aarch64_ctx end;
1202};
1203
1204struct target_rt_sigframe {
1205 struct target_siginfo info;
1206 struct target_ucontext uc;
1207 uint64_t fp;
1208 uint64_t lr;
1209 uint32_t tramp[2];
1210};
1211
1212static int target_setup_sigframe(struct target_rt_sigframe *sf,
1213 CPUARMState *env, target_sigset_t *set)
1214{
1215 int i;
1216 struct target_aux_context *aux =
1217 (struct target_aux_context *)sf->uc.tuc_mcontext.__reserved;
1218
1219 /* set up the stack frame for unwinding */
1220 __put_user(env->xregs[29], &sf->fp);
1221 __put_user(env->xregs[30], &sf->lr);
1222
1223 for (i = 0; i < 31; i++) {
1224 __put_user(env->xregs[i], &sf->uc.tuc_mcontext.regs[i]);
1225 }
1226 __put_user(env->xregs[31], &sf->uc.tuc_mcontext.sp);
1227 __put_user(env->pc, &sf->uc.tuc_mcontext.pc);
Peter Maydelld3563122013-12-17 19:42:30 +00001228 __put_user(pstate_read(env), &sf->uc.tuc_mcontext.pstate);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001229
Peter Maydell7af03922014-05-01 18:36:17 +01001230 __put_user(env->exception.vaddress, &sf->uc.tuc_mcontext.fault_address);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001231
1232 for (i = 0; i < TARGET_NSIG_WORDS; i++) {
1233 __put_user(set->sig[i], &sf->uc.tuc_sigmask.sig[i]);
1234 }
1235
1236 for (i = 0; i < 32; i++) {
1237#ifdef TARGET_WORDS_BIGENDIAN
1238 __put_user(env->vfp.regs[i * 2], &aux->fpsimd.vregs[i * 2 + 1]);
1239 __put_user(env->vfp.regs[i * 2 + 1], &aux->fpsimd.vregs[i * 2]);
1240#else
1241 __put_user(env->vfp.regs[i * 2], &aux->fpsimd.vregs[i * 2]);
1242 __put_user(env->vfp.regs[i * 2 + 1], &aux->fpsimd.vregs[i * 2 + 1]);
1243#endif
1244 }
Will Newtone0ee1382014-01-04 22:15:48 +00001245 __put_user(vfp_get_fpsr(env), &aux->fpsimd.fpsr);
1246 __put_user(vfp_get_fpcr(env), &aux->fpsimd.fpcr);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001247 __put_user(TARGET_FPSIMD_MAGIC, &aux->fpsimd.head.magic);
1248 __put_user(sizeof(struct target_fpsimd_context),
1249 &aux->fpsimd.head.size);
1250
1251 /* set the "end" magic */
1252 __put_user(0, &aux->end.magic);
1253 __put_user(0, &aux->end.size);
1254
1255 return 0;
1256}
1257
1258static int target_restore_sigframe(CPUARMState *env,
1259 struct target_rt_sigframe *sf)
1260{
1261 sigset_t set;
1262 int i;
1263 struct target_aux_context *aux =
1264 (struct target_aux_context *)sf->uc.tuc_mcontext.__reserved;
Will Newtone0ee1382014-01-04 22:15:48 +00001265 uint32_t magic, size, fpsr, fpcr;
Peter Maydelld3563122013-12-17 19:42:30 +00001266 uint64_t pstate;
Andreas Schwab1744aea2013-09-03 20:12:16 +01001267
1268 target_to_host_sigset(&set, &sf->uc.tuc_sigmask);
Alex Barcelo1c275922014-03-14 14:36:55 +00001269 do_sigprocmask(SIG_SETMASK, &set, NULL);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001270
1271 for (i = 0; i < 31; i++) {
1272 __get_user(env->xregs[i], &sf->uc.tuc_mcontext.regs[i]);
1273 }
1274
1275 __get_user(env->xregs[31], &sf->uc.tuc_mcontext.sp);
1276 __get_user(env->pc, &sf->uc.tuc_mcontext.pc);
Peter Maydelld3563122013-12-17 19:42:30 +00001277 __get_user(pstate, &sf->uc.tuc_mcontext.pstate);
1278 pstate_write(env, pstate);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001279
1280 __get_user(magic, &aux->fpsimd.head.magic);
1281 __get_user(size, &aux->fpsimd.head.size);
1282
1283 if (magic != TARGET_FPSIMD_MAGIC
1284 || size != sizeof(struct target_fpsimd_context)) {
1285 return 1;
1286 }
1287
Peter Maydell4cf23482014-03-02 19:36:38 +00001288 for (i = 0; i < 32; i++) {
1289#ifdef TARGET_WORDS_BIGENDIAN
1290 __get_user(env->vfp.regs[i * 2], &aux->fpsimd.vregs[i * 2 + 1]);
1291 __get_user(env->vfp.regs[i * 2 + 1], &aux->fpsimd.vregs[i * 2]);
1292#else
1293 __get_user(env->vfp.regs[i * 2], &aux->fpsimd.vregs[i * 2]);
1294 __get_user(env->vfp.regs[i * 2 + 1], &aux->fpsimd.vregs[i * 2 + 1]);
1295#endif
Andreas Schwab1744aea2013-09-03 20:12:16 +01001296 }
Will Newtone0ee1382014-01-04 22:15:48 +00001297 __get_user(fpsr, &aux->fpsimd.fpsr);
1298 vfp_set_fpsr(env, fpsr);
1299 __get_user(fpcr, &aux->fpsimd.fpcr);
1300 vfp_set_fpcr(env, fpcr);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001301
1302 return 0;
1303}
1304
1305static abi_ulong get_sigframe(struct target_sigaction *ka, CPUARMState *env)
1306{
1307 abi_ulong sp;
1308
1309 sp = env->xregs[31];
1310
1311 /*
1312 * This is the X/Open sanctioned signal stack switching.
1313 */
1314 if ((ka->sa_flags & SA_ONSTACK) && !sas_ss_flags(sp)) {
1315 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
1316 }
1317
1318 sp = (sp - sizeof(struct target_rt_sigframe)) & ~15;
1319
1320 return sp;
1321}
1322
1323static void target_setup_frame(int usig, struct target_sigaction *ka,
1324 target_siginfo_t *info, target_sigset_t *set,
1325 CPUARMState *env)
1326{
1327 struct target_rt_sigframe *frame;
Michael Matz8a3ae912014-03-02 19:36:39 +00001328 abi_ulong frame_addr, return_addr;
Andreas Schwab1744aea2013-09-03 20:12:16 +01001329
1330 frame_addr = get_sigframe(ka, env);
1331 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
1332 goto give_sigsegv;
1333 }
1334
1335 __put_user(0, &frame->uc.tuc_flags);
1336 __put_user(0, &frame->uc.tuc_link);
1337
1338 __put_user(target_sigaltstack_used.ss_sp,
1339 &frame->uc.tuc_stack.ss_sp);
1340 __put_user(sas_ss_flags(env->xregs[31]),
1341 &frame->uc.tuc_stack.ss_flags);
1342 __put_user(target_sigaltstack_used.ss_size,
1343 &frame->uc.tuc_stack.ss_size);
1344 target_setup_sigframe(frame, env, set);
Michael Matz8a3ae912014-03-02 19:36:39 +00001345 if (ka->sa_flags & TARGET_SA_RESTORER) {
1346 return_addr = ka->sa_restorer;
1347 } else {
1348 /* mov x8,#__NR_rt_sigreturn; svc #0 */
1349 __put_user(0xd2801168, &frame->tramp[0]);
1350 __put_user(0xd4000001, &frame->tramp[1]);
1351 return_addr = frame_addr + offsetof(struct target_rt_sigframe, tramp);
1352 }
Andreas Schwab1744aea2013-09-03 20:12:16 +01001353 env->xregs[0] = usig;
1354 env->xregs[31] = frame_addr;
1355 env->xregs[29] = env->xregs[31] + offsetof(struct target_rt_sigframe, fp);
1356 env->pc = ka->_sa_handler;
Michael Matz8a3ae912014-03-02 19:36:39 +00001357 env->xregs[30] = return_addr;
Andreas Schwab1744aea2013-09-03 20:12:16 +01001358 if (info) {
Riku Voipiob0fd8d12014-04-23 10:46:13 +03001359 copy_siginfo_to_user(&frame->info, info);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001360 env->xregs[1] = frame_addr + offsetof(struct target_rt_sigframe, info);
1361 env->xregs[2] = frame_addr + offsetof(struct target_rt_sigframe, uc);
1362 }
1363
1364 unlock_user_struct(frame, frame_addr, 1);
1365 return;
1366
1367 give_sigsegv:
1368 unlock_user_struct(frame, frame_addr, 1);
1369 force_sig(TARGET_SIGSEGV);
1370}
1371
1372static void setup_rt_frame(int sig, struct target_sigaction *ka,
1373 target_siginfo_t *info, target_sigset_t *set,
1374 CPUARMState *env)
1375{
1376 target_setup_frame(sig, ka, info, set, env);
1377}
1378
1379static void setup_frame(int sig, struct target_sigaction *ka,
1380 target_sigset_t *set, CPUARMState *env)
1381{
1382 target_setup_frame(sig, ka, 0, set, env);
1383}
1384
1385long do_rt_sigreturn(CPUARMState *env)
1386{
Peter Maydell7f72cd22014-03-12 13:06:00 +00001387 struct target_rt_sigframe *frame = NULL;
Andreas Schwab1744aea2013-09-03 20:12:16 +01001388 abi_ulong frame_addr = env->xregs[31];
1389
1390 if (frame_addr & 15) {
1391 goto badframe;
1392 }
1393
1394 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
1395 goto badframe;
1396 }
1397
1398 if (target_restore_sigframe(env, frame)) {
1399 goto badframe;
1400 }
1401
1402 if (do_sigaltstack(frame_addr +
1403 offsetof(struct target_rt_sigframe, uc.tuc_stack),
1404 0, get_sp_from_cpustate(env)) == -EFAULT) {
1405 goto badframe;
1406 }
1407
1408 unlock_user_struct(frame, frame_addr, 0);
1409 return env->xregs[0];
1410
1411 badframe:
1412 unlock_user_struct(frame, frame_addr, 0);
1413 force_sig(TARGET_SIGSEGV);
1414 return 0;
1415}
1416
1417long do_sigreturn(CPUARMState *env)
1418{
1419 return do_rt_sigreturn(env);
1420}
1421
bellard43fff232003-07-09 19:31:39 +00001422#elif defined(TARGET_ARM)
1423
1424struct target_sigcontext {
blueswir1992f48a2007-10-14 16:27:31 +00001425 abi_ulong trap_no;
1426 abi_ulong error_code;
1427 abi_ulong oldmask;
1428 abi_ulong arm_r0;
1429 abi_ulong arm_r1;
1430 abi_ulong arm_r2;
1431 abi_ulong arm_r3;
1432 abi_ulong arm_r4;
1433 abi_ulong arm_r5;
1434 abi_ulong arm_r6;
1435 abi_ulong arm_r7;
1436 abi_ulong arm_r8;
1437 abi_ulong arm_r9;
1438 abi_ulong arm_r10;
1439 abi_ulong arm_fp;
1440 abi_ulong arm_ip;
1441 abi_ulong arm_sp;
1442 abi_ulong arm_lr;
1443 abi_ulong arm_pc;
1444 abi_ulong arm_cpsr;
1445 abi_ulong fault_address;
bellard43fff232003-07-09 19:31:39 +00001446};
1447
pbrooka745ec62008-05-06 15:36:17 +00001448struct target_ucontext_v1 {
blueswir1992f48a2007-10-14 16:27:31 +00001449 abi_ulong tuc_flags;
1450 abi_ulong tuc_link;
Anthony Liguoric227f092009-10-01 16:12:16 -05001451 target_stack_t tuc_stack;
bellardb8076a72005-04-07 22:20:31 +00001452 struct target_sigcontext tuc_mcontext;
Anthony Liguoric227f092009-10-01 16:12:16 -05001453 target_sigset_t tuc_sigmask; /* mask last for extensibility */
bellard43fff232003-07-09 19:31:39 +00001454};
1455
pbrooka745ec62008-05-06 15:36:17 +00001456struct target_ucontext_v2 {
1457 abi_ulong tuc_flags;
1458 abi_ulong tuc_link;
Anthony Liguoric227f092009-10-01 16:12:16 -05001459 target_stack_t tuc_stack;
pbrooka745ec62008-05-06 15:36:17 +00001460 struct target_sigcontext tuc_mcontext;
Anthony Liguoric227f092009-10-01 16:12:16 -05001461 target_sigset_t tuc_sigmask; /* mask last for extensibility */
Peter Maydell5f0b7c82010-11-24 15:20:03 +00001462 char __unused[128 - sizeof(target_sigset_t)];
pbrooka745ec62008-05-06 15:36:17 +00001463 abi_ulong tuc_regspace[128] __attribute__((__aligned__(8)));
1464};
1465
Peter Maydell0d871bd2010-11-24 15:20:05 +00001466struct target_user_vfp {
1467 uint64_t fpregs[32];
1468 abi_ulong fpscr;
1469};
1470
1471struct target_user_vfp_exc {
1472 abi_ulong fpexc;
1473 abi_ulong fpinst;
1474 abi_ulong fpinst2;
1475};
1476
1477struct target_vfp_sigframe {
1478 abi_ulong magic;
1479 abi_ulong size;
1480 struct target_user_vfp ufp;
1481 struct target_user_vfp_exc ufp_exc;
1482} __attribute__((__aligned__(8)));
1483
Peter Maydell08e11252010-11-24 15:20:07 +00001484struct target_iwmmxt_sigframe {
1485 abi_ulong magic;
1486 abi_ulong size;
1487 uint64_t regs[16];
1488 /* Note that not all the coprocessor control registers are stored here */
1489 uint32_t wcssf;
1490 uint32_t wcasf;
1491 uint32_t wcgr0;
1492 uint32_t wcgr1;
1493 uint32_t wcgr2;
1494 uint32_t wcgr3;
1495} __attribute__((__aligned__(8)));
1496
Peter Maydell0d871bd2010-11-24 15:20:05 +00001497#define TARGET_VFP_MAGIC 0x56465001
Peter Maydell08e11252010-11-24 15:20:07 +00001498#define TARGET_IWMMXT_MAGIC 0x12ef842a
Peter Maydell0d871bd2010-11-24 15:20:05 +00001499
pbrooka8c33202008-05-07 23:22:46 +00001500struct sigframe_v1
bellard43fff232003-07-09 19:31:39 +00001501{
1502 struct target_sigcontext sc;
blueswir1992f48a2007-10-14 16:27:31 +00001503 abi_ulong extramask[TARGET_NSIG_WORDS-1];
1504 abi_ulong retcode;
bellard43fff232003-07-09 19:31:39 +00001505};
1506
pbrooka8c33202008-05-07 23:22:46 +00001507struct sigframe_v2
1508{
1509 struct target_ucontext_v2 uc;
1510 abi_ulong retcode;
1511};
1512
pbrooka745ec62008-05-06 15:36:17 +00001513struct rt_sigframe_v1
bellard43fff232003-07-09 19:31:39 +00001514{
bellardf8b0aa22007-11-11 23:03:42 +00001515 abi_ulong pinfo;
1516 abi_ulong puc;
bellard43fff232003-07-09 19:31:39 +00001517 struct target_siginfo info;
pbrooka745ec62008-05-06 15:36:17 +00001518 struct target_ucontext_v1 uc;
1519 abi_ulong retcode;
1520};
1521
1522struct rt_sigframe_v2
1523{
1524 struct target_siginfo info;
1525 struct target_ucontext_v2 uc;
blueswir1992f48a2007-10-14 16:27:31 +00001526 abi_ulong retcode;
bellard43fff232003-07-09 19:31:39 +00001527};
1528
1529#define TARGET_CONFIG_CPU_32 1
1530
1531/*
1532 * For ARM syscalls, we encode the syscall number into the instruction.
1533 */
1534#define SWI_SYS_SIGRETURN (0xef000000|(TARGET_NR_sigreturn + ARM_SYSCALL_BASE))
1535#define SWI_SYS_RT_SIGRETURN (0xef000000|(TARGET_NR_rt_sigreturn + ARM_SYSCALL_BASE))
1536
1537/*
1538 * For Thumb syscalls, we pass the syscall number via r7. We therefore
1539 * need two 16-bit instructions.
1540 */
1541#define SWI_THUMB_SIGRETURN (0xdf00 << 16 | 0x2700 | (TARGET_NR_sigreturn))
1542#define SWI_THUMB_RT_SIGRETURN (0xdf00 << 16 | 0x2700 | (TARGET_NR_rt_sigreturn))
1543
blueswir1992f48a2007-10-14 16:27:31 +00001544static const abi_ulong retcodes[4] = {
bellard43fff232003-07-09 19:31:39 +00001545 SWI_SYS_SIGRETURN, SWI_THUMB_SIGRETURN,
1546 SWI_SYS_RT_SIGRETURN, SWI_THUMB_RT_SIGRETURN
1547};
1548
1549
Andreas Färber05390242012-02-25 03:37:53 +01001550static inline int valid_user_regs(CPUARMState *regs)
bellard43fff232003-07-09 19:31:39 +00001551{
1552 return 1;
1553}
1554
pbrooka8c33202008-05-07 23:22:46 +00001555static void
bellard43fff232003-07-09 19:31:39 +00001556setup_sigcontext(struct target_sigcontext *sc, /*struct _fpstate *fpstate,*/
Andreas Färber05390242012-02-25 03:37:53 +01001557 CPUARMState *env, abi_ulong mask)
bellard43fff232003-07-09 19:31:39 +00001558{
pbrooka8c33202008-05-07 23:22:46 +00001559 __put_user(env->regs[0], &sc->arm_r0);
1560 __put_user(env->regs[1], &sc->arm_r1);
1561 __put_user(env->regs[2], &sc->arm_r2);
1562 __put_user(env->regs[3], &sc->arm_r3);
1563 __put_user(env->regs[4], &sc->arm_r4);
1564 __put_user(env->regs[5], &sc->arm_r5);
1565 __put_user(env->regs[6], &sc->arm_r6);
1566 __put_user(env->regs[7], &sc->arm_r7);
1567 __put_user(env->regs[8], &sc->arm_r8);
1568 __put_user(env->regs[9], &sc->arm_r9);
1569 __put_user(env->regs[10], &sc->arm_r10);
1570 __put_user(env->regs[11], &sc->arm_fp);
1571 __put_user(env->regs[12], &sc->arm_ip);
1572 __put_user(env->regs[13], &sc->arm_sp);
1573 __put_user(env->regs[14], &sc->arm_lr);
1574 __put_user(env->regs[15], &sc->arm_pc);
bellard43fff232003-07-09 19:31:39 +00001575#ifdef TARGET_CONFIG_CPU_32
pbrooka8c33202008-05-07 23:22:46 +00001576 __put_user(cpsr_read(env), &sc->arm_cpsr);
bellard43fff232003-07-09 19:31:39 +00001577#endif
1578
pbrooka8c33202008-05-07 23:22:46 +00001579 __put_user(/* current->thread.trap_no */ 0, &sc->trap_no);
1580 __put_user(/* current->thread.error_code */ 0, &sc->error_code);
1581 __put_user(/* current->thread.address */ 0, &sc->fault_address);
1582 __put_user(mask, &sc->oldmask);
bellard43fff232003-07-09 19:31:39 +00001583}
1584
bellard579a97f2007-11-11 14:26:47 +00001585static inline abi_ulong
Andreas Färber05390242012-02-25 03:37:53 +01001586get_sigframe(struct target_sigaction *ka, CPUARMState *regs, int framesize)
bellard43fff232003-07-09 19:31:39 +00001587{
1588 unsigned long sp = regs->regs[13];
1589
bellard43fff232003-07-09 19:31:39 +00001590 /*
1591 * This is the X/Open sanctioned signal stack switching.
1592 */
pbrook624f7972008-05-31 16:11:38 +00001593 if ((ka->sa_flags & TARGET_SA_ONSTACK) && !sas_ss_flags(sp))
thsa04e1342007-09-27 13:57:58 +00001594 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
bellard43fff232003-07-09 19:31:39 +00001595 /*
1596 * ATPCS B01 mandates 8-byte alignment
1597 */
bellard579a97f2007-11-11 14:26:47 +00001598 return (sp - framesize) & ~7;
bellard43fff232003-07-09 19:31:39 +00001599}
1600
1601static int
Andreas Färber05390242012-02-25 03:37:53 +01001602setup_return(CPUARMState *env, struct target_sigaction *ka,
bellardf8b0aa22007-11-11 23:03:42 +00001603 abi_ulong *rc, abi_ulong frame_addr, int usig, abi_ulong rc_addr)
bellard43fff232003-07-09 19:31:39 +00001604{
pbrook624f7972008-05-31 16:11:38 +00001605 abi_ulong handler = ka->_sa_handler;
blueswir1992f48a2007-10-14 16:27:31 +00001606 abi_ulong retcode;
pbrook75b680e2008-03-21 16:07:30 +00001607 int thumb = handler & 1;
Peter Maydell964413d2011-01-14 20:39:19 +01001608 uint32_t cpsr = cpsr_read(env);
1609
1610 cpsr &= ~CPSR_IT;
1611 if (thumb) {
1612 cpsr |= CPSR_T;
1613 } else {
1614 cpsr &= ~CPSR_T;
1615 }
bellard43fff232003-07-09 19:31:39 +00001616
pbrook624f7972008-05-31 16:11:38 +00001617 if (ka->sa_flags & TARGET_SA_RESTORER) {
1618 retcode = ka->sa_restorer;
bellard43fff232003-07-09 19:31:39 +00001619 } else {
1620 unsigned int idx = thumb;
1621
pbrook624f7972008-05-31 16:11:38 +00001622 if (ka->sa_flags & TARGET_SA_SIGINFO)
bellard43fff232003-07-09 19:31:39 +00001623 idx += 2;
1624
1625 if (__put_user(retcodes[idx], rc))
1626 return 1;
Stefan Weilca8a2772011-10-03 22:43:19 +02001627
bellardf8b0aa22007-11-11 23:03:42 +00001628 retcode = rc_addr + thumb;
bellard43fff232003-07-09 19:31:39 +00001629 }
1630
1631 env->regs[0] = usig;
bellardf8b0aa22007-11-11 23:03:42 +00001632 env->regs[13] = frame_addr;
bellard43fff232003-07-09 19:31:39 +00001633 env->regs[14] = retcode;
1634 env->regs[15] = handler & (thumb ? ~1 : ~3);
Peter Maydell964413d2011-01-14 20:39:19 +01001635 cpsr_write(env, cpsr, 0xffffffff);
bellard43fff232003-07-09 19:31:39 +00001636
1637 return 0;
1638}
1639
Andreas Färber05390242012-02-25 03:37:53 +01001640static abi_ulong *setup_sigframe_v2_vfp(abi_ulong *regspace, CPUARMState *env)
Peter Maydell0d871bd2010-11-24 15:20:05 +00001641{
1642 int i;
1643 struct target_vfp_sigframe *vfpframe;
1644 vfpframe = (struct target_vfp_sigframe *)regspace;
1645 __put_user(TARGET_VFP_MAGIC, &vfpframe->magic);
1646 __put_user(sizeof(*vfpframe), &vfpframe->size);
1647 for (i = 0; i < 32; i++) {
Peter Maydell005e1a02011-02-10 13:59:35 +00001648 __put_user(float64_val(env->vfp.regs[i]), &vfpframe->ufp.fpregs[i]);
Peter Maydell0d871bd2010-11-24 15:20:05 +00001649 }
1650 __put_user(vfp_get_fpscr(env), &vfpframe->ufp.fpscr);
1651 __put_user(env->vfp.xregs[ARM_VFP_FPEXC], &vfpframe->ufp_exc.fpexc);
1652 __put_user(env->vfp.xregs[ARM_VFP_FPINST], &vfpframe->ufp_exc.fpinst);
1653 __put_user(env->vfp.xregs[ARM_VFP_FPINST2], &vfpframe->ufp_exc.fpinst2);
1654 return (abi_ulong*)(vfpframe+1);
1655}
1656
Andreas Färber05390242012-02-25 03:37:53 +01001657static abi_ulong *setup_sigframe_v2_iwmmxt(abi_ulong *regspace,
1658 CPUARMState *env)
Peter Maydell08e11252010-11-24 15:20:07 +00001659{
1660 int i;
1661 struct target_iwmmxt_sigframe *iwmmxtframe;
1662 iwmmxtframe = (struct target_iwmmxt_sigframe *)regspace;
1663 __put_user(TARGET_IWMMXT_MAGIC, &iwmmxtframe->magic);
1664 __put_user(sizeof(*iwmmxtframe), &iwmmxtframe->size);
1665 for (i = 0; i < 16; i++) {
1666 __put_user(env->iwmmxt.regs[i], &iwmmxtframe->regs[i]);
1667 }
1668 __put_user(env->vfp.xregs[ARM_IWMMXT_wCSSF], &iwmmxtframe->wcssf);
1669 __put_user(env->vfp.xregs[ARM_IWMMXT_wCASF], &iwmmxtframe->wcssf);
1670 __put_user(env->vfp.xregs[ARM_IWMMXT_wCGR0], &iwmmxtframe->wcgr0);
1671 __put_user(env->vfp.xregs[ARM_IWMMXT_wCGR1], &iwmmxtframe->wcgr1);
1672 __put_user(env->vfp.xregs[ARM_IWMMXT_wCGR2], &iwmmxtframe->wcgr2);
1673 __put_user(env->vfp.xregs[ARM_IWMMXT_wCGR3], &iwmmxtframe->wcgr3);
1674 return (abi_ulong*)(iwmmxtframe+1);
1675}
1676
pbrooka8c33202008-05-07 23:22:46 +00001677static void setup_sigframe_v2(struct target_ucontext_v2 *uc,
Andreas Färber05390242012-02-25 03:37:53 +01001678 target_sigset_t *set, CPUARMState *env)
bellard43fff232003-07-09 19:31:39 +00001679{
pbrooka8c33202008-05-07 23:22:46 +00001680 struct target_sigaltstack stack;
1681 int i;
Peter Maydell0d871bd2010-11-24 15:20:05 +00001682 abi_ulong *regspace;
pbrooka8c33202008-05-07 23:22:46 +00001683
1684 /* Clear all the bits of the ucontext we don't use. */
1685 memset(uc, 0, offsetof(struct target_ucontext_v2, tuc_mcontext));
1686
1687 memset(&stack, 0, sizeof(stack));
1688 __put_user(target_sigaltstack_used.ss_sp, &stack.ss_sp);
1689 __put_user(target_sigaltstack_used.ss_size, &stack.ss_size);
1690 __put_user(sas_ss_flags(get_sp_from_cpustate(env)), &stack.ss_flags);
1691 memcpy(&uc->tuc_stack, &stack, sizeof(stack));
1692
1693 setup_sigcontext(&uc->tuc_mcontext, env, set->sig[0]);
Peter Maydell0d871bd2010-11-24 15:20:05 +00001694 /* Save coprocessor signal frame. */
1695 regspace = uc->tuc_regspace;
1696 if (arm_feature(env, ARM_FEATURE_VFP)) {
1697 regspace = setup_sigframe_v2_vfp(regspace, env);
1698 }
Peter Maydell08e11252010-11-24 15:20:07 +00001699 if (arm_feature(env, ARM_FEATURE_IWMMXT)) {
1700 regspace = setup_sigframe_v2_iwmmxt(regspace, env);
1701 }
1702
Peter Maydell0d871bd2010-11-24 15:20:05 +00001703 /* Write terminating magic word */
1704 __put_user(0, regspace);
1705
pbrooka8c33202008-05-07 23:22:46 +00001706 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
1707 __put_user(set->sig[i], &uc->tuc_sigmask.sig[i]);
1708 }
1709}
1710
1711/* compare linux/arch/arm/kernel/signal.c:setup_frame() */
pbrook624f7972008-05-31 16:11:38 +00001712static void setup_frame_v1(int usig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01001713 target_sigset_t *set, CPUARMState *regs)
pbrooka8c33202008-05-07 23:22:46 +00001714{
1715 struct sigframe_v1 *frame;
bellard579a97f2007-11-11 14:26:47 +00001716 abi_ulong frame_addr = get_sigframe(ka, regs, sizeof(*frame));
pbrooka8c33202008-05-07 23:22:46 +00001717 int i;
bellard43fff232003-07-09 19:31:39 +00001718
bellard579a97f2007-11-11 14:26:47 +00001719 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
1720 return;
1721
pbrooka8c33202008-05-07 23:22:46 +00001722 setup_sigcontext(&frame->sc, regs, set->sig[0]);
bellard43fff232003-07-09 19:31:39 +00001723
bellard92319442004-06-19 16:58:13 +00001724 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
1725 if (__put_user(set->sig[i], &frame->extramask[i - 1]))
bellard579a97f2007-11-11 14:26:47 +00001726 goto end;
bellard43fff232003-07-09 19:31:39 +00001727 }
1728
pbrooka8c33202008-05-07 23:22:46 +00001729 setup_return(regs, ka, &frame->retcode, frame_addr, usig,
1730 frame_addr + offsetof(struct sigframe_v1, retcode));
bellard579a97f2007-11-11 14:26:47 +00001731
1732end:
1733 unlock_user_struct(frame, frame_addr, 1);
pbrooka8c33202008-05-07 23:22:46 +00001734}
1735
pbrook624f7972008-05-31 16:11:38 +00001736static void setup_frame_v2(int usig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01001737 target_sigset_t *set, CPUARMState *regs)
pbrooka8c33202008-05-07 23:22:46 +00001738{
1739 struct sigframe_v2 *frame;
1740 abi_ulong frame_addr = get_sigframe(ka, regs, sizeof(*frame));
1741
1742 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
1743 return;
1744
1745 setup_sigframe_v2(&frame->uc, set, regs);
1746
1747 setup_return(regs, ka, &frame->retcode, frame_addr, usig,
1748 frame_addr + offsetof(struct sigframe_v2, retcode));
1749
1750 unlock_user_struct(frame, frame_addr, 1);
1751}
1752
pbrook624f7972008-05-31 16:11:38 +00001753static void setup_frame(int usig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01001754 target_sigset_t *set, CPUARMState *regs)
pbrooka8c33202008-05-07 23:22:46 +00001755{
1756 if (get_osversion() >= 0x020612) {
1757 setup_frame_v2(usig, ka, set, regs);
1758 } else {
1759 setup_frame_v1(usig, ka, set, regs);
1760 }
bellard43fff232003-07-09 19:31:39 +00001761}
1762
bellard579a97f2007-11-11 14:26:47 +00001763/* compare linux/arch/arm/kernel/signal.c:setup_rt_frame() */
pbrook624f7972008-05-31 16:11:38 +00001764static void setup_rt_frame_v1(int usig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05001765 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01001766 target_sigset_t *set, CPUARMState *env)
bellard43fff232003-07-09 19:31:39 +00001767{
pbrooka745ec62008-05-06 15:36:17 +00001768 struct rt_sigframe_v1 *frame;
bellard579a97f2007-11-11 14:26:47 +00001769 abi_ulong frame_addr = get_sigframe(ka, env, sizeof(*frame));
thsa04e1342007-09-27 13:57:58 +00001770 struct target_sigaltstack stack;
pbrooka8c33202008-05-07 23:22:46 +00001771 int i;
bellardf8b0aa22007-11-11 23:03:42 +00001772 abi_ulong info_addr, uc_addr;
bellard43fff232003-07-09 19:31:39 +00001773
bellard579a97f2007-11-11 14:26:47 +00001774 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
bellardedf779f2004-02-22 13:40:13 +00001775 return /* 1 */;
1776
pbrooka745ec62008-05-06 15:36:17 +00001777 info_addr = frame_addr + offsetof(struct rt_sigframe_v1, info);
pbrooka8c33202008-05-07 23:22:46 +00001778 __put_user(info_addr, &frame->pinfo);
pbrooka745ec62008-05-06 15:36:17 +00001779 uc_addr = frame_addr + offsetof(struct rt_sigframe_v1, uc);
pbrooka8c33202008-05-07 23:22:46 +00001780 __put_user(uc_addr, &frame->puc);
1781 copy_siginfo_to_user(&frame->info, info);
bellard43fff232003-07-09 19:31:39 +00001782
1783 /* Clear all the bits of the ucontext we don't use. */
pbrooka745ec62008-05-06 15:36:17 +00001784 memset(&frame->uc, 0, offsetof(struct target_ucontext_v1, tuc_mcontext));
bellard43fff232003-07-09 19:31:39 +00001785
thsa04e1342007-09-27 13:57:58 +00001786 memset(&stack, 0, sizeof(stack));
1787 __put_user(target_sigaltstack_used.ss_sp, &stack.ss_sp);
1788 __put_user(target_sigaltstack_used.ss_size, &stack.ss_size);
1789 __put_user(sas_ss_flags(get_sp_from_cpustate(env)), &stack.ss_flags);
bellard775b58d2007-11-11 16:22:17 +00001790 memcpy(&frame->uc.tuc_stack, &stack, sizeof(stack));
thsa04e1342007-09-27 13:57:58 +00001791
pbrooka8c33202008-05-07 23:22:46 +00001792 setup_sigcontext(&frame->uc.tuc_mcontext, env, set->sig[0]);
bellard92319442004-06-19 16:58:13 +00001793 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
bellardb8076a72005-04-07 22:20:31 +00001794 if (__put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]))
bellard579a97f2007-11-11 14:26:47 +00001795 goto end;
bellard92319442004-06-19 16:58:13 +00001796 }
bellard43fff232003-07-09 19:31:39 +00001797
pbrooka8c33202008-05-07 23:22:46 +00001798 setup_return(env, ka, &frame->retcode, frame_addr, usig,
1799 frame_addr + offsetof(struct rt_sigframe_v1, retcode));
pbrooka745ec62008-05-06 15:36:17 +00001800
pbrooka8c33202008-05-07 23:22:46 +00001801 env->regs[1] = info_addr;
1802 env->regs[2] = uc_addr;
pbrooka745ec62008-05-06 15:36:17 +00001803
1804end:
1805 unlock_user_struct(frame, frame_addr, 1);
pbrooka745ec62008-05-06 15:36:17 +00001806}
1807
pbrook624f7972008-05-31 16:11:38 +00001808static void setup_rt_frame_v2(int usig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05001809 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01001810 target_sigset_t *set, CPUARMState *env)
pbrooka745ec62008-05-06 15:36:17 +00001811{
1812 struct rt_sigframe_v2 *frame;
1813 abi_ulong frame_addr = get_sigframe(ka, env, sizeof(*frame));
pbrooka745ec62008-05-06 15:36:17 +00001814 abi_ulong info_addr, uc_addr;
1815
1816 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
1817 return /* 1 */;
1818
1819 info_addr = frame_addr + offsetof(struct rt_sigframe_v2, info);
1820 uc_addr = frame_addr + offsetof(struct rt_sigframe_v2, uc);
pbrooka8c33202008-05-07 23:22:46 +00001821 copy_siginfo_to_user(&frame->info, info);
pbrooka745ec62008-05-06 15:36:17 +00001822
pbrooka8c33202008-05-07 23:22:46 +00001823 setup_sigframe_v2(&frame->uc, set, env);
pbrooka745ec62008-05-06 15:36:17 +00001824
pbrooka8c33202008-05-07 23:22:46 +00001825 setup_return(env, ka, &frame->retcode, frame_addr, usig,
1826 frame_addr + offsetof(struct rt_sigframe_v2, retcode));
pbrooka745ec62008-05-06 15:36:17 +00001827
pbrooka8c33202008-05-07 23:22:46 +00001828 env->regs[1] = info_addr;
1829 env->regs[2] = uc_addr;
pbrooka745ec62008-05-06 15:36:17 +00001830
bellard579a97f2007-11-11 14:26:47 +00001831 unlock_user_struct(frame, frame_addr, 1);
bellard43fff232003-07-09 19:31:39 +00001832}
1833
pbrook624f7972008-05-31 16:11:38 +00001834static void setup_rt_frame(int usig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05001835 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01001836 target_sigset_t *set, CPUARMState *env)
pbrooka745ec62008-05-06 15:36:17 +00001837{
1838 if (get_osversion() >= 0x020612) {
1839 setup_rt_frame_v2(usig, ka, info, set, env);
1840 } else {
1841 setup_rt_frame_v1(usig, ka, info, set, env);
1842 }
1843}
1844
bellard43fff232003-07-09 19:31:39 +00001845static int
Andreas Färber05390242012-02-25 03:37:53 +01001846restore_sigcontext(CPUARMState *env, struct target_sigcontext *sc)
bellard43fff232003-07-09 19:31:39 +00001847{
1848 int err = 0;
bellardb5ff1b32005-11-26 10:38:39 +00001849 uint32_t cpsr;
bellard43fff232003-07-09 19:31:39 +00001850
Riku Voipio1d8b5122014-04-23 10:26:05 +03001851 __get_user(env->regs[0], &sc->arm_r0);
1852 __get_user(env->regs[1], &sc->arm_r1);
1853 __get_user(env->regs[2], &sc->arm_r2);
1854 __get_user(env->regs[3], &sc->arm_r3);
1855 __get_user(env->regs[4], &sc->arm_r4);
1856 __get_user(env->regs[5], &sc->arm_r5);
1857 __get_user(env->regs[6], &sc->arm_r6);
1858 __get_user(env->regs[7], &sc->arm_r7);
1859 __get_user(env->regs[8], &sc->arm_r8);
1860 __get_user(env->regs[9], &sc->arm_r9);
1861 __get_user(env->regs[10], &sc->arm_r10);
1862 __get_user(env->regs[11], &sc->arm_fp);
1863 __get_user(env->regs[12], &sc->arm_ip);
1864 __get_user(env->regs[13], &sc->arm_sp);
1865 __get_user(env->regs[14], &sc->arm_lr);
1866 __get_user(env->regs[15], &sc->arm_pc);
bellard43fff232003-07-09 19:31:39 +00001867#ifdef TARGET_CONFIG_CPU_32
Riku Voipio1d8b5122014-04-23 10:26:05 +03001868 __get_user(cpsr, &sc->arm_cpsr);
pbrook75b680e2008-03-21 16:07:30 +00001869 cpsr_write(env, cpsr, CPSR_USER | CPSR_EXEC);
bellard43fff232003-07-09 19:31:39 +00001870#endif
1871
1872 err |= !valid_user_regs(env);
1873
1874 return err;
1875}
1876
Andreas Färber05390242012-02-25 03:37:53 +01001877static long do_sigreturn_v1(CPUARMState *env)
bellard43fff232003-07-09 19:31:39 +00001878{
bellardf8b0aa22007-11-11 23:03:42 +00001879 abi_ulong frame_addr;
Peter Maydell978fae92013-07-29 12:00:32 +01001880 struct sigframe_v1 *frame = NULL;
Anthony Liguoric227f092009-10-01 16:12:16 -05001881 target_sigset_t set;
bellard43fff232003-07-09 19:31:39 +00001882 sigset_t host_set;
bellard92319442004-06-19 16:58:13 +00001883 int i;
bellard43fff232003-07-09 19:31:39 +00001884
1885 /*
1886 * Since we stacked the signal on a 64-bit boundary,
1887 * then 'sp' should be word aligned here. If it's
1888 * not, then the user is trying to mess with us.
1889 */
bellardf8b0aa22007-11-11 23:03:42 +00001890 frame_addr = env->regs[13];
Peter Maydell978fae92013-07-29 12:00:32 +01001891 if (frame_addr & 7) {
1892 goto badframe;
1893 }
1894
bellardf8b0aa22007-11-11 23:03:42 +00001895 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
1896 goto badframe;
bellard43fff232003-07-09 19:31:39 +00001897
bellard92319442004-06-19 16:58:13 +00001898 if (__get_user(set.sig[0], &frame->sc.oldmask))
1899 goto badframe;
1900 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
1901 if (__get_user(set.sig[i], &frame->extramask[i - 1]))
1902 goto badframe;
1903 }
bellard43fff232003-07-09 19:31:39 +00001904
bellard92319442004-06-19 16:58:13 +00001905 target_to_host_sigset_internal(&host_set, &set);
Alex Barcelo1c275922014-03-14 14:36:55 +00001906 do_sigprocmask(SIG_SETMASK, &host_set, NULL);
bellard43fff232003-07-09 19:31:39 +00001907
1908 if (restore_sigcontext(env, &frame->sc))
1909 goto badframe;
1910
1911#if 0
1912 /* Send SIGTRAP if we're single-stepping */
1913 if (ptrace_cancel_bpt(current))
1914 send_sig(SIGTRAP, current, 1);
1915#endif
bellardf8b0aa22007-11-11 23:03:42 +00001916 unlock_user_struct(frame, frame_addr, 0);
1917 return env->regs[0];
bellard43fff232003-07-09 19:31:39 +00001918
1919badframe:
bellardf8b0aa22007-11-11 23:03:42 +00001920 unlock_user_struct(frame, frame_addr, 0);
Riku Voipio66393fb2009-12-04 15:16:32 +02001921 force_sig(TARGET_SIGSEGV /* , current */);
bellard43fff232003-07-09 19:31:39 +00001922 return 0;
1923}
1924
Andreas Färber05390242012-02-25 03:37:53 +01001925static abi_ulong *restore_sigframe_v2_vfp(CPUARMState *env, abi_ulong *regspace)
Peter Maydell5f9099d2010-11-24 15:20:06 +00001926{
1927 int i;
1928 abi_ulong magic, sz;
1929 uint32_t fpscr, fpexc;
1930 struct target_vfp_sigframe *vfpframe;
1931 vfpframe = (struct target_vfp_sigframe *)regspace;
1932
1933 __get_user(magic, &vfpframe->magic);
1934 __get_user(sz, &vfpframe->size);
1935 if (magic != TARGET_VFP_MAGIC || sz != sizeof(*vfpframe)) {
1936 return 0;
1937 }
1938 for (i = 0; i < 32; i++) {
Peter Maydell005e1a02011-02-10 13:59:35 +00001939 __get_user(float64_val(env->vfp.regs[i]), &vfpframe->ufp.fpregs[i]);
Peter Maydell5f9099d2010-11-24 15:20:06 +00001940 }
1941 __get_user(fpscr, &vfpframe->ufp.fpscr);
1942 vfp_set_fpscr(env, fpscr);
1943 __get_user(fpexc, &vfpframe->ufp_exc.fpexc);
1944 /* Sanitise FPEXC: ensure VFP is enabled, FPINST2 is invalid
1945 * and the exception flag is cleared
1946 */
1947 fpexc |= (1 << 30);
1948 fpexc &= ~((1 << 31) | (1 << 28));
1949 env->vfp.xregs[ARM_VFP_FPEXC] = fpexc;
1950 __get_user(env->vfp.xregs[ARM_VFP_FPINST], &vfpframe->ufp_exc.fpinst);
1951 __get_user(env->vfp.xregs[ARM_VFP_FPINST2], &vfpframe->ufp_exc.fpinst2);
1952 return (abi_ulong*)(vfpframe + 1);
1953}
1954
Andreas Färber05390242012-02-25 03:37:53 +01001955static abi_ulong *restore_sigframe_v2_iwmmxt(CPUARMState *env,
1956 abi_ulong *regspace)
Peter Maydella59d69d2010-11-24 15:20:08 +00001957{
1958 int i;
1959 abi_ulong magic, sz;
1960 struct target_iwmmxt_sigframe *iwmmxtframe;
1961 iwmmxtframe = (struct target_iwmmxt_sigframe *)regspace;
1962
1963 __get_user(magic, &iwmmxtframe->magic);
1964 __get_user(sz, &iwmmxtframe->size);
1965 if (magic != TARGET_IWMMXT_MAGIC || sz != sizeof(*iwmmxtframe)) {
1966 return 0;
1967 }
1968 for (i = 0; i < 16; i++) {
1969 __get_user(env->iwmmxt.regs[i], &iwmmxtframe->regs[i]);
1970 }
1971 __get_user(env->vfp.xregs[ARM_IWMMXT_wCSSF], &iwmmxtframe->wcssf);
1972 __get_user(env->vfp.xregs[ARM_IWMMXT_wCASF], &iwmmxtframe->wcssf);
1973 __get_user(env->vfp.xregs[ARM_IWMMXT_wCGR0], &iwmmxtframe->wcgr0);
1974 __get_user(env->vfp.xregs[ARM_IWMMXT_wCGR1], &iwmmxtframe->wcgr1);
1975 __get_user(env->vfp.xregs[ARM_IWMMXT_wCGR2], &iwmmxtframe->wcgr2);
1976 __get_user(env->vfp.xregs[ARM_IWMMXT_wCGR3], &iwmmxtframe->wcgr3);
1977 return (abi_ulong*)(iwmmxtframe + 1);
1978}
1979
Andreas Färber05390242012-02-25 03:37:53 +01001980static int do_sigframe_return_v2(CPUARMState *env, target_ulong frame_addr,
pbrooka8c33202008-05-07 23:22:46 +00001981 struct target_ucontext_v2 *uc)
1982{
1983 sigset_t host_set;
Peter Maydell5f9099d2010-11-24 15:20:06 +00001984 abi_ulong *regspace;
pbrooka8c33202008-05-07 23:22:46 +00001985
1986 target_to_host_sigset(&host_set, &uc->tuc_sigmask);
Alex Barcelo1c275922014-03-14 14:36:55 +00001987 do_sigprocmask(SIG_SETMASK, &host_set, NULL);
pbrooka8c33202008-05-07 23:22:46 +00001988
1989 if (restore_sigcontext(env, &uc->tuc_mcontext))
1990 return 1;
1991
Peter Maydell5f9099d2010-11-24 15:20:06 +00001992 /* Restore coprocessor signal frame */
1993 regspace = uc->tuc_regspace;
1994 if (arm_feature(env, ARM_FEATURE_VFP)) {
1995 regspace = restore_sigframe_v2_vfp(env, regspace);
1996 if (!regspace) {
1997 return 1;
1998 }
1999 }
Peter Maydella59d69d2010-11-24 15:20:08 +00002000 if (arm_feature(env, ARM_FEATURE_IWMMXT)) {
2001 regspace = restore_sigframe_v2_iwmmxt(env, regspace);
2002 if (!regspace) {
2003 return 1;
2004 }
2005 }
Peter Maydell5f9099d2010-11-24 15:20:06 +00002006
pbrooka8c33202008-05-07 23:22:46 +00002007 if (do_sigaltstack(frame_addr + offsetof(struct target_ucontext_v2, tuc_stack), 0, get_sp_from_cpustate(env)) == -EFAULT)
2008 return 1;
2009
2010#if 0
2011 /* Send SIGTRAP if we're single-stepping */
2012 if (ptrace_cancel_bpt(current))
2013 send_sig(SIGTRAP, current, 1);
2014#endif
2015
2016 return 0;
2017}
2018
Andreas Färber05390242012-02-25 03:37:53 +01002019static long do_sigreturn_v2(CPUARMState *env)
pbrooka8c33202008-05-07 23:22:46 +00002020{
2021 abi_ulong frame_addr;
Peter Maydell978fae92013-07-29 12:00:32 +01002022 struct sigframe_v2 *frame = NULL;
pbrooka8c33202008-05-07 23:22:46 +00002023
2024 /*
2025 * Since we stacked the signal on a 64-bit boundary,
2026 * then 'sp' should be word aligned here. If it's
2027 * not, then the user is trying to mess with us.
2028 */
pbrooka8c33202008-05-07 23:22:46 +00002029 frame_addr = env->regs[13];
Peter Maydell978fae92013-07-29 12:00:32 +01002030 if (frame_addr & 7) {
2031 goto badframe;
2032 }
2033
pbrooka8c33202008-05-07 23:22:46 +00002034 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
2035 goto badframe;
2036
2037 if (do_sigframe_return_v2(env, frame_addr, &frame->uc))
2038 goto badframe;
2039
2040 unlock_user_struct(frame, frame_addr, 0);
2041 return env->regs[0];
2042
2043badframe:
2044 unlock_user_struct(frame, frame_addr, 0);
Riku Voipio66393fb2009-12-04 15:16:32 +02002045 force_sig(TARGET_SIGSEGV /* , current */);
pbrooka8c33202008-05-07 23:22:46 +00002046 return 0;
2047}
2048
Andreas Färber05390242012-02-25 03:37:53 +01002049long do_sigreturn(CPUARMState *env)
pbrooka8c33202008-05-07 23:22:46 +00002050{
2051 if (get_osversion() >= 0x020612) {
2052 return do_sigreturn_v2(env);
2053 } else {
2054 return do_sigreturn_v1(env);
2055 }
2056}
2057
Andreas Färber05390242012-02-25 03:37:53 +01002058static long do_rt_sigreturn_v1(CPUARMState *env)
bellard43fff232003-07-09 19:31:39 +00002059{
bellardf8b0aa22007-11-11 23:03:42 +00002060 abi_ulong frame_addr;
Peter Maydell978fae92013-07-29 12:00:32 +01002061 struct rt_sigframe_v1 *frame = NULL;
bellard43fff232003-07-09 19:31:39 +00002062 sigset_t host_set;
2063
2064 /*
2065 * Since we stacked the signal on a 64-bit boundary,
2066 * then 'sp' should be word aligned here. If it's
2067 * not, then the user is trying to mess with us.
2068 */
bellardf8b0aa22007-11-11 23:03:42 +00002069 frame_addr = env->regs[13];
Peter Maydell978fae92013-07-29 12:00:32 +01002070 if (frame_addr & 7) {
2071 goto badframe;
2072 }
2073
bellardf8b0aa22007-11-11 23:03:42 +00002074 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
2075 goto badframe;
bellard43fff232003-07-09 19:31:39 +00002076
bellardb8076a72005-04-07 22:20:31 +00002077 target_to_host_sigset(&host_set, &frame->uc.tuc_sigmask);
Alex Barcelo1c275922014-03-14 14:36:55 +00002078 do_sigprocmask(SIG_SETMASK, &host_set, NULL);
bellard43fff232003-07-09 19:31:39 +00002079
bellardb8076a72005-04-07 22:20:31 +00002080 if (restore_sigcontext(env, &frame->uc.tuc_mcontext))
bellard43fff232003-07-09 19:31:39 +00002081 goto badframe;
2082
pbrooka745ec62008-05-06 15:36:17 +00002083 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 +00002084 goto badframe;
2085
bellard43fff232003-07-09 19:31:39 +00002086#if 0
2087 /* Send SIGTRAP if we're single-stepping */
2088 if (ptrace_cancel_bpt(current))
2089 send_sig(SIGTRAP, current, 1);
2090#endif
bellardf8b0aa22007-11-11 23:03:42 +00002091 unlock_user_struct(frame, frame_addr, 0);
bellard43fff232003-07-09 19:31:39 +00002092 return env->regs[0];
2093
2094badframe:
bellardf8b0aa22007-11-11 23:03:42 +00002095 unlock_user_struct(frame, frame_addr, 0);
Riku Voipio66393fb2009-12-04 15:16:32 +02002096 force_sig(TARGET_SIGSEGV /* , current */);
bellard43fff232003-07-09 19:31:39 +00002097 return 0;
2098}
2099
Andreas Färber05390242012-02-25 03:37:53 +01002100static long do_rt_sigreturn_v2(CPUARMState *env)
pbrooka745ec62008-05-06 15:36:17 +00002101{
2102 abi_ulong frame_addr;
Peter Maydell978fae92013-07-29 12:00:32 +01002103 struct rt_sigframe_v2 *frame = NULL;
pbrooka745ec62008-05-06 15:36:17 +00002104
2105 /*
2106 * Since we stacked the signal on a 64-bit boundary,
2107 * then 'sp' should be word aligned here. If it's
2108 * not, then the user is trying to mess with us.
2109 */
pbrooka745ec62008-05-06 15:36:17 +00002110 frame_addr = env->regs[13];
Peter Maydell978fae92013-07-29 12:00:32 +01002111 if (frame_addr & 7) {
2112 goto badframe;
2113 }
2114
pbrooka745ec62008-05-06 15:36:17 +00002115 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
2116 goto badframe;
2117
pbrooka8c33202008-05-07 23:22:46 +00002118 if (do_sigframe_return_v2(env, frame_addr, &frame->uc))
2119 goto badframe;
pbrooka745ec62008-05-06 15:36:17 +00002120
pbrooka745ec62008-05-06 15:36:17 +00002121 unlock_user_struct(frame, frame_addr, 0);
2122 return env->regs[0];
2123
2124badframe:
2125 unlock_user_struct(frame, frame_addr, 0);
Riku Voipio66393fb2009-12-04 15:16:32 +02002126 force_sig(TARGET_SIGSEGV /* , current */);
pbrooka745ec62008-05-06 15:36:17 +00002127 return 0;
2128}
2129
Andreas Färber05390242012-02-25 03:37:53 +01002130long do_rt_sigreturn(CPUARMState *env)
pbrooka745ec62008-05-06 15:36:17 +00002131{
2132 if (get_osversion() >= 0x020612) {
2133 return do_rt_sigreturn_v2(env);
2134 } else {
2135 return do_rt_sigreturn_v1(env);
2136 }
2137}
2138
bellard6d5e2162004-09-30 22:04:13 +00002139#elif defined(TARGET_SPARC)
bellard80a9d032005-01-03 23:31:27 +00002140
bellard6d5e2162004-09-30 22:04:13 +00002141#define __SUNOS_MAXWIN 31
2142
2143/* This is what SunOS does, so shall I. */
2144struct target_sigcontext {
blueswir1992f48a2007-10-14 16:27:31 +00002145 abi_ulong sigc_onstack; /* state to restore */
bellard6d5e2162004-09-30 22:04:13 +00002146
blueswir1992f48a2007-10-14 16:27:31 +00002147 abi_ulong sigc_mask; /* sigmask to restore */
2148 abi_ulong sigc_sp; /* stack pointer */
2149 abi_ulong sigc_pc; /* program counter */
2150 abi_ulong sigc_npc; /* next program counter */
2151 abi_ulong sigc_psr; /* for condition codes etc */
2152 abi_ulong sigc_g1; /* User uses these two registers */
2153 abi_ulong sigc_o0; /* within the trampoline code. */
bellard6d5e2162004-09-30 22:04:13 +00002154
2155 /* Now comes information regarding the users window set
2156 * at the time of the signal.
2157 */
blueswir1992f48a2007-10-14 16:27:31 +00002158 abi_ulong sigc_oswins; /* outstanding windows */
bellard6d5e2162004-09-30 22:04:13 +00002159
2160 /* stack ptrs for each regwin buf */
2161 char *sigc_spbuf[__SUNOS_MAXWIN];
2162
2163 /* Windows to restore after signal */
2164 struct {
blueswir1992f48a2007-10-14 16:27:31 +00002165 abi_ulong locals[8];
2166 abi_ulong ins[8];
bellard6d5e2162004-09-30 22:04:13 +00002167 } sigc_wbuf[__SUNOS_MAXWIN];
2168};
2169/* A Sparc stack frame */
2170struct sparc_stackf {
blueswir1992f48a2007-10-14 16:27:31 +00002171 abi_ulong locals[8];
Peter Maydelle321c342011-02-01 15:54:52 +00002172 abi_ulong ins[8];
2173 /* It's simpler to treat fp and callers_pc as elements of ins[]
2174 * since we never need to access them ourselves.
2175 */
bellard6d5e2162004-09-30 22:04:13 +00002176 char *structptr;
blueswir1992f48a2007-10-14 16:27:31 +00002177 abi_ulong xargs[6];
2178 abi_ulong xxargs[1];
bellard6d5e2162004-09-30 22:04:13 +00002179};
2180
2181typedef struct {
2182 struct {
blueswir1992f48a2007-10-14 16:27:31 +00002183 abi_ulong psr;
2184 abi_ulong pc;
2185 abi_ulong npc;
2186 abi_ulong y;
2187 abi_ulong u_regs[16]; /* globals and ins */
bellard6d5e2162004-09-30 22:04:13 +00002188 } si_regs;
2189 int si_mask;
2190} __siginfo_t;
2191
2192typedef struct {
Blue Swirl8954bae2012-07-30 15:29:11 +00002193 abi_ulong si_float_regs[32];
bellard6d5e2162004-09-30 22:04:13 +00002194 unsigned long si_fsr;
2195 unsigned long si_fpqdepth;
2196 struct {
2197 unsigned long *insn_addr;
2198 unsigned long insn;
2199 } si_fpqueue [16];
Anthony Liguoric227f092009-10-01 16:12:16 -05002200} qemu_siginfo_fpu_t;
bellard6d5e2162004-09-30 22:04:13 +00002201
2202
2203struct target_signal_frame {
2204 struct sparc_stackf ss;
2205 __siginfo_t info;
bellardf8b0aa22007-11-11 23:03:42 +00002206 abi_ulong fpu_save;
blueswir1992f48a2007-10-14 16:27:31 +00002207 abi_ulong insns[2] __attribute__ ((aligned (8)));
2208 abi_ulong extramask[TARGET_NSIG_WORDS - 1];
2209 abi_ulong extra_size; /* Should be 0 */
Anthony Liguoric227f092009-10-01 16:12:16 -05002210 qemu_siginfo_fpu_t fpu_state;
bellard6d5e2162004-09-30 22:04:13 +00002211};
2212struct target_rt_signal_frame {
2213 struct sparc_stackf ss;
2214 siginfo_t info;
blueswir1992f48a2007-10-14 16:27:31 +00002215 abi_ulong regs[20];
bellard6d5e2162004-09-30 22:04:13 +00002216 sigset_t mask;
bellardf8b0aa22007-11-11 23:03:42 +00002217 abi_ulong fpu_save;
bellard6d5e2162004-09-30 22:04:13 +00002218 unsigned int insns[2];
2219 stack_t stack;
2220 unsigned int extra_size; /* Should be 0 */
Anthony Liguoric227f092009-10-01 16:12:16 -05002221 qemu_siginfo_fpu_t fpu_state;
bellard6d5e2162004-09-30 22:04:13 +00002222};
2223
bellarde80cfcf2004-12-19 23:18:01 +00002224#define UREG_O0 16
2225#define UREG_O6 22
2226#define UREG_I0 0
2227#define UREG_I1 1
2228#define UREG_I2 2
blueswir15bfb56b2007-10-05 17:01:51 +00002229#define UREG_I3 3
2230#define UREG_I4 4
2231#define UREG_I5 5
bellarde80cfcf2004-12-19 23:18:01 +00002232#define UREG_I6 6
2233#define UREG_I7 7
2234#define UREG_L0 8
bellard6d5e2162004-09-30 22:04:13 +00002235#define UREG_FP UREG_I6
2236#define UREG_SP UREG_O6
2237
pbrook624f7972008-05-31 16:11:38 +00002238static inline abi_ulong get_sigframe(struct target_sigaction *sa,
Andreas Färber05390242012-02-25 03:37:53 +01002239 CPUSPARCState *env,
2240 unsigned long framesize)
bellard6d5e2162004-09-30 22:04:13 +00002241{
bellard459a4012007-11-11 19:45:10 +00002242 abi_ulong sp;
bellard6d5e2162004-09-30 22:04:13 +00002243
2244 sp = env->regwptr[UREG_FP];
bellard6d5e2162004-09-30 22:04:13 +00002245
2246 /* This is the X/Open sanctioned signal stack switching. */
pbrook624f7972008-05-31 16:11:38 +00002247 if (sa->sa_flags & TARGET_SA_ONSTACK) {
thsa04e1342007-09-27 13:57:58 +00002248 if (!on_sig_stack(sp)
2249 && !((target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size) & 7))
2250 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
bellard6d5e2162004-09-30 22:04:13 +00002251 }
bellard459a4012007-11-11 19:45:10 +00002252 return sp - framesize;
bellard6d5e2162004-09-30 22:04:13 +00002253}
2254
2255static int
Andreas Färber05390242012-02-25 03:37:53 +01002256setup___siginfo(__siginfo_t *si, CPUSPARCState *env, abi_ulong mask)
bellard6d5e2162004-09-30 22:04:13 +00002257{
2258 int err = 0, i;
2259
Riku Voipio1d8b5122014-04-23 10:26:05 +03002260 __put_user(env->psr, &si->si_regs.psr);
2261 __put_user(env->pc, &si->si_regs.pc);
2262 __put_user(env->npc, &si->si_regs.npc);
2263 __put_user(env->y, &si->si_regs.y);
bellarda315a142005-01-30 22:59:18 +00002264 for (i=0; i < 8; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002265 __put_user(env->gregs[i], &si->si_regs.u_regs[i]);
bellard6d5e2162004-09-30 22:04:13 +00002266 }
bellarda315a142005-01-30 22:59:18 +00002267 for (i=0; i < 8; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002268 __put_user(env->regwptr[UREG_I0 + i], &si->si_regs.u_regs[i+8]);
bellard6d5e2162004-09-30 22:04:13 +00002269 }
Riku Voipio1d8b5122014-04-23 10:26:05 +03002270 __put_user(mask, &si->si_mask);
bellard6d5e2162004-09-30 22:04:13 +00002271 return err;
2272}
bellarde80cfcf2004-12-19 23:18:01 +00002273
bellard80a9d032005-01-03 23:31:27 +00002274#if 0
bellard6d5e2162004-09-30 22:04:13 +00002275static int
2276setup_sigcontext(struct target_sigcontext *sc, /*struct _fpstate *fpstate,*/
Andreas Färber05390242012-02-25 03:37:53 +01002277 CPUSPARCState *env, unsigned long mask)
bellard6d5e2162004-09-30 22:04:13 +00002278{
2279 int err = 0;
2280
Riku Voipio1d8b5122014-04-23 10:26:05 +03002281 __put_user(mask, &sc->sigc_mask);
2282 __put_user(env->regwptr[UREG_SP], &sc->sigc_sp);
2283 __put_user(env->pc, &sc->sigc_pc);
2284 __put_user(env->npc, &sc->sigc_npc);
2285 __put_user(env->psr, &sc->sigc_psr);
2286 __put_user(env->gregs[1], &sc->sigc_g1);
2287 __put_user(env->regwptr[UREG_O0], &sc->sigc_o0);
bellard6d5e2162004-09-30 22:04:13 +00002288
2289 return err;
2290}
bellard80a9d032005-01-03 23:31:27 +00002291#endif
bellard6d5e2162004-09-30 22:04:13 +00002292#define NF_ALIGNEDSZ (((sizeof(struct target_signal_frame) + 7) & (~7)))
2293
pbrook624f7972008-05-31 16:11:38 +00002294static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01002295 target_sigset_t *set, CPUSPARCState *env)
bellard6d5e2162004-09-30 22:04:13 +00002296{
bellard459a4012007-11-11 19:45:10 +00002297 abi_ulong sf_addr;
bellard6d5e2162004-09-30 22:04:13 +00002298 struct target_signal_frame *sf;
2299 int sigframe_size, err, i;
2300
2301 /* 1. Make sure everything is clean */
2302 //synchronize_user_stack();
2303
2304 sigframe_size = NF_ALIGNEDSZ;
bellard459a4012007-11-11 19:45:10 +00002305 sf_addr = get_sigframe(ka, env, sigframe_size);
bellard6d5e2162004-09-30 22:04:13 +00002306
bellard459a4012007-11-11 19:45:10 +00002307 sf = lock_user(VERIFY_WRITE, sf_addr,
2308 sizeof(struct target_signal_frame), 0);
2309 if (!sf)
2310 goto sigsegv;
2311
bellarde80cfcf2004-12-19 23:18:01 +00002312 //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 +00002313#if 0
2314 if (invalid_frame_pointer(sf, sigframe_size))
2315 goto sigill_and_return;
2316#endif
2317 /* 2. Save the current process state */
2318 err = setup___siginfo(&sf->info, env, set->sig[0]);
Riku Voipio1d8b5122014-04-23 10:26:05 +03002319 __put_user(0, &sf->extra_size);
bellard6d5e2162004-09-30 22:04:13 +00002320
Riku Voipio1d8b5122014-04-23 10:26:05 +03002321 //save_fpu_state(regs, &sf->fpu_state);
2322 //__put_user(&sf->fpu_state, &sf->fpu_save);
bellard6d5e2162004-09-30 22:04:13 +00002323
Riku Voipio1d8b5122014-04-23 10:26:05 +03002324 __put_user(set->sig[0], &sf->info.si_mask);
bellard6d5e2162004-09-30 22:04:13 +00002325 for (i = 0; i < TARGET_NSIG_WORDS - 1; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002326 __put_user(set->sig[i + 1], &sf->extramask[i]);
bellard6d5e2162004-09-30 22:04:13 +00002327 }
2328
bellarda315a142005-01-30 22:59:18 +00002329 for (i = 0; i < 8; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002330 __put_user(env->regwptr[i + UREG_L0], &sf->ss.locals[i]);
bellard6d5e2162004-09-30 22:04:13 +00002331 }
bellarda315a142005-01-30 22:59:18 +00002332 for (i = 0; i < 8; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002333 __put_user(env->regwptr[i + UREG_I0], &sf->ss.ins[i]);
bellard6d5e2162004-09-30 22:04:13 +00002334 }
bellard6d5e2162004-09-30 22:04:13 +00002335 if (err)
2336 goto sigsegv;
2337
2338 /* 3. signal handler back-trampoline and parameters */
bellard459a4012007-11-11 19:45:10 +00002339 env->regwptr[UREG_FP] = sf_addr;
bellard6d5e2162004-09-30 22:04:13 +00002340 env->regwptr[UREG_I0] = sig;
bellard459a4012007-11-11 19:45:10 +00002341 env->regwptr[UREG_I1] = sf_addr +
2342 offsetof(struct target_signal_frame, info);
2343 env->regwptr[UREG_I2] = sf_addr +
2344 offsetof(struct target_signal_frame, info);
bellard6d5e2162004-09-30 22:04:13 +00002345
2346 /* 4. signal handler */
pbrook624f7972008-05-31 16:11:38 +00002347 env->pc = ka->_sa_handler;
bellard6d5e2162004-09-30 22:04:13 +00002348 env->npc = (env->pc + 4);
2349 /* 5. return to kernel instructions */
pbrook624f7972008-05-31 16:11:38 +00002350 if (ka->sa_restorer)
2351 env->regwptr[UREG_I7] = ka->sa_restorer;
bellard6d5e2162004-09-30 22:04:13 +00002352 else {
bellard775b58d2007-11-11 16:22:17 +00002353 uint32_t val32;
bellard459a4012007-11-11 19:45:10 +00002354
2355 env->regwptr[UREG_I7] = sf_addr +
2356 offsetof(struct target_signal_frame, insns) - 2 * 4;
bellard6d5e2162004-09-30 22:04:13 +00002357
2358 /* mov __NR_sigreturn, %g1 */
bellard775b58d2007-11-11 16:22:17 +00002359 val32 = 0x821020d8;
Riku Voipio1d8b5122014-04-23 10:26:05 +03002360 __put_user(val32, &sf->insns[0]);
bellard6d5e2162004-09-30 22:04:13 +00002361
2362 /* t 0x10 */
bellard775b58d2007-11-11 16:22:17 +00002363 val32 = 0x91d02010;
Riku Voipio1d8b5122014-04-23 10:26:05 +03002364 __put_user(val32, &sf->insns[1]);
bellard6d5e2162004-09-30 22:04:13 +00002365 if (err)
2366 goto sigsegv;
2367
2368 /* Flush instruction space. */
2369 //flush_sig_insns(current->mm, (unsigned long) &(sf->insns[0]));
bellard80a9d032005-01-03 23:31:27 +00002370 // tb_flush(env);
bellard6d5e2162004-09-30 22:04:13 +00002371 }
bellard459a4012007-11-11 19:45:10 +00002372 unlock_user(sf, sf_addr, sizeof(struct target_signal_frame));
bellard6d5e2162004-09-30 22:04:13 +00002373 return;
bellard459a4012007-11-11 19:45:10 +00002374#if 0
2375sigill_and_return:
bellard6d5e2162004-09-30 22:04:13 +00002376 force_sig(TARGET_SIGILL);
bellard459a4012007-11-11 19:45:10 +00002377#endif
bellard6d5e2162004-09-30 22:04:13 +00002378sigsegv:
bellarde80cfcf2004-12-19 23:18:01 +00002379 //fprintf(stderr, "force_sig\n");
bellard459a4012007-11-11 19:45:10 +00002380 unlock_user(sf, sf_addr, sizeof(struct target_signal_frame));
bellard6d5e2162004-09-30 22:04:13 +00002381 force_sig(TARGET_SIGSEGV);
2382}
bellard6d5e2162004-09-30 22:04:13 +00002383
pbrook624f7972008-05-31 16:11:38 +00002384static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05002385 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01002386 target_sigset_t *set, CPUSPARCState *env)
bellard6d5e2162004-09-30 22:04:13 +00002387{
2388 fprintf(stderr, "setup_rt_frame: not implemented\n");
2389}
2390
Andreas Färber05390242012-02-25 03:37:53 +01002391long do_sigreturn(CPUSPARCState *env)
bellard6d5e2162004-09-30 22:04:13 +00002392{
bellardf8b0aa22007-11-11 23:03:42 +00002393 abi_ulong sf_addr;
bellard6d5e2162004-09-30 22:04:13 +00002394 struct target_signal_frame *sf;
bellarde80cfcf2004-12-19 23:18:01 +00002395 uint32_t up_psr, pc, npc;
Anthony Liguoric227f092009-10-01 16:12:16 -05002396 target_sigset_t set;
bellarde80cfcf2004-12-19 23:18:01 +00002397 sigset_t host_set;
Riku Voipio1d8b5122014-04-23 10:26:05 +03002398 int err=0, i;
bellard6d5e2162004-09-30 22:04:13 +00002399
bellardf8b0aa22007-11-11 23:03:42 +00002400 sf_addr = env->regwptr[UREG_FP];
2401 if (!lock_user_struct(VERIFY_READ, sf, sf_addr, 1))
2402 goto segv_and_exit;
bellard80a9d032005-01-03 23:31:27 +00002403#if 0
bellarde80cfcf2004-12-19 23:18:01 +00002404 fprintf(stderr, "sigreturn\n");
2405 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 +00002406#endif
bellarde80cfcf2004-12-19 23:18:01 +00002407 //cpu_dump_state(env, stderr, fprintf, 0);
bellard6d5e2162004-09-30 22:04:13 +00002408
2409 /* 1. Make sure we are not getting garbage from the user */
bellard6d5e2162004-09-30 22:04:13 +00002410
bellardf8b0aa22007-11-11 23:03:42 +00002411 if (sf_addr & 3)
bellard6d5e2162004-09-30 22:04:13 +00002412 goto segv_and_exit;
2413
Riku Voipio1d8b5122014-04-23 10:26:05 +03002414 __get_user(pc, &sf->info.si_regs.pc);
2415 __get_user(npc, &sf->info.si_regs.npc);
bellard6d5e2162004-09-30 22:04:13 +00002416
bellard6d5e2162004-09-30 22:04:13 +00002417 if ((pc | npc) & 3)
2418 goto segv_and_exit;
2419
2420 /* 2. Restore the state */
Riku Voipio1d8b5122014-04-23 10:26:05 +03002421 __get_user(up_psr, &sf->info.si_regs.psr);
bellarde80cfcf2004-12-19 23:18:01 +00002422
bellard6d5e2162004-09-30 22:04:13 +00002423 /* User can only change condition codes and FPU enabling in %psr. */
bellarda315a142005-01-30 22:59:18 +00002424 env->psr = (up_psr & (PSR_ICC /* | PSR_EF */))
2425 | (env->psr & ~(PSR_ICC /* | PSR_EF */));
2426
2427 env->pc = pc;
2428 env->npc = npc;
Riku Voipio1d8b5122014-04-23 10:26:05 +03002429 __get_user(env->y, &sf->info.si_regs.y);
bellarda315a142005-01-30 22:59:18 +00002430 for (i=0; i < 8; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002431 __get_user(env->gregs[i], &sf->info.si_regs.u_regs[i]);
bellarde80cfcf2004-12-19 23:18:01 +00002432 }
bellarda315a142005-01-30 22:59:18 +00002433 for (i=0; i < 8; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002434 __get_user(env->regwptr[i + UREG_I0], &sf->info.si_regs.u_regs[i+8]);
bellarde80cfcf2004-12-19 23:18:01 +00002435 }
bellard6d5e2162004-09-30 22:04:13 +00002436
Peter Maydell2aec3a22011-06-16 17:37:14 +01002437 /* FIXME: implement FPU save/restore:
2438 * __get_user(fpu_save, &sf->fpu_save);
2439 * if (fpu_save)
2440 * err |= restore_fpu_state(env, fpu_save);
2441 */
bellard6d5e2162004-09-30 22:04:13 +00002442
2443 /* This is pretty much atomic, no amount locking would prevent
2444 * the races which exist anyways.
2445 */
Riku Voipio1d8b5122014-04-23 10:26:05 +03002446 __get_user(set.sig[0], &sf->info.si_mask);
bellarde80cfcf2004-12-19 23:18:01 +00002447 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002448 __get_user(set.sig[i], &sf->extramask[i - 1]);
bellarde80cfcf2004-12-19 23:18:01 +00002449 }
2450
2451 target_to_host_sigset_internal(&host_set, &set);
Alex Barcelo1c275922014-03-14 14:36:55 +00002452 do_sigprocmask(SIG_SETMASK, &host_set, NULL);
bellard6d5e2162004-09-30 22:04:13 +00002453
2454 if (err)
2455 goto segv_and_exit;
bellardf8b0aa22007-11-11 23:03:42 +00002456 unlock_user_struct(sf, sf_addr, 0);
bellard6d5e2162004-09-30 22:04:13 +00002457 return env->regwptr[0];
2458
2459segv_and_exit:
bellardf8b0aa22007-11-11 23:03:42 +00002460 unlock_user_struct(sf, sf_addr, 0);
bellard6d5e2162004-09-30 22:04:13 +00002461 force_sig(TARGET_SIGSEGV);
2462}
2463
Andreas Färber05390242012-02-25 03:37:53 +01002464long do_rt_sigreturn(CPUSPARCState *env)
bellard6d5e2162004-09-30 22:04:13 +00002465{
2466 fprintf(stderr, "do_rt_sigreturn: not implemented\n");
bellardf8b0aa22007-11-11 23:03:42 +00002467 return -TARGET_ENOSYS;
bellard6d5e2162004-09-30 22:04:13 +00002468}
2469
bellard459a4012007-11-11 19:45:10 +00002470#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
blueswir15bfb56b2007-10-05 17:01:51 +00002471#define MC_TSTATE 0
2472#define MC_PC 1
2473#define MC_NPC 2
2474#define MC_Y 3
2475#define MC_G1 4
2476#define MC_G2 5
2477#define MC_G3 6
2478#define MC_G4 7
2479#define MC_G5 8
2480#define MC_G6 9
2481#define MC_G7 10
2482#define MC_O0 11
2483#define MC_O1 12
2484#define MC_O2 13
2485#define MC_O3 14
2486#define MC_O4 15
2487#define MC_O5 16
2488#define MC_O6 17
2489#define MC_O7 18
2490#define MC_NGREG 19
2491
Anthony Liguoric227f092009-10-01 16:12:16 -05002492typedef abi_ulong target_mc_greg_t;
2493typedef target_mc_greg_t target_mc_gregset_t[MC_NGREG];
blueswir15bfb56b2007-10-05 17:01:51 +00002494
2495struct target_mc_fq {
blueswir1992f48a2007-10-14 16:27:31 +00002496 abi_ulong *mcfq_addr;
blueswir15bfb56b2007-10-05 17:01:51 +00002497 uint32_t mcfq_insn;
2498};
2499
2500struct target_mc_fpu {
2501 union {
2502 uint32_t sregs[32];
2503 uint64_t dregs[32];
2504 //uint128_t qregs[16];
2505 } mcfpu_fregs;
blueswir1992f48a2007-10-14 16:27:31 +00002506 abi_ulong mcfpu_fsr;
2507 abi_ulong mcfpu_fprs;
2508 abi_ulong mcfpu_gsr;
blueswir15bfb56b2007-10-05 17:01:51 +00002509 struct target_mc_fq *mcfpu_fq;
2510 unsigned char mcfpu_qcnt;
2511 unsigned char mcfpu_qentsz;
2512 unsigned char mcfpu_enab;
2513};
Anthony Liguoric227f092009-10-01 16:12:16 -05002514typedef struct target_mc_fpu target_mc_fpu_t;
blueswir15bfb56b2007-10-05 17:01:51 +00002515
2516typedef struct {
Anthony Liguoric227f092009-10-01 16:12:16 -05002517 target_mc_gregset_t mc_gregs;
2518 target_mc_greg_t mc_fp;
2519 target_mc_greg_t mc_i7;
2520 target_mc_fpu_t mc_fpregs;
2521} target_mcontext_t;
blueswir15bfb56b2007-10-05 17:01:51 +00002522
2523struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02002524 struct target_ucontext *tuc_link;
2525 abi_ulong tuc_flags;
2526 target_sigset_t tuc_sigmask;
2527 target_mcontext_t tuc_mcontext;
blueswir15bfb56b2007-10-05 17:01:51 +00002528};
2529
2530/* A V9 register window */
2531struct target_reg_window {
blueswir1992f48a2007-10-14 16:27:31 +00002532 abi_ulong locals[8];
2533 abi_ulong ins[8];
blueswir15bfb56b2007-10-05 17:01:51 +00002534};
2535
2536#define TARGET_STACK_BIAS 2047
2537
2538/* {set, get}context() needed for 64-bit SparcLinux userland. */
2539void sparc64_set_context(CPUSPARCState *env)
2540{
bellard459a4012007-11-11 19:45:10 +00002541 abi_ulong ucp_addr;
2542 struct target_ucontext *ucp;
Anthony Liguoric227f092009-10-01 16:12:16 -05002543 target_mc_gregset_t *grp;
blueswir1992f48a2007-10-14 16:27:31 +00002544 abi_ulong pc, npc, tstate;
bellard459a4012007-11-11 19:45:10 +00002545 abi_ulong fp, i7, w_addr;
Riku Voipio1d8b5122014-04-23 10:26:05 +03002546 int err = 0;
blueswir15bfb56b2007-10-05 17:01:51 +00002547 unsigned int i;
blueswir15bfb56b2007-10-05 17:01:51 +00002548
bellard459a4012007-11-11 19:45:10 +00002549 ucp_addr = env->regwptr[UREG_I0];
2550 if (!lock_user_struct(VERIFY_READ, ucp, ucp_addr, 1))
2551 goto do_sigsegv;
Aurelien Jarno60e99242010-03-29 02:12:51 +02002552 grp = &ucp->tuc_mcontext.mc_gregs;
Riku Voipio1d8b5122014-04-23 10:26:05 +03002553 __get_user(pc, &((*grp)[MC_PC]));
2554 __get_user(npc, &((*grp)[MC_NPC]));
blueswir15bfb56b2007-10-05 17:01:51 +00002555 if (err || ((pc | npc) & 3))
2556 goto do_sigsegv;
2557 if (env->regwptr[UREG_I1]) {
Anthony Liguoric227f092009-10-01 16:12:16 -05002558 target_sigset_t target_set;
blueswir15bfb56b2007-10-05 17:01:51 +00002559 sigset_t set;
2560
2561 if (TARGET_NSIG_WORDS == 1) {
Aurelien Jarno60e99242010-03-29 02:12:51 +02002562 if (__get_user(target_set.sig[0], &ucp->tuc_sigmask.sig[0]))
blueswir15bfb56b2007-10-05 17:01:51 +00002563 goto do_sigsegv;
2564 } else {
bellard459a4012007-11-11 19:45:10 +00002565 abi_ulong *src, *dst;
Aurelien Jarno60e99242010-03-29 02:12:51 +02002566 src = ucp->tuc_sigmask.sig;
bellard459a4012007-11-11 19:45:10 +00002567 dst = target_set.sig;
Stefan Weil0d9e61c2013-12-07 14:48:08 +01002568 for (i = 0; i < TARGET_NSIG_WORDS; i++, dst++, src++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002569 __get_user(*dst, src);
Stefan Weil0d9e61c2013-12-07 14:48:08 +01002570 }
blueswir15bfb56b2007-10-05 17:01:51 +00002571 if (err)
2572 goto do_sigsegv;
2573 }
2574 target_to_host_sigset_internal(&set, &target_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00002575 do_sigprocmask(SIG_SETMASK, &set, NULL);
blueswir15bfb56b2007-10-05 17:01:51 +00002576 }
2577 env->pc = pc;
2578 env->npc = npc;
Riku Voipio1d8b5122014-04-23 10:26:05 +03002579 __get_user(env->y, &((*grp)[MC_Y]));
2580 __get_user(tstate, &((*grp)[MC_TSTATE]));
blueswir15bfb56b2007-10-05 17:01:51 +00002581 env->asi = (tstate >> 24) & 0xff;
Blue Swirl5a834bb2010-05-09 20:19:04 +00002582 cpu_put_ccr(env, tstate >> 32);
2583 cpu_put_cwp64(env, tstate & 0x1f);
Riku Voipio1d8b5122014-04-23 10:26:05 +03002584 __get_user(env->gregs[1], (&(*grp)[MC_G1]));
2585 __get_user(env->gregs[2], (&(*grp)[MC_G2]));
2586 __get_user(env->gregs[3], (&(*grp)[MC_G3]));
2587 __get_user(env->gregs[4], (&(*grp)[MC_G4]));
2588 __get_user(env->gregs[5], (&(*grp)[MC_G5]));
2589 __get_user(env->gregs[6], (&(*grp)[MC_G6]));
2590 __get_user(env->gregs[7], (&(*grp)[MC_G7]));
2591 __get_user(env->regwptr[UREG_I0], (&(*grp)[MC_O0]));
2592 __get_user(env->regwptr[UREG_I1], (&(*grp)[MC_O1]));
2593 __get_user(env->regwptr[UREG_I2], (&(*grp)[MC_O2]));
2594 __get_user(env->regwptr[UREG_I3], (&(*grp)[MC_O3]));
2595 __get_user(env->regwptr[UREG_I4], (&(*grp)[MC_O4]));
2596 __get_user(env->regwptr[UREG_I5], (&(*grp)[MC_O5]));
2597 __get_user(env->regwptr[UREG_I6], (&(*grp)[MC_O6]));
2598 __get_user(env->regwptr[UREG_I7], (&(*grp)[MC_O7]));
blueswir15bfb56b2007-10-05 17:01:51 +00002599
Riku Voipio1d8b5122014-04-23 10:26:05 +03002600 __get_user(fp, &(ucp->tuc_mcontext.mc_fp));
2601 __get_user(i7, &(ucp->tuc_mcontext.mc_i7));
blueswir15bfb56b2007-10-05 17:01:51 +00002602
bellard459a4012007-11-11 19:45:10 +00002603 w_addr = TARGET_STACK_BIAS+env->regwptr[UREG_I6];
2604 if (put_user(fp, w_addr + offsetof(struct target_reg_window, ins[6]),
2605 abi_ulong) != 0)
2606 goto do_sigsegv;
2607 if (put_user(i7, w_addr + offsetof(struct target_reg_window, ins[7]),
2608 abi_ulong) != 0)
2609 goto do_sigsegv;
Peter Maydellc7b016b2011-06-16 17:37:15 +01002610 /* FIXME this does not match how the kernel handles the FPU in
2611 * its sparc64_set_context implementation. In particular the FPU
2612 * is only restored if fenab is non-zero in:
2613 * __get_user(fenab, &(ucp->tuc_mcontext.mc_fpregs.mcfpu_enab));
2614 */
Aurelien Jarno60e99242010-03-29 02:12:51 +02002615 err |= __get_user(env->fprs, &(ucp->tuc_mcontext.mc_fpregs.mcfpu_fprs));
bellard459a4012007-11-11 19:45:10 +00002616 {
Richard Henderson30038fd2011-10-17 10:42:49 -07002617 uint32_t *src = ucp->tuc_mcontext.mc_fpregs.mcfpu_fregs.sregs;
2618 for (i = 0; i < 64; i++, src++) {
2619 if (i & 1) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002620 __get_user(env->fpr[i/2].l.lower, src);
Richard Henderson30038fd2011-10-17 10:42:49 -07002621 } else {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002622 __get_user(env->fpr[i/2].l.upper, src);
Richard Henderson30038fd2011-10-17 10:42:49 -07002623 }
2624 }
bellard459a4012007-11-11 19:45:10 +00002625 }
Riku Voipio1d8b5122014-04-23 10:26:05 +03002626 __get_user(env->fsr,
2627 &(ucp->tuc_mcontext.mc_fpregs.mcfpu_fsr));
2628 __get_user(env->gsr,
2629 &(ucp->tuc_mcontext.mc_fpregs.mcfpu_gsr));
blueswir15bfb56b2007-10-05 17:01:51 +00002630 if (err)
2631 goto do_sigsegv;
bellard459a4012007-11-11 19:45:10 +00002632 unlock_user_struct(ucp, ucp_addr, 0);
blueswir15bfb56b2007-10-05 17:01:51 +00002633 return;
2634 do_sigsegv:
bellard459a4012007-11-11 19:45:10 +00002635 unlock_user_struct(ucp, ucp_addr, 0);
Riku Voipio66393fb2009-12-04 15:16:32 +02002636 force_sig(TARGET_SIGSEGV);
blueswir15bfb56b2007-10-05 17:01:51 +00002637}
2638
2639void sparc64_get_context(CPUSPARCState *env)
2640{
bellard459a4012007-11-11 19:45:10 +00002641 abi_ulong ucp_addr;
2642 struct target_ucontext *ucp;
Anthony Liguoric227f092009-10-01 16:12:16 -05002643 target_mc_gregset_t *grp;
2644 target_mcontext_t *mcp;
bellard459a4012007-11-11 19:45:10 +00002645 abi_ulong fp, i7, w_addr;
blueswir15bfb56b2007-10-05 17:01:51 +00002646 int err;
2647 unsigned int i;
Anthony Liguoric227f092009-10-01 16:12:16 -05002648 target_sigset_t target_set;
blueswir15bfb56b2007-10-05 17:01:51 +00002649 sigset_t set;
2650
bellard459a4012007-11-11 19:45:10 +00002651 ucp_addr = env->regwptr[UREG_I0];
2652 if (!lock_user_struct(VERIFY_WRITE, ucp, ucp_addr, 0))
2653 goto do_sigsegv;
2654
Aurelien Jarno60e99242010-03-29 02:12:51 +02002655 mcp = &ucp->tuc_mcontext;
blueswir15bfb56b2007-10-05 17:01:51 +00002656 grp = &mcp->mc_gregs;
2657
2658 /* Skip over the trap instruction, first. */
2659 env->pc = env->npc;
2660 env->npc += 4;
2661
2662 err = 0;
2663
Alex Barcelo1c275922014-03-14 14:36:55 +00002664 do_sigprocmask(0, NULL, &set);
blueswir15bfb56b2007-10-05 17:01:51 +00002665 host_to_target_sigset_internal(&target_set, &set);
bellard459a4012007-11-11 19:45:10 +00002666 if (TARGET_NSIG_WORDS == 1) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002667 __put_user(target_set.sig[0],
2668 (abi_ulong *)&ucp->tuc_sigmask);
bellard459a4012007-11-11 19:45:10 +00002669 } else {
2670 abi_ulong *src, *dst;
2671 src = target_set.sig;
Aurelien Jarno60e99242010-03-29 02:12:51 +02002672 dst = ucp->tuc_sigmask.sig;
Stefan Weil0d9e61c2013-12-07 14:48:08 +01002673 for (i = 0; i < TARGET_NSIG_WORDS; i++, dst++, src++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002674 __put_user(*src, dst);
Stefan Weil0d9e61c2013-12-07 14:48:08 +01002675 }
blueswir15bfb56b2007-10-05 17:01:51 +00002676 if (err)
2677 goto do_sigsegv;
2678 }
2679
bellard459a4012007-11-11 19:45:10 +00002680 /* XXX: tstate must be saved properly */
Riku Voipio1d8b5122014-04-23 10:26:05 +03002681 // __put_user(env->tstate, &((*grp)[MC_TSTATE]));
2682 __put_user(env->pc, &((*grp)[MC_PC]));
2683 __put_user(env->npc, &((*grp)[MC_NPC]));
2684 __put_user(env->y, &((*grp)[MC_Y]));
2685 __put_user(env->gregs[1], &((*grp)[MC_G1]));
2686 __put_user(env->gregs[2], &((*grp)[MC_G2]));
2687 __put_user(env->gregs[3], &((*grp)[MC_G3]));
2688 __put_user(env->gregs[4], &((*grp)[MC_G4]));
2689 __put_user(env->gregs[5], &((*grp)[MC_G5]));
2690 __put_user(env->gregs[6], &((*grp)[MC_G6]));
2691 __put_user(env->gregs[7], &((*grp)[MC_G7]));
2692 __put_user(env->regwptr[UREG_I0], &((*grp)[MC_O0]));
2693 __put_user(env->regwptr[UREG_I1], &((*grp)[MC_O1]));
2694 __put_user(env->regwptr[UREG_I2], &((*grp)[MC_O2]));
2695 __put_user(env->regwptr[UREG_I3], &((*grp)[MC_O3]));
2696 __put_user(env->regwptr[UREG_I4], &((*grp)[MC_O4]));
2697 __put_user(env->regwptr[UREG_I5], &((*grp)[MC_O5]));
2698 __put_user(env->regwptr[UREG_I6], &((*grp)[MC_O6]));
2699 __put_user(env->regwptr[UREG_I7], &((*grp)[MC_O7]));
blueswir15bfb56b2007-10-05 17:01:51 +00002700
bellard459a4012007-11-11 19:45:10 +00002701 w_addr = TARGET_STACK_BIAS+env->regwptr[UREG_I6];
2702 fp = i7 = 0;
2703 if (get_user(fp, w_addr + offsetof(struct target_reg_window, ins[6]),
2704 abi_ulong) != 0)
2705 goto do_sigsegv;
2706 if (get_user(i7, w_addr + offsetof(struct target_reg_window, ins[7]),
2707 abi_ulong) != 0)
2708 goto do_sigsegv;
Riku Voipio1d8b5122014-04-23 10:26:05 +03002709 __put_user(fp, &(mcp->mc_fp));
2710 __put_user(i7, &(mcp->mc_i7));
blueswir15bfb56b2007-10-05 17:01:51 +00002711
bellard459a4012007-11-11 19:45:10 +00002712 {
Richard Henderson30038fd2011-10-17 10:42:49 -07002713 uint32_t *dst = ucp->tuc_mcontext.mc_fpregs.mcfpu_fregs.sregs;
2714 for (i = 0; i < 64; i++, dst++) {
2715 if (i & 1) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002716 __put_user(env->fpr[i/2].l.lower, dst);
Richard Henderson30038fd2011-10-17 10:42:49 -07002717 } else {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002718 __put_user(env->fpr[i/2].l.upper, dst);
Richard Henderson30038fd2011-10-17 10:42:49 -07002719 }
2720 }
bellard459a4012007-11-11 19:45:10 +00002721 }
Riku Voipio1d8b5122014-04-23 10:26:05 +03002722 __put_user(env->fsr, &(mcp->mc_fpregs.mcfpu_fsr));
2723 __put_user(env->gsr, &(mcp->mc_fpregs.mcfpu_gsr));
2724 __put_user(env->fprs, &(mcp->mc_fpregs.mcfpu_fprs));
blueswir15bfb56b2007-10-05 17:01:51 +00002725
2726 if (err)
2727 goto do_sigsegv;
bellard459a4012007-11-11 19:45:10 +00002728 unlock_user_struct(ucp, ucp_addr, 1);
blueswir15bfb56b2007-10-05 17:01:51 +00002729 return;
2730 do_sigsegv:
bellard459a4012007-11-11 19:45:10 +00002731 unlock_user_struct(ucp, ucp_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02002732 force_sig(TARGET_SIGSEGV);
blueswir15bfb56b2007-10-05 17:01:51 +00002733}
2734#endif
Richard Hendersonff970902013-02-10 10:30:42 -08002735#elif defined(TARGET_MIPS) || defined(TARGET_MIPS64)
bellard106ec872006-06-27 21:08:10 +00002736
Richard Hendersonff970902013-02-10 10:30:42 -08002737# if defined(TARGET_ABI_MIPSO32)
bellard106ec872006-06-27 21:08:10 +00002738struct target_sigcontext {
2739 uint32_t sc_regmask; /* Unused */
2740 uint32_t sc_status;
2741 uint64_t sc_pc;
2742 uint64_t sc_regs[32];
2743 uint64_t sc_fpregs[32];
2744 uint32_t sc_ownedfp; /* Unused */
2745 uint32_t sc_fpc_csr;
2746 uint32_t sc_fpc_eir; /* Unused */
2747 uint32_t sc_used_math;
2748 uint32_t sc_dsp; /* dsp status, was sc_ssflags */
Paul Brook94c54952009-07-09 18:40:15 +01002749 uint32_t pad0;
bellard106ec872006-06-27 21:08:10 +00002750 uint64_t sc_mdhi;
2751 uint64_t sc_mdlo;
2752 target_ulong sc_hi1; /* Was sc_cause */
2753 target_ulong sc_lo1; /* Was sc_badvaddr */
2754 target_ulong sc_hi2; /* Was sc_sigset[4] */
2755 target_ulong sc_lo2;
2756 target_ulong sc_hi3;
2757 target_ulong sc_lo3;
2758};
Richard Hendersonff970902013-02-10 10:30:42 -08002759# else /* N32 || N64 */
2760struct target_sigcontext {
2761 uint64_t sc_regs[32];
2762 uint64_t sc_fpregs[32];
2763 uint64_t sc_mdhi;
2764 uint64_t sc_hi1;
2765 uint64_t sc_hi2;
2766 uint64_t sc_hi3;
2767 uint64_t sc_mdlo;
2768 uint64_t sc_lo1;
2769 uint64_t sc_lo2;
2770 uint64_t sc_lo3;
2771 uint64_t sc_pc;
2772 uint32_t sc_fpc_csr;
2773 uint32_t sc_used_math;
2774 uint32_t sc_dsp;
2775 uint32_t sc_reserved;
2776};
2777# endif /* O32 */
bellard106ec872006-06-27 21:08:10 +00002778
2779struct sigframe {
2780 uint32_t sf_ass[4]; /* argument save space for o32 */
2781 uint32_t sf_code[2]; /* signal trampoline */
2782 struct target_sigcontext sf_sc;
Anthony Liguoric227f092009-10-01 16:12:16 -05002783 target_sigset_t sf_mask;
bellard106ec872006-06-27 21:08:10 +00002784};
2785
pbrook0b1bcb02009-04-21 01:41:10 +00002786struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02002787 target_ulong tuc_flags;
2788 target_ulong tuc_link;
2789 target_stack_t tuc_stack;
Paul Brook94c54952009-07-09 18:40:15 +01002790 target_ulong pad0;
Aurelien Jarno60e99242010-03-29 02:12:51 +02002791 struct target_sigcontext tuc_mcontext;
2792 target_sigset_t tuc_sigmask;
pbrook0b1bcb02009-04-21 01:41:10 +00002793};
2794
2795struct target_rt_sigframe {
2796 uint32_t rs_ass[4]; /* argument save space for o32 */
2797 uint32_t rs_code[2]; /* signal trampoline */
2798 struct target_siginfo rs_info;
2799 struct target_ucontext rs_uc;
2800};
2801
bellard106ec872006-06-27 21:08:10 +00002802/* Install trampoline to jump back from signal handler */
2803static inline int install_sigtramp(unsigned int *tramp, unsigned int syscall)
2804{
Richard Henderson084d0492013-02-10 10:30:44 -08002805 int err = 0;
bellard106ec872006-06-27 21:08:10 +00002806
2807 /*
Richard Henderson084d0492013-02-10 10:30:44 -08002808 * Set up the return code ...
2809 *
2810 * li v0, __NR__foo_sigreturn
2811 * syscall
2812 */
bellard106ec872006-06-27 21:08:10 +00002813
Riku Voipio1d8b5122014-04-23 10:26:05 +03002814 __put_user(0x24020000 + syscall, tramp + 0);
2815 __put_user(0x0000000c , tramp + 1);
bellard106ec872006-06-27 21:08:10 +00002816 return err;
2817}
2818
Riku Voipio41ecc722014-04-23 11:01:00 +03002819static inline void setup_sigcontext(CPUMIPSState *regs,
2820 struct target_sigcontext *sc)
bellard106ec872006-06-27 21:08:10 +00002821{
Richard Henderson084d0492013-02-10 10:30:44 -08002822 int i;
bellard106ec872006-06-27 21:08:10 +00002823
Riku Voipio1d8b5122014-04-23 10:26:05 +03002824 __put_user(exception_resume_pc(regs), &sc->sc_pc);
Kwok Cheung Yeung1239b472013-05-17 14:51:21 -07002825 regs->hflags &= ~MIPS_HFLAG_BMASK;
bellard106ec872006-06-27 21:08:10 +00002826
Richard Henderson084d0492013-02-10 10:30:44 -08002827 __put_user(0, &sc->sc_regs[0]);
2828 for (i = 1; i < 32; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002829 __put_user(regs->active_tc.gpr[i], &sc->sc_regs[i]);
Richard Henderson084d0492013-02-10 10:30:44 -08002830 }
bellard106ec872006-06-27 21:08:10 +00002831
Riku Voipio1d8b5122014-04-23 10:26:05 +03002832 __put_user(regs->active_tc.HI[0], &sc->sc_mdhi);
2833 __put_user(regs->active_tc.LO[0], &sc->sc_mdlo);
bellard106ec872006-06-27 21:08:10 +00002834
Richard Henderson084d0492013-02-10 10:30:44 -08002835 /* Rather than checking for dsp existence, always copy. The storage
2836 would just be garbage otherwise. */
Riku Voipio1d8b5122014-04-23 10:26:05 +03002837 __put_user(regs->active_tc.HI[1], &sc->sc_hi1);
2838 __put_user(regs->active_tc.HI[2], &sc->sc_hi2);
2839 __put_user(regs->active_tc.HI[3], &sc->sc_hi3);
2840 __put_user(regs->active_tc.LO[1], &sc->sc_lo1);
2841 __put_user(regs->active_tc.LO[2], &sc->sc_lo2);
2842 __put_user(regs->active_tc.LO[3], &sc->sc_lo3);
Richard Henderson084d0492013-02-10 10:30:44 -08002843 {
2844 uint32_t dsp = cpu_rddsp(0x3ff, regs);
Riku Voipio1d8b5122014-04-23 10:26:05 +03002845 __put_user(dsp, &sc->sc_dsp);
bellard106ec872006-06-27 21:08:10 +00002846 }
Richard Henderson084d0492013-02-10 10:30:44 -08002847
Riku Voipio1d8b5122014-04-23 10:26:05 +03002848 __put_user(1, &sc->sc_used_math);
Richard Henderson084d0492013-02-10 10:30:44 -08002849
2850 for (i = 0; i < 32; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002851 __put_user(regs->active_fpu.fpr[i].d, &sc->sc_fpregs[i]);
bellard106ec872006-06-27 21:08:10 +00002852 }
bellard106ec872006-06-27 21:08:10 +00002853}
2854
Riku Voipio016d2e12014-04-23 11:19:48 +03002855static inline void
Andreas Färber05390242012-02-25 03:37:53 +01002856restore_sigcontext(CPUMIPSState *regs, struct target_sigcontext *sc)
bellard106ec872006-06-27 21:08:10 +00002857{
Richard Henderson084d0492013-02-10 10:30:44 -08002858 int i;
bellard106ec872006-06-27 21:08:10 +00002859
Riku Voipio1d8b5122014-04-23 10:26:05 +03002860 __get_user(regs->CP0_EPC, &sc->sc_pc);
bellard106ec872006-06-27 21:08:10 +00002861
Riku Voipio1d8b5122014-04-23 10:26:05 +03002862 __get_user(regs->active_tc.HI[0], &sc->sc_mdhi);
2863 __get_user(regs->active_tc.LO[0], &sc->sc_mdlo);
bellard106ec872006-06-27 21:08:10 +00002864
Richard Henderson084d0492013-02-10 10:30:44 -08002865 for (i = 1; i < 32; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002866 __get_user(regs->active_tc.gpr[i], &sc->sc_regs[i]);
bellard106ec872006-06-27 21:08:10 +00002867 }
2868
Riku Voipio1d8b5122014-04-23 10:26:05 +03002869 __get_user(regs->active_tc.HI[1], &sc->sc_hi1);
2870 __get_user(regs->active_tc.HI[2], &sc->sc_hi2);
2871 __get_user(regs->active_tc.HI[3], &sc->sc_hi3);
2872 __get_user(regs->active_tc.LO[1], &sc->sc_lo1);
2873 __get_user(regs->active_tc.LO[2], &sc->sc_lo2);
2874 __get_user(regs->active_tc.LO[3], &sc->sc_lo3);
Richard Henderson084d0492013-02-10 10:30:44 -08002875 {
2876 uint32_t dsp;
Riku Voipio1d8b5122014-04-23 10:26:05 +03002877 __get_user(dsp, &sc->sc_dsp);
Richard Henderson084d0492013-02-10 10:30:44 -08002878 cpu_wrdsp(dsp, 0x3ff, regs);
2879 }
2880
2881 for (i = 0; i < 32; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002882 __get_user(regs->active_fpu.fpr[i].d, &sc->sc_fpregs[i]);
Richard Henderson084d0492013-02-10 10:30:44 -08002883 }
bellard106ec872006-06-27 21:08:10 +00002884}
Richard Hendersonff970902013-02-10 10:30:42 -08002885
bellard106ec872006-06-27 21:08:10 +00002886/*
2887 * Determine which stack to use..
2888 */
bellard579a97f2007-11-11 14:26:47 +00002889static inline abi_ulong
Andreas Färber05390242012-02-25 03:37:53 +01002890get_sigframe(struct target_sigaction *ka, CPUMIPSState *regs, size_t frame_size)
bellard106ec872006-06-27 21:08:10 +00002891{
2892 unsigned long sp;
2893
2894 /* Default to using normal stack */
thsb5dc7732008-06-27 10:02:35 +00002895 sp = regs->active_tc.gpr[29];
bellard106ec872006-06-27 21:08:10 +00002896
2897 /*
Stefan Weil93148aa2012-02-26 18:46:12 +01002898 * FPU emulator may have its own trampoline active just
bellard106ec872006-06-27 21:08:10 +00002899 * above the user stack, 16-bytes before the next lowest
2900 * 16 byte boundary. Try to avoid trashing it.
2901 */
2902 sp -= 32;
2903
bellard106ec872006-06-27 21:08:10 +00002904 /* This is the X/Open sanctioned signal stack switching. */
pbrook624f7972008-05-31 16:11:38 +00002905 if ((ka->sa_flags & TARGET_SA_ONSTACK) && (sas_ss_flags (sp) == 0)) {
thsa04e1342007-09-27 13:57:58 +00002906 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
2907 }
bellard106ec872006-06-27 21:08:10 +00002908
bellard579a97f2007-11-11 14:26:47 +00002909 return (sp - frame_size) & ~7;
bellard106ec872006-06-27 21:08:10 +00002910}
2911
Kwok Cheung Yeungea3164a2013-05-17 14:51:20 -07002912static void mips_set_hflags_isa_mode_from_pc(CPUMIPSState *env)
2913{
2914 if (env->insn_flags & (ASE_MIPS16 | ASE_MICROMIPS)) {
2915 env->hflags &= ~MIPS_HFLAG_M16;
2916 env->hflags |= (env->active_tc.PC & 1) << MIPS_HFLAG_M16_SHIFT;
2917 env->active_tc.PC &= ~(target_ulong) 1;
2918 }
2919}
2920
Richard Hendersonff970902013-02-10 10:30:42 -08002921# if defined(TARGET_ABI_MIPSO32)
bellard579a97f2007-11-11 14:26:47 +00002922/* compare linux/arch/mips/kernel/signal.c:setup_frame() */
pbrook624f7972008-05-31 16:11:38 +00002923static void setup_frame(int sig, struct target_sigaction * ka,
Andreas Färber05390242012-02-25 03:37:53 +01002924 target_sigset_t *set, CPUMIPSState *regs)
bellard106ec872006-06-27 21:08:10 +00002925{
2926 struct sigframe *frame;
bellard579a97f2007-11-11 14:26:47 +00002927 abi_ulong frame_addr;
bellard106ec872006-06-27 21:08:10 +00002928 int i;
2929
bellard579a97f2007-11-11 14:26:47 +00002930 frame_addr = get_sigframe(ka, regs, sizeof(*frame));
2931 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
bellard106ec872006-06-27 21:08:10 +00002932 goto give_sigsegv;
2933
2934 install_sigtramp(frame->sf_code, TARGET_NR_sigreturn);
2935
Riku Voipio41ecc722014-04-23 11:01:00 +03002936 setup_sigcontext(regs, &frame->sf_sc);
bellard106ec872006-06-27 21:08:10 +00002937
2938 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
2939 if(__put_user(set->sig[i], &frame->sf_mask.sig[i]))
2940 goto give_sigsegv;
2941 }
2942
2943 /*
2944 * Arguments to signal handler:
2945 *
2946 * a0 = signal number
2947 * a1 = 0 (should be cause)
2948 * a2 = pointer to struct sigcontext
2949 *
2950 * $25 and PC point to the signal handler, $29 points to the
2951 * struct sigframe.
2952 */
thsb5dc7732008-06-27 10:02:35 +00002953 regs->active_tc.gpr[ 4] = sig;
2954 regs->active_tc.gpr[ 5] = 0;
2955 regs->active_tc.gpr[ 6] = frame_addr + offsetof(struct sigframe, sf_sc);
2956 regs->active_tc.gpr[29] = frame_addr;
2957 regs->active_tc.gpr[31] = frame_addr + offsetof(struct sigframe, sf_code);
bellard106ec872006-06-27 21:08:10 +00002958 /* The original kernel code sets CP0_EPC to the handler
2959 * since it returns to userland using eret
2960 * we cannot do this here, and we must set PC directly */
thsb5dc7732008-06-27 10:02:35 +00002961 regs->active_tc.PC = regs->active_tc.gpr[25] = ka->_sa_handler;
Kwok Cheung Yeungea3164a2013-05-17 14:51:20 -07002962 mips_set_hflags_isa_mode_from_pc(regs);
bellard579a97f2007-11-11 14:26:47 +00002963 unlock_user_struct(frame, frame_addr, 1);
bellard106ec872006-06-27 21:08:10 +00002964 return;
2965
2966give_sigsegv:
bellard579a97f2007-11-11 14:26:47 +00002967 unlock_user_struct(frame, frame_addr, 1);
bellard106ec872006-06-27 21:08:10 +00002968 force_sig(TARGET_SIGSEGV/*, current*/);
bellard106ec872006-06-27 21:08:10 +00002969}
2970
Andreas Färber05390242012-02-25 03:37:53 +01002971long do_sigreturn(CPUMIPSState *regs)
bellard106ec872006-06-27 21:08:10 +00002972{
ths388bb212007-05-13 13:58:00 +00002973 struct sigframe *frame;
bellard579a97f2007-11-11 14:26:47 +00002974 abi_ulong frame_addr;
ths388bb212007-05-13 13:58:00 +00002975 sigset_t blocked;
Anthony Liguoric227f092009-10-01 16:12:16 -05002976 target_sigset_t target_set;
ths388bb212007-05-13 13:58:00 +00002977 int i;
bellard106ec872006-06-27 21:08:10 +00002978
2979#if defined(DEBUG_SIGNAL)
ths388bb212007-05-13 13:58:00 +00002980 fprintf(stderr, "do_sigreturn\n");
bellard106ec872006-06-27 21:08:10 +00002981#endif
thsb5dc7732008-06-27 10:02:35 +00002982 frame_addr = regs->active_tc.gpr[29];
bellard579a97f2007-11-11 14:26:47 +00002983 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
bellard106ec872006-06-27 21:08:10 +00002984 goto badframe;
2985
ths388bb212007-05-13 13:58:00 +00002986 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
bellard106ec872006-06-27 21:08:10 +00002987 if(__get_user(target_set.sig[i], &frame->sf_mask.sig[i]))
2988 goto badframe;
ths388bb212007-05-13 13:58:00 +00002989 }
bellard106ec872006-06-27 21:08:10 +00002990
ths388bb212007-05-13 13:58:00 +00002991 target_to_host_sigset_internal(&blocked, &target_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00002992 do_sigprocmask(SIG_SETMASK, &blocked, NULL);
bellard106ec872006-06-27 21:08:10 +00002993
Riku Voipio016d2e12014-04-23 11:19:48 +03002994 restore_sigcontext(regs, &frame->sf_sc);
bellard106ec872006-06-27 21:08:10 +00002995
2996#if 0
ths388bb212007-05-13 13:58:00 +00002997 /*
2998 * Don't let your children do this ...
2999 */
3000 __asm__ __volatile__(
bellard106ec872006-06-27 21:08:10 +00003001 "move\t$29, %0\n\t"
3002 "j\tsyscall_exit"
3003 :/* no outputs */
3004 :"r" (&regs));
ths388bb212007-05-13 13:58:00 +00003005 /* Unreached */
bellard106ec872006-06-27 21:08:10 +00003006#endif
ths3b46e622007-09-17 08:09:54 +00003007
thsb5dc7732008-06-27 10:02:35 +00003008 regs->active_tc.PC = regs->CP0_EPC;
Kwok Cheung Yeungea3164a2013-05-17 14:51:20 -07003009 mips_set_hflags_isa_mode_from_pc(regs);
ths388bb212007-05-13 13:58:00 +00003010 /* I am not sure this is right, but it seems to work
bellard106ec872006-06-27 21:08:10 +00003011 * maybe a problem with nested signals ? */
3012 regs->CP0_EPC = 0;
pbrook0b1bcb02009-04-21 01:41:10 +00003013 return -TARGET_QEMU_ESIGRETURN;
bellard106ec872006-06-27 21:08:10 +00003014
3015badframe:
ths388bb212007-05-13 13:58:00 +00003016 force_sig(TARGET_SIGSEGV/*, current*/);
3017 return 0;
bellard106ec872006-06-27 21:08:10 +00003018}
Richard Hendersonff970902013-02-10 10:30:42 -08003019# endif /* O32 */
bellard106ec872006-06-27 21:08:10 +00003020
pbrook624f7972008-05-31 16:11:38 +00003021static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05003022 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01003023 target_sigset_t *set, CPUMIPSState *env)
bellard106ec872006-06-27 21:08:10 +00003024{
pbrook0b1bcb02009-04-21 01:41:10 +00003025 struct target_rt_sigframe *frame;
3026 abi_ulong frame_addr;
3027 int i;
3028
3029 frame_addr = get_sigframe(ka, env, sizeof(*frame));
3030 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
3031 goto give_sigsegv;
3032
3033 install_sigtramp(frame->rs_code, TARGET_NR_rt_sigreturn);
3034
3035 copy_siginfo_to_user(&frame->rs_info, info);
3036
Aurelien Jarno60e99242010-03-29 02:12:51 +02003037 __put_user(0, &frame->rs_uc.tuc_flags);
3038 __put_user(0, &frame->rs_uc.tuc_link);
3039 __put_user(target_sigaltstack_used.ss_sp, &frame->rs_uc.tuc_stack.ss_sp);
3040 __put_user(target_sigaltstack_used.ss_size, &frame->rs_uc.tuc_stack.ss_size);
pbrook0b1bcb02009-04-21 01:41:10 +00003041 __put_user(sas_ss_flags(get_sp_from_cpustate(env)),
Aurelien Jarno60e99242010-03-29 02:12:51 +02003042 &frame->rs_uc.tuc_stack.ss_flags);
pbrook0b1bcb02009-04-21 01:41:10 +00003043
Aurelien Jarno60e99242010-03-29 02:12:51 +02003044 setup_sigcontext(env, &frame->rs_uc.tuc_mcontext);
pbrook0b1bcb02009-04-21 01:41:10 +00003045
3046 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
Aurelien Jarno60e99242010-03-29 02:12:51 +02003047 __put_user(set->sig[i], &frame->rs_uc.tuc_sigmask.sig[i]);
pbrook0b1bcb02009-04-21 01:41:10 +00003048 }
3049
3050 /*
3051 * Arguments to signal handler:
3052 *
3053 * a0 = signal number
Richard W.M. Jones02d2bd52012-07-05 03:32:44 +00003054 * a1 = pointer to siginfo_t
pbrook0b1bcb02009-04-21 01:41:10 +00003055 * a2 = pointer to struct ucontext
3056 *
3057 * $25 and PC point to the signal handler, $29 points to the
3058 * struct sigframe.
3059 */
3060 env->active_tc.gpr[ 4] = sig;
3061 env->active_tc.gpr[ 5] = frame_addr
3062 + offsetof(struct target_rt_sigframe, rs_info);
3063 env->active_tc.gpr[ 6] = frame_addr
3064 + offsetof(struct target_rt_sigframe, rs_uc);
3065 env->active_tc.gpr[29] = frame_addr;
3066 env->active_tc.gpr[31] = frame_addr
3067 + offsetof(struct target_rt_sigframe, rs_code);
3068 /* The original kernel code sets CP0_EPC to the handler
3069 * since it returns to userland using eret
3070 * we cannot do this here, and we must set PC directly */
3071 env->active_tc.PC = env->active_tc.gpr[25] = ka->_sa_handler;
Kwok Cheung Yeungea3164a2013-05-17 14:51:20 -07003072 mips_set_hflags_isa_mode_from_pc(env);
pbrook0b1bcb02009-04-21 01:41:10 +00003073 unlock_user_struct(frame, frame_addr, 1);
3074 return;
3075
3076give_sigsegv:
3077 unlock_user_struct(frame, frame_addr, 1);
3078 force_sig(TARGET_SIGSEGV/*, current*/);
bellard106ec872006-06-27 21:08:10 +00003079}
3080
Andreas Färber05390242012-02-25 03:37:53 +01003081long do_rt_sigreturn(CPUMIPSState *env)
bellard106ec872006-06-27 21:08:10 +00003082{
pbrook0b1bcb02009-04-21 01:41:10 +00003083 struct target_rt_sigframe *frame;
3084 abi_ulong frame_addr;
3085 sigset_t blocked;
3086
3087#if defined(DEBUG_SIGNAL)
3088 fprintf(stderr, "do_rt_sigreturn\n");
3089#endif
3090 frame_addr = env->active_tc.gpr[29];
3091 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
3092 goto badframe;
3093
Aurelien Jarno60e99242010-03-29 02:12:51 +02003094 target_to_host_sigset(&blocked, &frame->rs_uc.tuc_sigmask);
Alex Barcelo1c275922014-03-14 14:36:55 +00003095 do_sigprocmask(SIG_SETMASK, &blocked, NULL);
pbrook0b1bcb02009-04-21 01:41:10 +00003096
Riku Voipio016d2e12014-04-23 11:19:48 +03003097 restore_sigcontext(env, &frame->rs_uc.tuc_mcontext);
pbrook0b1bcb02009-04-21 01:41:10 +00003098
3099 if (do_sigaltstack(frame_addr +
Aurelien Jarno60e99242010-03-29 02:12:51 +02003100 offsetof(struct target_rt_sigframe, rs_uc.tuc_stack),
pbrook0b1bcb02009-04-21 01:41:10 +00003101 0, get_sp_from_cpustate(env)) == -EFAULT)
3102 goto badframe;
3103
3104 env->active_tc.PC = env->CP0_EPC;
Kwok Cheung Yeungea3164a2013-05-17 14:51:20 -07003105 mips_set_hflags_isa_mode_from_pc(env);
pbrook0b1bcb02009-04-21 01:41:10 +00003106 /* I am not sure this is right, but it seems to work
3107 * maybe a problem with nested signals ? */
3108 env->CP0_EPC = 0;
3109 return -TARGET_QEMU_ESIGRETURN;
3110
3111badframe:
3112 force_sig(TARGET_SIGSEGV/*, current*/);
3113 return 0;
bellard106ec872006-06-27 21:08:10 +00003114}
bellard6d5e2162004-09-30 22:04:13 +00003115
thsc3b5bc82007-12-02 06:31:25 +00003116#elif defined(TARGET_SH4)
3117
3118/*
3119 * code and data structures from linux kernel:
3120 * include/asm-sh/sigcontext.h
3121 * arch/sh/kernel/signal.c
3122 */
3123
3124struct target_sigcontext {
3125 target_ulong oldmask;
3126
3127 /* CPU registers */
3128 target_ulong sc_gregs[16];
3129 target_ulong sc_pc;
3130 target_ulong sc_pr;
3131 target_ulong sc_sr;
3132 target_ulong sc_gbr;
3133 target_ulong sc_mach;
3134 target_ulong sc_macl;
3135
3136 /* FPU registers */
3137 target_ulong sc_fpregs[16];
3138 target_ulong sc_xfpregs[16];
3139 unsigned int sc_fpscr;
3140 unsigned int sc_fpul;
3141 unsigned int sc_ownedfp;
3142};
3143
3144struct target_sigframe
3145{
3146 struct target_sigcontext sc;
3147 target_ulong extramask[TARGET_NSIG_WORDS-1];
3148 uint16_t retcode[3];
3149};
3150
3151
3152struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02003153 target_ulong tuc_flags;
3154 struct target_ucontext *tuc_link;
3155 target_stack_t tuc_stack;
3156 struct target_sigcontext tuc_mcontext;
3157 target_sigset_t tuc_sigmask; /* mask last for extensibility */
thsc3b5bc82007-12-02 06:31:25 +00003158};
3159
3160struct target_rt_sigframe
3161{
3162 struct target_siginfo info;
3163 struct target_ucontext uc;
3164 uint16_t retcode[3];
3165};
3166
3167
3168#define MOVW(n) (0x9300|((n)-2)) /* Move mem word at PC+n to R3 */
3169#define TRAP_NOARG 0xc310 /* Syscall w/no args (NR in R3) SH3/4 */
3170
pbrook624f7972008-05-31 16:11:38 +00003171static abi_ulong get_sigframe(struct target_sigaction *ka,
thsc3b5bc82007-12-02 06:31:25 +00003172 unsigned long sp, size_t frame_size)
3173{
pbrook624f7972008-05-31 16:11:38 +00003174 if ((ka->sa_flags & TARGET_SA_ONSTACK) && (sas_ss_flags(sp) == 0)) {
thsc3b5bc82007-12-02 06:31:25 +00003175 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
3176 }
3177
3178 return (sp - frame_size) & -8ul;
3179}
3180
Riku Voipio41ecc722014-04-23 11:01:00 +03003181static void setup_sigcontext(struct target_sigcontext *sc,
Andreas Färber05390242012-02-25 03:37:53 +01003182 CPUSH4State *regs, unsigned long mask)
thsc3b5bc82007-12-02 06:31:25 +00003183{
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003184 int i;
thsc3b5bc82007-12-02 06:31:25 +00003185
Riku Voipio1d8b5122014-04-23 10:26:05 +03003186#define COPY(x) __put_user(regs->x, &sc->sc_##x)
thsc3b5bc82007-12-02 06:31:25 +00003187 COPY(gregs[0]); COPY(gregs[1]);
3188 COPY(gregs[2]); COPY(gregs[3]);
3189 COPY(gregs[4]); COPY(gregs[5]);
3190 COPY(gregs[6]); COPY(gregs[7]);
3191 COPY(gregs[8]); COPY(gregs[9]);
3192 COPY(gregs[10]); COPY(gregs[11]);
3193 COPY(gregs[12]); COPY(gregs[13]);
3194 COPY(gregs[14]); COPY(gregs[15]);
3195 COPY(gbr); COPY(mach);
3196 COPY(macl); COPY(pr);
3197 COPY(sr); COPY(pc);
3198#undef COPY
3199
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003200 for (i=0; i<16; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03003201 __put_user(regs->fregs[i], &sc->sc_fpregs[i]);
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003202 }
Riku Voipio1d8b5122014-04-23 10:26:05 +03003203 __put_user(regs->fpscr, &sc->sc_fpscr);
3204 __put_user(regs->fpul, &sc->sc_fpul);
thsc3b5bc82007-12-02 06:31:25 +00003205
3206 /* non-iBCS2 extensions.. */
Riku Voipio1d8b5122014-04-23 10:26:05 +03003207 __put_user(mask, &sc->oldmask);
thsc3b5bc82007-12-02 06:31:25 +00003208}
3209
Riku Voipio016d2e12014-04-23 11:19:48 +03003210static void restore_sigcontext(CPUSH4State *regs, struct target_sigcontext *sc,
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003211 target_ulong *r0_p)
thsc3b5bc82007-12-02 06:31:25 +00003212{
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003213 int i;
thsc3b5bc82007-12-02 06:31:25 +00003214
Riku Voipio1d8b5122014-04-23 10:26:05 +03003215#define COPY(x) __get_user(regs->x, &sc->sc_##x)
thsc3b5bc82007-12-02 06:31:25 +00003216 COPY(gregs[1]);
3217 COPY(gregs[2]); COPY(gregs[3]);
3218 COPY(gregs[4]); COPY(gregs[5]);
3219 COPY(gregs[6]); COPY(gregs[7]);
3220 COPY(gregs[8]); COPY(gregs[9]);
3221 COPY(gregs[10]); COPY(gregs[11]);
3222 COPY(gregs[12]); COPY(gregs[13]);
3223 COPY(gregs[14]); COPY(gregs[15]);
3224 COPY(gbr); COPY(mach);
3225 COPY(macl); COPY(pr);
3226 COPY(sr); COPY(pc);
3227#undef COPY
3228
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003229 for (i=0; i<16; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03003230 __get_user(regs->fregs[i], &sc->sc_fpregs[i]);
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003231 }
Riku Voipio1d8b5122014-04-23 10:26:05 +03003232 __get_user(regs->fpscr, &sc->sc_fpscr);
3233 __get_user(regs->fpul, &sc->sc_fpul);
thsc3b5bc82007-12-02 06:31:25 +00003234
3235 regs->tra = -1; /* disable syscall checks */
Riku Voipio1d8b5122014-04-23 10:26:05 +03003236 __get_user(*r0_p, &sc->sc_gregs[0]);
thsc3b5bc82007-12-02 06:31:25 +00003237}
3238
pbrook624f7972008-05-31 16:11:38 +00003239static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01003240 target_sigset_t *set, CPUSH4State *regs)
thsc3b5bc82007-12-02 06:31:25 +00003241{
3242 struct target_sigframe *frame;
3243 abi_ulong frame_addr;
3244 int i;
3245 int err = 0;
3246 int signal;
3247
3248 frame_addr = get_sigframe(ka, regs->gregs[15], sizeof(*frame));
3249 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
3250 goto give_sigsegv;
3251
3252 signal = current_exec_domain_sig(sig);
3253
Riku Voipio41ecc722014-04-23 11:01:00 +03003254 setup_sigcontext(&frame->sc, regs, set->sig[0]);
thsc3b5bc82007-12-02 06:31:25 +00003255
3256 for (i = 0; i < TARGET_NSIG_WORDS - 1; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03003257 __put_user(set->sig[i + 1], &frame->extramask[i]);
thsc3b5bc82007-12-02 06:31:25 +00003258 }
3259
3260 /* Set up to return from userspace. If provided, use a stub
3261 already in userspace. */
pbrook624f7972008-05-31 16:11:38 +00003262 if (ka->sa_flags & TARGET_SA_RESTORER) {
3263 regs->pr = (unsigned long) ka->sa_restorer;
thsc3b5bc82007-12-02 06:31:25 +00003264 } else {
3265 /* Generate return code (system call to sigreturn) */
Riku Voipio1d8b5122014-04-23 10:26:05 +03003266 __put_user(MOVW(2), &frame->retcode[0]);
3267 __put_user(TRAP_NOARG, &frame->retcode[1]);
3268 __put_user((TARGET_NR_sigreturn), &frame->retcode[2]);
thsc3b5bc82007-12-02 06:31:25 +00003269 regs->pr = (unsigned long) frame->retcode;
3270 }
3271
3272 if (err)
3273 goto give_sigsegv;
3274
3275 /* Set up registers for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003276 regs->gregs[15] = frame_addr;
thsc3b5bc82007-12-02 06:31:25 +00003277 regs->gregs[4] = signal; /* Arg for signal handler */
3278 regs->gregs[5] = 0;
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003279 regs->gregs[6] = frame_addr += offsetof(typeof(*frame), sc);
pbrook624f7972008-05-31 16:11:38 +00003280 regs->pc = (unsigned long) ka->_sa_handler;
thsc3b5bc82007-12-02 06:31:25 +00003281
3282 unlock_user_struct(frame, frame_addr, 1);
3283 return;
3284
3285give_sigsegv:
3286 unlock_user_struct(frame, frame_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02003287 force_sig(TARGET_SIGSEGV);
thsc3b5bc82007-12-02 06:31:25 +00003288}
3289
pbrook624f7972008-05-31 16:11:38 +00003290static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05003291 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01003292 target_sigset_t *set, CPUSH4State *regs)
thsc3b5bc82007-12-02 06:31:25 +00003293{
3294 struct target_rt_sigframe *frame;
3295 abi_ulong frame_addr;
3296 int i;
3297 int err = 0;
3298 int signal;
3299
3300 frame_addr = get_sigframe(ka, regs->gregs[15], sizeof(*frame));
3301 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
3302 goto give_sigsegv;
3303
3304 signal = current_exec_domain_sig(sig);
3305
Riku Voipiob0fd8d12014-04-23 10:46:13 +03003306 copy_siginfo_to_user(&frame->info, info);
thsc3b5bc82007-12-02 06:31:25 +00003307
3308 /* Create the ucontext. */
Riku Voipio1d8b5122014-04-23 10:26:05 +03003309 __put_user(0, &frame->uc.tuc_flags);
3310 __put_user(0, (unsigned long *)&frame->uc.tuc_link);
3311 __put_user((unsigned long)target_sigaltstack_used.ss_sp,
3312 &frame->uc.tuc_stack.ss_sp);
3313 __put_user(sas_ss_flags(regs->gregs[15]),
3314 &frame->uc.tuc_stack.ss_flags);
3315 __put_user(target_sigaltstack_used.ss_size,
3316 &frame->uc.tuc_stack.ss_size);
3317 setup_sigcontext(&frame->uc.tuc_mcontext,
thsc3b5bc82007-12-02 06:31:25 +00003318 regs, set->sig[0]);
3319 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03003320 __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
thsc3b5bc82007-12-02 06:31:25 +00003321 }
3322
3323 /* Set up to return from userspace. If provided, use a stub
3324 already in userspace. */
pbrook624f7972008-05-31 16:11:38 +00003325 if (ka->sa_flags & TARGET_SA_RESTORER) {
3326 regs->pr = (unsigned long) ka->sa_restorer;
thsc3b5bc82007-12-02 06:31:25 +00003327 } else {
3328 /* Generate return code (system call to sigreturn) */
Riku Voipio1d8b5122014-04-23 10:26:05 +03003329 __put_user(MOVW(2), &frame->retcode[0]);
3330 __put_user(TRAP_NOARG, &frame->retcode[1]);
3331 __put_user((TARGET_NR_rt_sigreturn), &frame->retcode[2]);
thsc3b5bc82007-12-02 06:31:25 +00003332 regs->pr = (unsigned long) frame->retcode;
3333 }
3334
3335 if (err)
3336 goto give_sigsegv;
3337
3338 /* Set up registers for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003339 regs->gregs[15] = frame_addr;
thsc3b5bc82007-12-02 06:31:25 +00003340 regs->gregs[4] = signal; /* Arg for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003341 regs->gregs[5] = frame_addr + offsetof(typeof(*frame), info);
3342 regs->gregs[6] = frame_addr + offsetof(typeof(*frame), uc);
pbrook624f7972008-05-31 16:11:38 +00003343 regs->pc = (unsigned long) ka->_sa_handler;
thsc3b5bc82007-12-02 06:31:25 +00003344
3345 unlock_user_struct(frame, frame_addr, 1);
3346 return;
3347
3348give_sigsegv:
3349 unlock_user_struct(frame, frame_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02003350 force_sig(TARGET_SIGSEGV);
thsc3b5bc82007-12-02 06:31:25 +00003351}
3352
Andreas Färber05390242012-02-25 03:37:53 +01003353long do_sigreturn(CPUSH4State *regs)
thsc3b5bc82007-12-02 06:31:25 +00003354{
3355 struct target_sigframe *frame;
3356 abi_ulong frame_addr;
3357 sigset_t blocked;
Anthony Liguoric227f092009-10-01 16:12:16 -05003358 target_sigset_t target_set;
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003359 target_ulong r0;
thsc3b5bc82007-12-02 06:31:25 +00003360 int i;
3361 int err = 0;
3362
3363#if defined(DEBUG_SIGNAL)
3364 fprintf(stderr, "do_sigreturn\n");
3365#endif
3366 frame_addr = regs->gregs[15];
3367 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
3368 goto badframe;
3369
Riku Voipio1d8b5122014-04-23 10:26:05 +03003370 __get_user(target_set.sig[0], &frame->sc.oldmask);
thsc3b5bc82007-12-02 06:31:25 +00003371 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03003372 __get_user(target_set.sig[i], &frame->extramask[i - 1]);
thsc3b5bc82007-12-02 06:31:25 +00003373 }
3374
3375 if (err)
3376 goto badframe;
3377
3378 target_to_host_sigset_internal(&blocked, &target_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00003379 do_sigprocmask(SIG_SETMASK, &blocked, NULL);
thsc3b5bc82007-12-02 06:31:25 +00003380
Riku Voipio016d2e12014-04-23 11:19:48 +03003381 restore_sigcontext(regs, &frame->sc, &r0);
thsc3b5bc82007-12-02 06:31:25 +00003382
3383 unlock_user_struct(frame, frame_addr, 0);
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003384 return r0;
thsc3b5bc82007-12-02 06:31:25 +00003385
3386badframe:
3387 unlock_user_struct(frame, frame_addr, 0);
3388 force_sig(TARGET_SIGSEGV);
3389 return 0;
3390}
3391
Andreas Färber05390242012-02-25 03:37:53 +01003392long do_rt_sigreturn(CPUSH4State *regs)
thsc3b5bc82007-12-02 06:31:25 +00003393{
3394 struct target_rt_sigframe *frame;
3395 abi_ulong frame_addr;
3396 sigset_t blocked;
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003397 target_ulong r0;
thsc3b5bc82007-12-02 06:31:25 +00003398
3399#if defined(DEBUG_SIGNAL)
3400 fprintf(stderr, "do_rt_sigreturn\n");
3401#endif
3402 frame_addr = regs->gregs[15];
3403 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
3404 goto badframe;
3405
Aurelien Jarno60e99242010-03-29 02:12:51 +02003406 target_to_host_sigset(&blocked, &frame->uc.tuc_sigmask);
Alex Barcelo1c275922014-03-14 14:36:55 +00003407 do_sigprocmask(SIG_SETMASK, &blocked, NULL);
thsc3b5bc82007-12-02 06:31:25 +00003408
Riku Voipio016d2e12014-04-23 11:19:48 +03003409 restore_sigcontext(regs, &frame->uc.tuc_mcontext, &r0);
thsc3b5bc82007-12-02 06:31:25 +00003410
3411 if (do_sigaltstack(frame_addr +
Aurelien Jarno60e99242010-03-29 02:12:51 +02003412 offsetof(struct target_rt_sigframe, uc.tuc_stack),
thsc3b5bc82007-12-02 06:31:25 +00003413 0, get_sp_from_cpustate(regs)) == -EFAULT)
3414 goto badframe;
3415
3416 unlock_user_struct(frame, frame_addr, 0);
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003417 return r0;
thsc3b5bc82007-12-02 06:31:25 +00003418
3419badframe:
3420 unlock_user_struct(frame, frame_addr, 0);
3421 force_sig(TARGET_SIGSEGV);
3422 return 0;
3423}
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003424#elif defined(TARGET_MICROBLAZE)
3425
3426struct target_sigcontext {
3427 struct target_pt_regs regs; /* needs to be first */
3428 uint32_t oldmask;
3429};
3430
Edgar E. Iglesiasb2178702010-07-23 09:30:37 +02003431struct target_stack_t {
3432 abi_ulong ss_sp;
3433 int ss_flags;
3434 unsigned int ss_size;
3435};
3436
3437struct target_ucontext {
Richard Hendersonf711df62010-11-22 14:57:52 -08003438 abi_ulong tuc_flags;
3439 abi_ulong tuc_link;
3440 struct target_stack_t tuc_stack;
3441 struct target_sigcontext tuc_mcontext;
3442 uint32_t tuc_extramask[TARGET_NSIG_WORDS - 1];
Edgar E. Iglesiasb2178702010-07-23 09:30:37 +02003443};
3444
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003445/* Signal frames. */
3446struct target_signal_frame {
Edgar E. Iglesiasb2178702010-07-23 09:30:37 +02003447 struct target_ucontext uc;
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003448 uint32_t extramask[TARGET_NSIG_WORDS - 1];
3449 uint32_t tramp[2];
3450};
3451
3452struct rt_signal_frame {
Richard W.M. Jones02d2bd52012-07-05 03:32:44 +00003453 siginfo_t info;
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003454 struct ucontext uc;
3455 uint32_t tramp[2];
3456};
3457
Andreas Färber05390242012-02-25 03:37:53 +01003458static void setup_sigcontext(struct target_sigcontext *sc, CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003459{
3460 __put_user(env->regs[0], &sc->regs.r0);
3461 __put_user(env->regs[1], &sc->regs.r1);
3462 __put_user(env->regs[2], &sc->regs.r2);
3463 __put_user(env->regs[3], &sc->regs.r3);
3464 __put_user(env->regs[4], &sc->regs.r4);
3465 __put_user(env->regs[5], &sc->regs.r5);
3466 __put_user(env->regs[6], &sc->regs.r6);
3467 __put_user(env->regs[7], &sc->regs.r7);
3468 __put_user(env->regs[8], &sc->regs.r8);
3469 __put_user(env->regs[9], &sc->regs.r9);
3470 __put_user(env->regs[10], &sc->regs.r10);
3471 __put_user(env->regs[11], &sc->regs.r11);
3472 __put_user(env->regs[12], &sc->regs.r12);
3473 __put_user(env->regs[13], &sc->regs.r13);
3474 __put_user(env->regs[14], &sc->regs.r14);
3475 __put_user(env->regs[15], &sc->regs.r15);
3476 __put_user(env->regs[16], &sc->regs.r16);
3477 __put_user(env->regs[17], &sc->regs.r17);
3478 __put_user(env->regs[18], &sc->regs.r18);
3479 __put_user(env->regs[19], &sc->regs.r19);
3480 __put_user(env->regs[20], &sc->regs.r20);
3481 __put_user(env->regs[21], &sc->regs.r21);
3482 __put_user(env->regs[22], &sc->regs.r22);
3483 __put_user(env->regs[23], &sc->regs.r23);
3484 __put_user(env->regs[24], &sc->regs.r24);
3485 __put_user(env->regs[25], &sc->regs.r25);
3486 __put_user(env->regs[26], &sc->regs.r26);
3487 __put_user(env->regs[27], &sc->regs.r27);
3488 __put_user(env->regs[28], &sc->regs.r28);
3489 __put_user(env->regs[29], &sc->regs.r29);
3490 __put_user(env->regs[30], &sc->regs.r30);
3491 __put_user(env->regs[31], &sc->regs.r31);
3492 __put_user(env->sregs[SR_PC], &sc->regs.pc);
3493}
3494
Andreas Färber05390242012-02-25 03:37:53 +01003495static void restore_sigcontext(struct target_sigcontext *sc, CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003496{
3497 __get_user(env->regs[0], &sc->regs.r0);
3498 __get_user(env->regs[1], &sc->regs.r1);
3499 __get_user(env->regs[2], &sc->regs.r2);
3500 __get_user(env->regs[3], &sc->regs.r3);
3501 __get_user(env->regs[4], &sc->regs.r4);
3502 __get_user(env->regs[5], &sc->regs.r5);
3503 __get_user(env->regs[6], &sc->regs.r6);
3504 __get_user(env->regs[7], &sc->regs.r7);
3505 __get_user(env->regs[8], &sc->regs.r8);
3506 __get_user(env->regs[9], &sc->regs.r9);
3507 __get_user(env->regs[10], &sc->regs.r10);
3508 __get_user(env->regs[11], &sc->regs.r11);
3509 __get_user(env->regs[12], &sc->regs.r12);
3510 __get_user(env->regs[13], &sc->regs.r13);
3511 __get_user(env->regs[14], &sc->regs.r14);
3512 __get_user(env->regs[15], &sc->regs.r15);
3513 __get_user(env->regs[16], &sc->regs.r16);
3514 __get_user(env->regs[17], &sc->regs.r17);
3515 __get_user(env->regs[18], &sc->regs.r18);
3516 __get_user(env->regs[19], &sc->regs.r19);
3517 __get_user(env->regs[20], &sc->regs.r20);
3518 __get_user(env->regs[21], &sc->regs.r21);
3519 __get_user(env->regs[22], &sc->regs.r22);
3520 __get_user(env->regs[23], &sc->regs.r23);
3521 __get_user(env->regs[24], &sc->regs.r24);
3522 __get_user(env->regs[25], &sc->regs.r25);
3523 __get_user(env->regs[26], &sc->regs.r26);
3524 __get_user(env->regs[27], &sc->regs.r27);
3525 __get_user(env->regs[28], &sc->regs.r28);
3526 __get_user(env->regs[29], &sc->regs.r29);
3527 __get_user(env->regs[30], &sc->regs.r30);
3528 __get_user(env->regs[31], &sc->regs.r31);
3529 __get_user(env->sregs[SR_PC], &sc->regs.pc);
3530}
3531
3532static abi_ulong get_sigframe(struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01003533 CPUMBState *env, int frame_size)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003534{
3535 abi_ulong sp = env->regs[1];
3536
3537 if ((ka->sa_flags & SA_ONSTACK) != 0 && !on_sig_stack(sp))
3538 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
3539
3540 return ((sp - frame_size) & -8UL);
3541}
3542
3543static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01003544 target_sigset_t *set, CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003545{
3546 struct target_signal_frame *frame;
3547 abi_ulong frame_addr;
3548 int err = 0;
3549 int i;
3550
3551 frame_addr = get_sigframe(ka, env, sizeof *frame);
3552 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
3553 goto badframe;
3554
3555 /* Save the mask. */
Riku Voipio1d8b5122014-04-23 10:26:05 +03003556 __put_user(set->sig[0], &frame->uc.tuc_mcontext.oldmask);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003557 if (err)
3558 goto badframe;
3559
3560 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
3561 if (__put_user(set->sig[i], &frame->extramask[i - 1]))
3562 goto badframe;
3563 }
3564
Richard Hendersonf711df62010-11-22 14:57:52 -08003565 setup_sigcontext(&frame->uc.tuc_mcontext, env);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003566
3567 /* Set up to return from userspace. If provided, use a stub
3568 already in userspace. */
3569 /* minus 8 is offset to cater for "rtsd r15,8" offset */
3570 if (ka->sa_flags & TARGET_SA_RESTORER) {
3571 env->regs[15] = ((unsigned long)ka->sa_restorer)-8;
3572 } else {
3573 uint32_t t;
3574 /* Note, these encodings are _big endian_! */
3575 /* addi r12, r0, __NR_sigreturn */
3576 t = 0x31800000UL | TARGET_NR_sigreturn;
Riku Voipio1d8b5122014-04-23 10:26:05 +03003577 __put_user(t, frame->tramp + 0);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003578 /* brki r14, 0x8 */
3579 t = 0xb9cc0008UL;
Riku Voipio1d8b5122014-04-23 10:26:05 +03003580 __put_user(t, frame->tramp + 1);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003581
3582 /* Return from sighandler will jump to the tramp.
3583 Negative 8 offset because return is rtsd r15, 8 */
3584 env->regs[15] = ((unsigned long)frame->tramp) - 8;
3585 }
3586
3587 if (err)
3588 goto badframe;
3589
3590 /* Set up registers for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003591 env->regs[1] = frame_addr;
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003592 /* Signal handler args: */
3593 env->regs[5] = sig; /* Arg 0: signum */
Edgar E. Iglesias187b4e02010-07-15 15:32:51 +02003594 env->regs[6] = 0;
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003595 /* arg 1: sigcontext */
3596 env->regs[7] = frame_addr += offsetof(typeof(*frame), uc);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003597
3598 /* Offset of 4 to handle microblaze rtid r14, 0 */
3599 env->sregs[SR_PC] = (unsigned long)ka->_sa_handler;
3600
3601 unlock_user_struct(frame, frame_addr, 1);
3602 return;
3603 badframe:
3604 unlock_user_struct(frame, frame_addr, 1);
3605 force_sig(TARGET_SIGSEGV);
3606}
3607
3608static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05003609 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01003610 target_sigset_t *set, CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003611{
3612 fprintf(stderr, "Microblaze setup_rt_frame: not implemented\n");
3613}
3614
Andreas Färber05390242012-02-25 03:37:53 +01003615long do_sigreturn(CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003616{
3617 struct target_signal_frame *frame;
3618 abi_ulong frame_addr;
Anthony Liguoric227f092009-10-01 16:12:16 -05003619 target_sigset_t target_set;
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003620 sigset_t set;
3621 int i;
3622
3623 frame_addr = env->regs[R_SP];
3624 /* Make sure the guest isn't playing games. */
3625 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 1))
3626 goto badframe;
3627
3628 /* Restore blocked signals */
Richard Hendersonf711df62010-11-22 14:57:52 -08003629 if (__get_user(target_set.sig[0], &frame->uc.tuc_mcontext.oldmask))
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003630 goto badframe;
3631 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
3632 if (__get_user(target_set.sig[i], &frame->extramask[i - 1]))
3633 goto badframe;
3634 }
3635 target_to_host_sigset_internal(&set, &target_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00003636 do_sigprocmask(SIG_SETMASK, &set, NULL);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003637
Richard Hendersonf711df62010-11-22 14:57:52 -08003638 restore_sigcontext(&frame->uc.tuc_mcontext, env);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003639 /* We got here through a sigreturn syscall, our path back is via an
3640 rtb insn so setup r14 for that. */
3641 env->regs[14] = env->sregs[SR_PC];
3642
3643 unlock_user_struct(frame, frame_addr, 0);
3644 return env->regs[10];
3645 badframe:
3646 unlock_user_struct(frame, frame_addr, 0);
3647 force_sig(TARGET_SIGSEGV);
3648}
3649
Andreas Färber05390242012-02-25 03:37:53 +01003650long do_rt_sigreturn(CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003651{
3652 fprintf(stderr, "Microblaze do_rt_sigreturn: not implemented\n");
3653 return -TARGET_ENOSYS;
3654}
3655
edgar_iglb6d3abd2008-02-28 11:29:27 +00003656#elif defined(TARGET_CRIS)
3657
3658struct target_sigcontext {
3659 struct target_pt_regs regs; /* needs to be first */
3660 uint32_t oldmask;
3661 uint32_t usp; /* usp before stacking this gunk on it */
3662};
3663
3664/* Signal frames. */
3665struct target_signal_frame {
3666 struct target_sigcontext sc;
3667 uint32_t extramask[TARGET_NSIG_WORDS - 1];
Stefan Weil8cfc1142014-02-01 09:41:09 +01003668 uint16_t retcode[4]; /* Trampoline code. */
edgar_iglb6d3abd2008-02-28 11:29:27 +00003669};
3670
3671struct rt_signal_frame {
Richard W.M. Jones02d2bd52012-07-05 03:32:44 +00003672 siginfo_t *pinfo;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003673 void *puc;
Richard W.M. Jones02d2bd52012-07-05 03:32:44 +00003674 siginfo_t info;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003675 struct ucontext uc;
Stefan Weil8cfc1142014-02-01 09:41:09 +01003676 uint16_t retcode[4]; /* Trampoline code. */
edgar_iglb6d3abd2008-02-28 11:29:27 +00003677};
3678
Andreas Färber05390242012-02-25 03:37:53 +01003679static void setup_sigcontext(struct target_sigcontext *sc, CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003680{
edgar_igl9664d922008-03-03 22:23:53 +00003681 __put_user(env->regs[0], &sc->regs.r0);
3682 __put_user(env->regs[1], &sc->regs.r1);
3683 __put_user(env->regs[2], &sc->regs.r2);
3684 __put_user(env->regs[3], &sc->regs.r3);
3685 __put_user(env->regs[4], &sc->regs.r4);
3686 __put_user(env->regs[5], &sc->regs.r5);
3687 __put_user(env->regs[6], &sc->regs.r6);
3688 __put_user(env->regs[7], &sc->regs.r7);
3689 __put_user(env->regs[8], &sc->regs.r8);
3690 __put_user(env->regs[9], &sc->regs.r9);
3691 __put_user(env->regs[10], &sc->regs.r10);
3692 __put_user(env->regs[11], &sc->regs.r11);
3693 __put_user(env->regs[12], &sc->regs.r12);
3694 __put_user(env->regs[13], &sc->regs.r13);
3695 __put_user(env->regs[14], &sc->usp);
3696 __put_user(env->regs[15], &sc->regs.acr);
3697 __put_user(env->pregs[PR_MOF], &sc->regs.mof);
3698 __put_user(env->pregs[PR_SRP], &sc->regs.srp);
3699 __put_user(env->pc, &sc->regs.erp);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003700}
edgar_igl9664d922008-03-03 22:23:53 +00003701
Andreas Färber05390242012-02-25 03:37:53 +01003702static void restore_sigcontext(struct target_sigcontext *sc, CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003703{
edgar_igl9664d922008-03-03 22:23:53 +00003704 __get_user(env->regs[0], &sc->regs.r0);
3705 __get_user(env->regs[1], &sc->regs.r1);
3706 __get_user(env->regs[2], &sc->regs.r2);
3707 __get_user(env->regs[3], &sc->regs.r3);
3708 __get_user(env->regs[4], &sc->regs.r4);
3709 __get_user(env->regs[5], &sc->regs.r5);
3710 __get_user(env->regs[6], &sc->regs.r6);
3711 __get_user(env->regs[7], &sc->regs.r7);
3712 __get_user(env->regs[8], &sc->regs.r8);
3713 __get_user(env->regs[9], &sc->regs.r9);
3714 __get_user(env->regs[10], &sc->regs.r10);
3715 __get_user(env->regs[11], &sc->regs.r11);
3716 __get_user(env->regs[12], &sc->regs.r12);
3717 __get_user(env->regs[13], &sc->regs.r13);
3718 __get_user(env->regs[14], &sc->usp);
3719 __get_user(env->regs[15], &sc->regs.acr);
3720 __get_user(env->pregs[PR_MOF], &sc->regs.mof);
3721 __get_user(env->pregs[PR_SRP], &sc->regs.srp);
3722 __get_user(env->pc, &sc->regs.erp);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003723}
3724
Andreas Färber05390242012-02-25 03:37:53 +01003725static abi_ulong get_sigframe(CPUCRISState *env, int framesize)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003726{
edgar_igl9664d922008-03-03 22:23:53 +00003727 abi_ulong sp;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003728 /* Align the stack downwards to 4. */
edgar_igl9664d922008-03-03 22:23:53 +00003729 sp = (env->regs[R_SP] & ~3);
3730 return sp - framesize;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003731}
3732
pbrook624f7972008-05-31 16:11:38 +00003733static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01003734 target_sigset_t *set, CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003735{
3736 struct target_signal_frame *frame;
edgar_igl9664d922008-03-03 22:23:53 +00003737 abi_ulong frame_addr;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003738 int err = 0;
3739 int i;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003740
edgar_igl9664d922008-03-03 22:23:53 +00003741 frame_addr = get_sigframe(env, sizeof *frame);
3742 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
edgar_iglb6d3abd2008-02-28 11:29:27 +00003743 goto badframe;
3744
3745 /*
3746 * The CRIS signal return trampoline. A real linux/CRIS kernel doesn't
3747 * use this trampoline anymore but it sets it up for GDB.
3748 * In QEMU, using the trampoline simplifies things a bit so we use it.
3749 *
3750 * This is movu.w __NR_sigreturn, r9; break 13;
3751 */
Riku Voipio1d8b5122014-04-23 10:26:05 +03003752 __put_user(0x9c5f, frame->retcode+0);
3753 __put_user(TARGET_NR_sigreturn,
3754 frame->retcode + 1);
3755 __put_user(0xe93d, frame->retcode + 2);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003756
3757 /* Save the mask. */
Riku Voipio1d8b5122014-04-23 10:26:05 +03003758 __put_user(set->sig[0], &frame->sc.oldmask);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003759 if (err)
3760 goto badframe;
3761
3762 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
3763 if (__put_user(set->sig[i], &frame->extramask[i - 1]))
3764 goto badframe;
3765 }
3766
3767 setup_sigcontext(&frame->sc, env);
3768
3769 /* Move the stack and setup the arguments for the handler. */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003770 env->regs[R_SP] = frame_addr;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003771 env->regs[10] = sig;
pbrook624f7972008-05-31 16:11:38 +00003772 env->pc = (unsigned long) ka->_sa_handler;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003773 /* Link SRP so the guest returns through the trampoline. */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003774 env->pregs[PR_SRP] = frame_addr + offsetof(typeof(*frame), retcode);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003775
edgar_igl9664d922008-03-03 22:23:53 +00003776 unlock_user_struct(frame, frame_addr, 1);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003777 return;
3778 badframe:
edgar_igl9664d922008-03-03 22:23:53 +00003779 unlock_user_struct(frame, frame_addr, 1);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003780 force_sig(TARGET_SIGSEGV);
3781}
3782
pbrook624f7972008-05-31 16:11:38 +00003783static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05003784 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01003785 target_sigset_t *set, CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003786{
3787 fprintf(stderr, "CRIS setup_rt_frame: not implemented\n");
3788}
3789
Andreas Färber05390242012-02-25 03:37:53 +01003790long do_sigreturn(CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003791{
3792 struct target_signal_frame *frame;
edgar_igl9664d922008-03-03 22:23:53 +00003793 abi_ulong frame_addr;
Anthony Liguoric227f092009-10-01 16:12:16 -05003794 target_sigset_t target_set;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003795 sigset_t set;
3796 int i;
3797
edgar_igl9664d922008-03-03 22:23:53 +00003798 frame_addr = env->regs[R_SP];
edgar_iglb6d3abd2008-02-28 11:29:27 +00003799 /* Make sure the guest isn't playing games. */
edgar_igl9664d922008-03-03 22:23:53 +00003800 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 1))
edgar_iglb6d3abd2008-02-28 11:29:27 +00003801 goto badframe;
3802
3803 /* Restore blocked signals */
3804 if (__get_user(target_set.sig[0], &frame->sc.oldmask))
3805 goto badframe;
3806 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
3807 if (__get_user(target_set.sig[i], &frame->extramask[i - 1]))
3808 goto badframe;
3809 }
3810 target_to_host_sigset_internal(&set, &target_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00003811 do_sigprocmask(SIG_SETMASK, &set, NULL);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003812
3813 restore_sigcontext(&frame->sc, env);
edgar_igl9664d922008-03-03 22:23:53 +00003814 unlock_user_struct(frame, frame_addr, 0);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003815 return env->regs[10];
3816 badframe:
edgar_igl9664d922008-03-03 22:23:53 +00003817 unlock_user_struct(frame, frame_addr, 0);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003818 force_sig(TARGET_SIGSEGV);
3819}
3820
Andreas Färber05390242012-02-25 03:37:53 +01003821long do_rt_sigreturn(CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003822{
3823 fprintf(stderr, "CRIS do_rt_sigreturn: not implemented\n");
3824 return -TARGET_ENOSYS;
3825}
thsc3b5bc82007-12-02 06:31:25 +00003826
Jia Liud9627832012-07-20 15:50:52 +08003827#elif defined(TARGET_OPENRISC)
3828
3829struct target_sigcontext {
3830 struct target_pt_regs regs;
3831 abi_ulong oldmask;
3832 abi_ulong usp;
3833};
3834
3835struct target_ucontext {
3836 abi_ulong tuc_flags;
3837 abi_ulong tuc_link;
3838 target_stack_t tuc_stack;
3839 struct target_sigcontext tuc_mcontext;
3840 target_sigset_t tuc_sigmask; /* mask last for extensibility */
3841};
3842
3843struct target_rt_sigframe {
3844 abi_ulong pinfo;
3845 uint64_t puc;
3846 struct target_siginfo info;
3847 struct target_sigcontext sc;
3848 struct target_ucontext uc;
3849 unsigned char retcode[16]; /* trampoline code */
3850};
3851
3852/* This is the asm-generic/ucontext.h version */
3853#if 0
3854static int restore_sigcontext(CPUOpenRISCState *regs,
3855 struct target_sigcontext *sc)
3856{
3857 unsigned int err = 0;
3858 unsigned long old_usp;
3859
3860 /* Alwys make any pending restarted system call return -EINTR */
3861 current_thread_info()->restart_block.fn = do_no_restart_syscall;
3862
3863 /* restore the regs from &sc->regs (same as sc, since regs is first)
3864 * (sc is already checked for VERIFY_READ since the sigframe was
3865 * checked in sys_sigreturn previously)
3866 */
3867
3868 if (copy_from_user(regs, &sc, sizeof(struct target_pt_regs))) {
3869 goto badframe;
3870 }
3871
3872 /* make sure the U-flag is set so user-mode cannot fool us */
3873
3874 regs->sr &= ~SR_SM;
3875
3876 /* restore the old USP as it was before we stacked the sc etc.
3877 * (we cannot just pop the sigcontext since we aligned the sp and
3878 * stuff after pushing it)
3879 */
3880
Riku Voipio1d8b5122014-04-23 10:26:05 +03003881 __get_user(old_usp, &sc->usp);
Jia Liud9627832012-07-20 15:50:52 +08003882 phx_signal("old_usp 0x%lx", old_usp);
3883
3884 __PHX__ REALLY /* ??? */
3885 wrusp(old_usp);
3886 regs->gpr[1] = old_usp;
3887
3888 /* TODO: the other ports use regs->orig_XX to disable syscall checks
3889 * after this completes, but we don't use that mechanism. maybe we can
3890 * use it now ?
3891 */
3892
3893 return err;
3894
3895badframe:
3896 return 1;
3897}
3898#endif
3899
3900/* Set up a signal frame. */
3901
Riku Voipio41ecc722014-04-23 11:01:00 +03003902static void setup_sigcontext(struct target_sigcontext *sc,
Jia Liud9627832012-07-20 15:50:52 +08003903 CPUOpenRISCState *regs,
3904 unsigned long mask)
3905{
Jia Liud9627832012-07-20 15:50:52 +08003906 unsigned long usp = regs->gpr[1];
3907
3908 /* copy the regs. they are first in sc so we can use sc directly */
3909
Riku Voipio1d8b5122014-04-23 10:26:05 +03003910 /*copy_to_user(&sc, regs, sizeof(struct target_pt_regs));*/
Jia Liud9627832012-07-20 15:50:52 +08003911
3912 /* Set the frametype to CRIS_FRAME_NORMAL for the execution of
3913 the signal handler. The frametype will be restored to its previous
3914 value in restore_sigcontext. */
3915 /*regs->frametype = CRIS_FRAME_NORMAL;*/
3916
3917 /* then some other stuff */
Riku Voipio1d8b5122014-04-23 10:26:05 +03003918 __put_user(mask, &sc->oldmask);
Riku Voipio41ecc722014-04-23 11:01:00 +03003919 __put_user(usp, &sc->usp);
Jia Liud9627832012-07-20 15:50:52 +08003920}
3921
3922static inline unsigned long align_sigframe(unsigned long sp)
3923{
3924 unsigned long i;
3925 i = sp & ~3UL;
3926 return i;
3927}
3928
3929static inline abi_ulong get_sigframe(struct target_sigaction *ka,
3930 CPUOpenRISCState *regs,
3931 size_t frame_size)
3932{
3933 unsigned long sp = regs->gpr[1];
3934 int onsigstack = on_sig_stack(sp);
3935
3936 /* redzone */
3937 /* This is the X/Open sanctioned signal stack switching. */
3938 if ((ka->sa_flags & SA_ONSTACK) != 0 && !onsigstack) {
3939 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
3940 }
3941
3942 sp = align_sigframe(sp - frame_size);
3943
3944 /*
3945 * If we are on the alternate signal stack and would overflow it, don't.
3946 * Return an always-bogus address instead so we will die with SIGSEGV.
3947 */
3948
3949 if (onsigstack && !likely(on_sig_stack(sp))) {
3950 return -1L;
3951 }
3952
3953 return sp;
3954}
3955
3956static void setup_frame(int sig, struct target_sigaction *ka,
3957 target_sigset_t *set, CPUOpenRISCState *env)
3958{
3959 qemu_log("Not implement.\n");
3960}
3961
3962static void setup_rt_frame(int sig, struct target_sigaction *ka,
3963 target_siginfo_t *info,
3964 target_sigset_t *set, CPUOpenRISCState *env)
3965{
3966 int err = 0;
3967 abi_ulong frame_addr;
3968 unsigned long return_ip;
3969 struct target_rt_sigframe *frame;
3970 abi_ulong info_addr, uc_addr;
3971
Jia Liud9627832012-07-20 15:50:52 +08003972 frame_addr = get_sigframe(ka, env, sizeof(*frame));
3973 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
3974 goto give_sigsegv;
3975 }
3976
3977 info_addr = frame_addr + offsetof(struct target_rt_sigframe, info);
Riku Voipio1d8b5122014-04-23 10:26:05 +03003978 __put_user(info_addr, &frame->pinfo);
Jia Liud9627832012-07-20 15:50:52 +08003979 uc_addr = frame_addr + offsetof(struct target_rt_sigframe, uc);
Riku Voipio1d8b5122014-04-23 10:26:05 +03003980 __put_user(uc_addr, &frame->puc);
Jia Liud9627832012-07-20 15:50:52 +08003981
3982 if (ka->sa_flags & SA_SIGINFO) {
Riku Voipiob0fd8d12014-04-23 10:46:13 +03003983 copy_siginfo_to_user(&frame->info, info);
Jia Liud9627832012-07-20 15:50:52 +08003984 }
3985
3986 /*err |= __clear_user(&frame->uc, offsetof(struct ucontext, uc_mcontext));*/
Riku Voipio1d8b5122014-04-23 10:26:05 +03003987 __put_user(0, &frame->uc.tuc_flags);
3988 __put_user(0, &frame->uc.tuc_link);
3989 __put_user(target_sigaltstack_used.ss_sp,
3990 &frame->uc.tuc_stack.ss_sp);
3991 __put_user(sas_ss_flags(env->gpr[1]), &frame->uc.tuc_stack.ss_flags);
3992 __put_user(target_sigaltstack_used.ss_size,
3993 &frame->uc.tuc_stack.ss_size);
Riku Voipio41ecc722014-04-23 11:01:00 +03003994 setup_sigcontext(&frame->sc, env, set->sig[0]);
Jia Liud9627832012-07-20 15:50:52 +08003995
3996 /*err |= copy_to_user(frame->uc.tuc_sigmask, set, sizeof(*set));*/
3997
Jia Liud9627832012-07-20 15:50:52 +08003998 /* trampoline - the desired return ip is the retcode itself */
3999 return_ip = (unsigned long)&frame->retcode;
4000 /* This is l.ori r11,r0,__NR_sigreturn, l.sys 1 */
Riku Voipio1d8b5122014-04-23 10:26:05 +03004001 __put_user(0xa960, (short *)(frame->retcode + 0));
4002 __put_user(TARGET_NR_rt_sigreturn, (short *)(frame->retcode + 2));
4003 __put_user(0x20000001, (unsigned long *)(frame->retcode + 4));
4004 __put_user(0x15000000, (unsigned long *)(frame->retcode + 8));
Jia Liud9627832012-07-20 15:50:52 +08004005
4006 if (err) {
4007 goto give_sigsegv;
4008 }
4009
4010 /* TODO what is the current->exec_domain stuff and invmap ? */
4011
4012 /* Set up registers for signal handler */
4013 env->pc = (unsigned long)ka->_sa_handler; /* what we enter NOW */
4014 env->gpr[9] = (unsigned long)return_ip; /* what we enter LATER */
4015 env->gpr[3] = (unsigned long)sig; /* arg 1: signo */
4016 env->gpr[4] = (unsigned long)&frame->info; /* arg 2: (siginfo_t*) */
4017 env->gpr[5] = (unsigned long)&frame->uc; /* arg 3: ucontext */
4018
4019 /* actually move the usp to reflect the stacked frame */
4020 env->gpr[1] = (unsigned long)frame;
4021
4022 return;
4023
4024give_sigsegv:
4025 unlock_user_struct(frame, frame_addr, 1);
4026 if (sig == TARGET_SIGSEGV) {
4027 ka->_sa_handler = TARGET_SIG_DFL;
4028 }
4029 force_sig(TARGET_SIGSEGV);
4030}
4031
4032long do_sigreturn(CPUOpenRISCState *env)
4033{
4034
4035 qemu_log("do_sigreturn: not implemented\n");
4036 return -TARGET_ENOSYS;
4037}
4038
4039long do_rt_sigreturn(CPUOpenRISCState *env)
4040{
4041 qemu_log("do_rt_sigreturn: not implemented\n");
4042 return -TARGET_ENOSYS;
4043}
4044/* TARGET_OPENRISC */
4045
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004046#elif defined(TARGET_S390X)
4047
4048#define __NUM_GPRS 16
4049#define __NUM_FPRS 16
4050#define __NUM_ACRS 16
4051
4052#define S390_SYSCALL_SIZE 2
4053#define __SIGNAL_FRAMESIZE 160 /* FIXME: 31-bit mode -> 96 */
4054
4055#define _SIGCONTEXT_NSIG 64
4056#define _SIGCONTEXT_NSIG_BPW 64 /* FIXME: 31-bit mode -> 32 */
4057#define _SIGCONTEXT_NSIG_WORDS (_SIGCONTEXT_NSIG / _SIGCONTEXT_NSIG_BPW)
4058#define _SIGMASK_COPY_SIZE (sizeof(unsigned long)*_SIGCONTEXT_NSIG_WORDS)
4059#define PSW_ADDR_AMODE 0x0000000000000000UL /* 0x80000000UL for 31-bit */
4060#define S390_SYSCALL_OPCODE ((uint16_t)0x0a00)
4061
4062typedef struct {
4063 target_psw_t psw;
4064 target_ulong gprs[__NUM_GPRS];
4065 unsigned int acrs[__NUM_ACRS];
4066} target_s390_regs_common;
4067
4068typedef struct {
4069 unsigned int fpc;
4070 double fprs[__NUM_FPRS];
4071} target_s390_fp_regs;
4072
4073typedef struct {
4074 target_s390_regs_common regs;
4075 target_s390_fp_regs fpregs;
4076} target_sigregs;
4077
4078struct target_sigcontext {
4079 target_ulong oldmask[_SIGCONTEXT_NSIG_WORDS];
4080 target_sigregs *sregs;
4081};
4082
4083typedef struct {
4084 uint8_t callee_used_stack[__SIGNAL_FRAMESIZE];
4085 struct target_sigcontext sc;
4086 target_sigregs sregs;
4087 int signo;
4088 uint8_t retcode[S390_SYSCALL_SIZE];
4089} sigframe;
4090
4091struct target_ucontext {
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004092 target_ulong tuc_flags;
4093 struct target_ucontext *tuc_link;
4094 target_stack_t tuc_stack;
4095 target_sigregs tuc_mcontext;
4096 target_sigset_t tuc_sigmask; /* mask last for extensibility */
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004097};
4098
4099typedef struct {
4100 uint8_t callee_used_stack[__SIGNAL_FRAMESIZE];
4101 uint8_t retcode[S390_SYSCALL_SIZE];
4102 struct target_siginfo info;
4103 struct target_ucontext uc;
4104} rt_sigframe;
4105
4106static inline abi_ulong
Andreas Färber05390242012-02-25 03:37:53 +01004107get_sigframe(struct target_sigaction *ka, CPUS390XState *env, size_t frame_size)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004108{
4109 abi_ulong sp;
4110
4111 /* Default to using normal stack */
4112 sp = env->regs[15];
4113
4114 /* This is the X/Open sanctioned signal stack switching. */
4115 if (ka->sa_flags & TARGET_SA_ONSTACK) {
4116 if (!sas_ss_flags(sp)) {
4117 sp = target_sigaltstack_used.ss_sp +
4118 target_sigaltstack_used.ss_size;
4119 }
4120 }
4121
4122 /* This is the legacy signal stack switching. */
4123 else if (/* FIXME !user_mode(regs) */ 0 &&
4124 !(ka->sa_flags & TARGET_SA_RESTORER) &&
4125 ka->sa_restorer) {
4126 sp = (abi_ulong) ka->sa_restorer;
4127 }
4128
4129 return (sp - frame_size) & -8ul;
4130}
4131
Andreas Färber05390242012-02-25 03:37:53 +01004132static void save_sigregs(CPUS390XState *env, target_sigregs *sregs)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004133{
4134 int i;
4135 //save_access_regs(current->thread.acrs); FIXME
4136
4137 /* Copy a 'clean' PSW mask to the user to avoid leaking
4138 information about whether PER is currently on. */
4139 __put_user(env->psw.mask, &sregs->regs.psw.mask);
4140 __put_user(env->psw.addr, &sregs->regs.psw.addr);
4141 for (i = 0; i < 16; i++) {
4142 __put_user(env->regs[i], &sregs->regs.gprs[i]);
4143 }
4144 for (i = 0; i < 16; i++) {
4145 __put_user(env->aregs[i], &sregs->regs.acrs[i]);
4146 }
4147 /*
4148 * We have to store the fp registers to current->thread.fp_regs
4149 * to merge them with the emulated registers.
4150 */
4151 //save_fp_regs(&current->thread.fp_regs); FIXME
4152 for (i = 0; i < 16; i++) {
4153 __put_user(env->fregs[i].ll, &sregs->fpregs.fprs[i]);
4154 }
4155}
4156
4157static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01004158 target_sigset_t *set, CPUS390XState *env)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004159{
4160 sigframe *frame;
4161 abi_ulong frame_addr;
4162
4163 frame_addr = get_sigframe(ka, env, sizeof(*frame));
4164 qemu_log("%s: frame_addr 0x%llx\n", __FUNCTION__,
4165 (unsigned long long)frame_addr);
4166 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
4167 goto give_sigsegv;
4168 }
4169
4170 qemu_log("%s: 1\n", __FUNCTION__);
4171 if (__put_user(set->sig[0], &frame->sc.oldmask[0])) {
4172 goto give_sigsegv;
4173 }
4174
4175 save_sigregs(env, &frame->sregs);
4176
4177 __put_user((abi_ulong)(unsigned long)&frame->sregs,
4178 (abi_ulong *)&frame->sc.sregs);
4179
4180 /* Set up to return from userspace. If provided, use a stub
4181 already in userspace. */
4182 if (ka->sa_flags & TARGET_SA_RESTORER) {
4183 env->regs[14] = (unsigned long)
4184 ka->sa_restorer | PSW_ADDR_AMODE;
4185 } else {
4186 env->regs[14] = (unsigned long)
4187 frame->retcode | PSW_ADDR_AMODE;
4188 if (__put_user(S390_SYSCALL_OPCODE | TARGET_NR_sigreturn,
4189 (uint16_t *)(frame->retcode)))
4190 goto give_sigsegv;
4191 }
4192
4193 /* Set up backchain. */
4194 if (__put_user(env->regs[15], (abi_ulong *) frame)) {
4195 goto give_sigsegv;
4196 }
4197
4198 /* Set up registers for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02004199 env->regs[15] = frame_addr;
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004200 env->psw.addr = (target_ulong) ka->_sa_handler | PSW_ADDR_AMODE;
4201
4202 env->regs[2] = sig; //map_signal(sig);
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02004203 env->regs[3] = frame_addr += offsetof(typeof(*frame), sc);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004204
4205 /* We forgot to include these in the sigcontext.
4206 To avoid breaking binary compatibility, they are passed as args. */
4207 env->regs[4] = 0; // FIXME: no clue... current->thread.trap_no;
4208 env->regs[5] = 0; // FIXME: no clue... current->thread.prot_addr;
4209
4210 /* Place signal number on stack to allow backtrace from handler. */
4211 if (__put_user(env->regs[2], (int *) &frame->signo)) {
4212 goto give_sigsegv;
4213 }
4214 unlock_user_struct(frame, frame_addr, 1);
4215 return;
4216
4217give_sigsegv:
4218 qemu_log("%s: give_sigsegv\n", __FUNCTION__);
4219 unlock_user_struct(frame, frame_addr, 1);
4220 force_sig(TARGET_SIGSEGV);
4221}
4222
4223static void setup_rt_frame(int sig, struct target_sigaction *ka,
4224 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01004225 target_sigset_t *set, CPUS390XState *env)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004226{
4227 int i;
4228 rt_sigframe *frame;
4229 abi_ulong frame_addr;
4230
4231 frame_addr = get_sigframe(ka, env, sizeof *frame);
4232 qemu_log("%s: frame_addr 0x%llx\n", __FUNCTION__,
4233 (unsigned long long)frame_addr);
4234 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
4235 goto give_sigsegv;
4236 }
4237
4238 qemu_log("%s: 1\n", __FUNCTION__);
Riku Voipiob0fd8d12014-04-23 10:46:13 +03004239 copy_siginfo_to_user(&frame->info, info);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004240
4241 /* Create the ucontext. */
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004242 __put_user(0, &frame->uc.tuc_flags);
4243 __put_user((abi_ulong)0, (abi_ulong *)&frame->uc.tuc_link);
4244 __put_user(target_sigaltstack_used.ss_sp, &frame->uc.tuc_stack.ss_sp);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004245 __put_user(sas_ss_flags(get_sp_from_cpustate(env)),
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004246 &frame->uc.tuc_stack.ss_flags);
4247 __put_user(target_sigaltstack_used.ss_size, &frame->uc.tuc_stack.ss_size);
4248 save_sigregs(env, &frame->uc.tuc_mcontext);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004249 for (i = 0; i < TARGET_NSIG_WORDS; i++) {
4250 __put_user((abi_ulong)set->sig[i],
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004251 (abi_ulong *)&frame->uc.tuc_sigmask.sig[i]);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004252 }
4253
4254 /* Set up to return from userspace. If provided, use a stub
4255 already in userspace. */
4256 if (ka->sa_flags & TARGET_SA_RESTORER) {
4257 env->regs[14] = (unsigned long) ka->sa_restorer | PSW_ADDR_AMODE;
4258 } else {
4259 env->regs[14] = (unsigned long) frame->retcode | PSW_ADDR_AMODE;
4260 if (__put_user(S390_SYSCALL_OPCODE | TARGET_NR_rt_sigreturn,
4261 (uint16_t *)(frame->retcode))) {
4262 goto give_sigsegv;
4263 }
4264 }
4265
4266 /* Set up backchain. */
4267 if (__put_user(env->regs[15], (abi_ulong *) frame)) {
4268 goto give_sigsegv;
4269 }
4270
4271 /* Set up registers for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02004272 env->regs[15] = frame_addr;
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004273 env->psw.addr = (target_ulong) ka->_sa_handler | PSW_ADDR_AMODE;
4274
4275 env->regs[2] = sig; //map_signal(sig);
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02004276 env->regs[3] = frame_addr + offsetof(typeof(*frame), info);
4277 env->regs[4] = frame_addr + offsetof(typeof(*frame), uc);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004278 return;
4279
4280give_sigsegv:
4281 qemu_log("%s: give_sigsegv\n", __FUNCTION__);
4282 unlock_user_struct(frame, frame_addr, 1);
4283 force_sig(TARGET_SIGSEGV);
4284}
4285
4286static int
Andreas Färber05390242012-02-25 03:37:53 +01004287restore_sigregs(CPUS390XState *env, target_sigregs *sc)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004288{
4289 int err = 0;
4290 int i;
4291
4292 for (i = 0; i < 16; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03004293 __get_user(env->regs[i], &sc->regs.gprs[i]);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004294 }
4295
Riku Voipio1d8b5122014-04-23 10:26:05 +03004296 __get_user(env->psw.mask, &sc->regs.psw.mask);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004297 qemu_log("%s: sc->regs.psw.addr 0x%llx env->psw.addr 0x%llx\n",
4298 __FUNCTION__, (unsigned long long)sc->regs.psw.addr,
4299 (unsigned long long)env->psw.addr);
Riku Voipio1d8b5122014-04-23 10:26:05 +03004300 __get_user(env->psw.addr, &sc->regs.psw.addr);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004301 /* FIXME: 31-bit -> | PSW_ADDR_AMODE */
4302
4303 for (i = 0; i < 16; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03004304 __get_user(env->aregs[i], &sc->regs.acrs[i]);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004305 }
4306 for (i = 0; i < 16; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03004307 __get_user(env->fregs[i].ll, &sc->fpregs.fprs[i]);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004308 }
4309
4310 return err;
4311}
4312
Andreas Färber05390242012-02-25 03:37:53 +01004313long do_sigreturn(CPUS390XState *env)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004314{
4315 sigframe *frame;
4316 abi_ulong frame_addr = env->regs[15];
4317 qemu_log("%s: frame_addr 0x%llx\n", __FUNCTION__,
4318 (unsigned long long)frame_addr);
4319 target_sigset_t target_set;
4320 sigset_t set;
4321
4322 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
4323 goto badframe;
4324 }
4325 if (__get_user(target_set.sig[0], &frame->sc.oldmask[0])) {
4326 goto badframe;
4327 }
4328
4329 target_to_host_sigset_internal(&set, &target_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00004330 do_sigprocmask(SIG_SETMASK, &set, NULL); /* ~_BLOCKABLE? */
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004331
4332 if (restore_sigregs(env, &frame->sregs)) {
4333 goto badframe;
4334 }
4335
4336 unlock_user_struct(frame, frame_addr, 0);
4337 return env->regs[2];
4338
4339badframe:
4340 unlock_user_struct(frame, frame_addr, 0);
4341 force_sig(TARGET_SIGSEGV);
4342 return 0;
4343}
4344
Andreas Färber05390242012-02-25 03:37:53 +01004345long do_rt_sigreturn(CPUS390XState *env)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004346{
4347 rt_sigframe *frame;
4348 abi_ulong frame_addr = env->regs[15];
4349 qemu_log("%s: frame_addr 0x%llx\n", __FUNCTION__,
4350 (unsigned long long)frame_addr);
4351 sigset_t set;
4352
4353 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
4354 goto badframe;
4355 }
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004356 target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004357
Alex Barcelo1c275922014-03-14 14:36:55 +00004358 do_sigprocmask(SIG_SETMASK, &set, NULL); /* ~_BLOCKABLE? */
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004359
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004360 if (restore_sigregs(env, &frame->uc.tuc_mcontext)) {
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004361 goto badframe;
4362 }
4363
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004364 if (do_sigaltstack(frame_addr + offsetof(rt_sigframe, uc.tuc_stack), 0,
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004365 get_sp_from_cpustate(env)) == -EFAULT) {
4366 goto badframe;
4367 }
4368 unlock_user_struct(frame, frame_addr, 0);
4369 return env->regs[2];
4370
4371badframe:
4372 unlock_user_struct(frame, frame_addr, 0);
4373 force_sig(TARGET_SIGSEGV);
4374 return 0;
4375}
4376
Nathan Froydbcd49332009-05-12 19:13:18 -07004377#elif defined(TARGET_PPC) && !defined(TARGET_PPC64)
4378
4379/* FIXME: Many of the structures are defined for both PPC and PPC64, but
4380 the signal handling is different enough that we haven't implemented
4381 support for PPC64 yet. Hence the restriction above.
4382
4383 There are various #if'd blocks for code for TARGET_PPC64. These
4384 blocks should go away so that we can successfully run 32-bit and
4385 64-bit binaries on a QEMU configured for PPC64. */
4386
4387/* Size of dummy stack frame allocated when calling signal handler.
4388 See arch/powerpc/include/asm/ptrace.h. */
4389#if defined(TARGET_PPC64)
4390#define SIGNAL_FRAMESIZE 128
4391#else
4392#define SIGNAL_FRAMESIZE 64
4393#endif
4394
4395/* See arch/powerpc/include/asm/sigcontext.h. */
4396struct target_sigcontext {
4397 target_ulong _unused[4];
4398 int32_t signal;
4399#if defined(TARGET_PPC64)
4400 int32_t pad0;
4401#endif
4402 target_ulong handler;
4403 target_ulong oldmask;
4404 target_ulong regs; /* struct pt_regs __user * */
4405 /* TODO: PPC64 includes extra bits here. */
4406};
4407
4408/* Indices for target_mcontext.mc_gregs, below.
4409 See arch/powerpc/include/asm/ptrace.h for details. */
4410enum {
4411 TARGET_PT_R0 = 0,
4412 TARGET_PT_R1 = 1,
4413 TARGET_PT_R2 = 2,
4414 TARGET_PT_R3 = 3,
4415 TARGET_PT_R4 = 4,
4416 TARGET_PT_R5 = 5,
4417 TARGET_PT_R6 = 6,
4418 TARGET_PT_R7 = 7,
4419 TARGET_PT_R8 = 8,
4420 TARGET_PT_R9 = 9,
4421 TARGET_PT_R10 = 10,
4422 TARGET_PT_R11 = 11,
4423 TARGET_PT_R12 = 12,
4424 TARGET_PT_R13 = 13,
4425 TARGET_PT_R14 = 14,
4426 TARGET_PT_R15 = 15,
4427 TARGET_PT_R16 = 16,
4428 TARGET_PT_R17 = 17,
4429 TARGET_PT_R18 = 18,
4430 TARGET_PT_R19 = 19,
4431 TARGET_PT_R20 = 20,
4432 TARGET_PT_R21 = 21,
4433 TARGET_PT_R22 = 22,
4434 TARGET_PT_R23 = 23,
4435 TARGET_PT_R24 = 24,
4436 TARGET_PT_R25 = 25,
4437 TARGET_PT_R26 = 26,
4438 TARGET_PT_R27 = 27,
4439 TARGET_PT_R28 = 28,
4440 TARGET_PT_R29 = 29,
4441 TARGET_PT_R30 = 30,
4442 TARGET_PT_R31 = 31,
4443 TARGET_PT_NIP = 32,
4444 TARGET_PT_MSR = 33,
4445 TARGET_PT_ORIG_R3 = 34,
4446 TARGET_PT_CTR = 35,
4447 TARGET_PT_LNK = 36,
4448 TARGET_PT_XER = 37,
4449 TARGET_PT_CCR = 38,
4450 /* Yes, there are two registers with #39. One is 64-bit only. */
4451 TARGET_PT_MQ = 39,
4452 TARGET_PT_SOFTE = 39,
4453 TARGET_PT_TRAP = 40,
4454 TARGET_PT_DAR = 41,
4455 TARGET_PT_DSISR = 42,
4456 TARGET_PT_RESULT = 43,
4457 TARGET_PT_REGS_COUNT = 44
4458};
4459
4460/* See arch/powerpc/include/asm/ucontext.h. Only used for 32-bit PPC;
4461 on 64-bit PPC, sigcontext and mcontext are one and the same. */
4462struct target_mcontext {
4463 target_ulong mc_gregs[48];
4464 /* Includes fpscr. */
4465 uint64_t mc_fregs[33];
4466 target_ulong mc_pad[2];
4467 /* We need to handle Altivec and SPE at the same time, which no
4468 kernel needs to do. Fortunately, the kernel defines this bit to
4469 be Altivec-register-large all the time, rather than trying to
4470 twiddle it based on the specific platform. */
4471 union {
4472 /* SPE vector registers. One extra for SPEFSCR. */
4473 uint32_t spe[33];
4474 /* Altivec vector registers. The packing of VSCR and VRSAVE
4475 varies depending on whether we're PPC64 or not: PPC64 splits
4476 them apart; PPC32 stuffs them together. */
4477#if defined(TARGET_PPC64)
malc3efa9a62009-07-18 13:10:12 +04004478#define QEMU_NVRREG 34
Nathan Froydbcd49332009-05-12 19:13:18 -07004479#else
malc3efa9a62009-07-18 13:10:12 +04004480#define QEMU_NVRREG 33
Nathan Froydbcd49332009-05-12 19:13:18 -07004481#endif
Anthony Liguoric227f092009-10-01 16:12:16 -05004482 ppc_avr_t altivec[QEMU_NVRREG];
malc3efa9a62009-07-18 13:10:12 +04004483#undef QEMU_NVRREG
Nathan Froydbcd49332009-05-12 19:13:18 -07004484 } mc_vregs __attribute__((__aligned__(16)));
4485};
4486
4487struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02004488 target_ulong tuc_flags;
4489 target_ulong tuc_link; /* struct ucontext __user * */
4490 struct target_sigaltstack tuc_stack;
Nathan Froydbcd49332009-05-12 19:13:18 -07004491#if !defined(TARGET_PPC64)
Aurelien Jarno60e99242010-03-29 02:12:51 +02004492 int32_t tuc_pad[7];
4493 target_ulong tuc_regs; /* struct mcontext __user *
Nathan Froydbcd49332009-05-12 19:13:18 -07004494 points to uc_mcontext field */
4495#endif
Aurelien Jarno60e99242010-03-29 02:12:51 +02004496 target_sigset_t tuc_sigmask;
Nathan Froydbcd49332009-05-12 19:13:18 -07004497#if defined(TARGET_PPC64)
Anthony Liguoric227f092009-10-01 16:12:16 -05004498 target_sigset_t unused[15]; /* Allow for uc_sigmask growth */
Aurelien Jarno60e99242010-03-29 02:12:51 +02004499 struct target_sigcontext tuc_mcontext;
Nathan Froydbcd49332009-05-12 19:13:18 -07004500#else
Aurelien Jarno60e99242010-03-29 02:12:51 +02004501 int32_t tuc_maskext[30];
4502 int32_t tuc_pad2[3];
4503 struct target_mcontext tuc_mcontext;
Nathan Froydbcd49332009-05-12 19:13:18 -07004504#endif
4505};
4506
4507/* See arch/powerpc/kernel/signal_32.c. */
4508struct target_sigframe {
4509 struct target_sigcontext sctx;
4510 struct target_mcontext mctx;
4511 int32_t abigap[56];
4512};
4513
4514struct target_rt_sigframe {
4515 struct target_siginfo info;
4516 struct target_ucontext uc;
4517 int32_t abigap[56];
4518};
4519
4520/* We use the mc_pad field for the signal return trampoline. */
4521#define tramp mc_pad
4522
4523/* See arch/powerpc/kernel/signal.c. */
4524static target_ulong get_sigframe(struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01004525 CPUPPCState *env,
Nathan Froydbcd49332009-05-12 19:13:18 -07004526 int frame_size)
4527{
4528 target_ulong oldsp, newsp;
4529
4530 oldsp = env->gpr[1];
4531
4532 if ((ka->sa_flags & TARGET_SA_ONSTACK) &&
Alex Barcelo32a20032012-02-09 23:55:46 +00004533 (sas_ss_flags(oldsp) == 0)) {
Nathan Froydbcd49332009-05-12 19:13:18 -07004534 oldsp = (target_sigaltstack_used.ss_sp
4535 + target_sigaltstack_used.ss_size);
4536 }
4537
4538 newsp = (oldsp - frame_size) & ~0xFUL;
4539
4540 return newsp;
4541}
4542
Andreas Färber05390242012-02-25 03:37:53 +01004543static int save_user_regs(CPUPPCState *env, struct target_mcontext *frame,
Nathan Froydbcd49332009-05-12 19:13:18 -07004544 int sigret)
4545{
4546 target_ulong msr = env->msr;
4547 int i;
4548 target_ulong ccr = 0;
4549
4550 /* In general, the kernel attempts to be intelligent about what it
4551 needs to save for Altivec/FP/SPE registers. We don't care that
4552 much, so we just go ahead and save everything. */
4553
4554 /* Save general registers. */
4555 for (i = 0; i < ARRAY_SIZE(env->gpr); i++) {
4556 if (__put_user(env->gpr[i], &frame->mc_gregs[i])) {
4557 return 1;
4558 }
4559 }
4560 if (__put_user(env->nip, &frame->mc_gregs[TARGET_PT_NIP])
4561 || __put_user(env->ctr, &frame->mc_gregs[TARGET_PT_CTR])
4562 || __put_user(env->lr, &frame->mc_gregs[TARGET_PT_LNK])
4563 || __put_user(env->xer, &frame->mc_gregs[TARGET_PT_XER]))
4564 return 1;
4565
4566 for (i = 0; i < ARRAY_SIZE(env->crf); i++) {
4567 ccr |= env->crf[i] << (32 - ((i + 1) * 4));
4568 }
4569 if (__put_user(ccr, &frame->mc_gregs[TARGET_PT_CCR]))
4570 return 1;
4571
4572 /* Save Altivec registers if necessary. */
4573 if (env->insns_flags & PPC_ALTIVEC) {
4574 for (i = 0; i < ARRAY_SIZE(env->avr); i++) {
Anthony Liguoric227f092009-10-01 16:12:16 -05004575 ppc_avr_t *avr = &env->avr[i];
4576 ppc_avr_t *vreg = &frame->mc_vregs.altivec[i];
Nathan Froydbcd49332009-05-12 19:13:18 -07004577
4578 if (__put_user(avr->u64[0], &vreg->u64[0]) ||
4579 __put_user(avr->u64[1], &vreg->u64[1])) {
4580 return 1;
4581 }
4582 }
4583 /* Set MSR_VR in the saved MSR value to indicate that
4584 frame->mc_vregs contains valid data. */
4585 msr |= MSR_VR;
4586 if (__put_user((uint32_t)env->spr[SPR_VRSAVE],
4587 &frame->mc_vregs.altivec[32].u32[3]))
4588 return 1;
4589 }
4590
4591 /* Save floating point registers. */
4592 if (env->insns_flags & PPC_FLOAT) {
4593 for (i = 0; i < ARRAY_SIZE(env->fpr); i++) {
4594 if (__put_user(env->fpr[i], &frame->mc_fregs[i])) {
4595 return 1;
4596 }
4597 }
4598 if (__put_user((uint64_t) env->fpscr, &frame->mc_fregs[32]))
4599 return 1;
4600 }
4601
4602 /* Save SPE registers. The kernel only saves the high half. */
4603 if (env->insns_flags & PPC_SPE) {
4604#if defined(TARGET_PPC64)
4605 for (i = 0; i < ARRAY_SIZE(env->gpr); i++) {
4606 if (__put_user(env->gpr[i] >> 32, &frame->mc_vregs.spe[i])) {
4607 return 1;
4608 }
4609 }
4610#else
4611 for (i = 0; i < ARRAY_SIZE(env->gprh); i++) {
4612 if (__put_user(env->gprh[i], &frame->mc_vregs.spe[i])) {
4613 return 1;
4614 }
4615 }
4616#endif
4617 /* Set MSR_SPE in the saved MSR value to indicate that
4618 frame->mc_vregs contains valid data. */
4619 msr |= MSR_SPE;
4620 if (__put_user(env->spe_fscr, &frame->mc_vregs.spe[32]))
4621 return 1;
4622 }
4623
4624 /* Store MSR. */
4625 if (__put_user(msr, &frame->mc_gregs[TARGET_PT_MSR]))
4626 return 1;
4627
4628 /* Set up the sigreturn trampoline: li r0,sigret; sc. */
4629 if (sigret) {
4630 if (__put_user(0x38000000UL | sigret, &frame->tramp[0]) ||
4631 __put_user(0x44000002UL, &frame->tramp[1])) {
4632 return 1;
4633 }
4634 }
4635
4636 return 0;
4637}
4638
Andreas Färber05390242012-02-25 03:37:53 +01004639static int restore_user_regs(CPUPPCState *env,
Nathan Froydbcd49332009-05-12 19:13:18 -07004640 struct target_mcontext *frame, int sig)
4641{
4642 target_ulong save_r2 = 0;
4643 target_ulong msr;
4644 target_ulong ccr;
4645
4646 int i;
4647
4648 if (!sig) {
4649 save_r2 = env->gpr[2];
4650 }
4651
4652 /* Restore general registers. */
4653 for (i = 0; i < ARRAY_SIZE(env->gpr); i++) {
4654 if (__get_user(env->gpr[i], &frame->mc_gregs[i])) {
4655 return 1;
4656 }
4657 }
4658 if (__get_user(env->nip, &frame->mc_gregs[TARGET_PT_NIP])
4659 || __get_user(env->ctr, &frame->mc_gregs[TARGET_PT_CTR])
4660 || __get_user(env->lr, &frame->mc_gregs[TARGET_PT_LNK])
4661 || __get_user(env->xer, &frame->mc_gregs[TARGET_PT_XER]))
4662 return 1;
4663 if (__get_user(ccr, &frame->mc_gregs[TARGET_PT_CCR]))
4664 return 1;
4665
4666 for (i = 0; i < ARRAY_SIZE(env->crf); i++) {
4667 env->crf[i] = (ccr >> (32 - ((i + 1) * 4))) & 0xf;
4668 }
4669
4670 if (!sig) {
4671 env->gpr[2] = save_r2;
4672 }
4673 /* Restore MSR. */
4674 if (__get_user(msr, &frame->mc_gregs[TARGET_PT_MSR]))
4675 return 1;
4676
4677 /* If doing signal return, restore the previous little-endian mode. */
4678 if (sig)
4679 env->msr = (env->msr & ~MSR_LE) | (msr & MSR_LE);
4680
4681 /* Restore Altivec registers if necessary. */
4682 if (env->insns_flags & PPC_ALTIVEC) {
4683 for (i = 0; i < ARRAY_SIZE(env->avr); i++) {
Anthony Liguoric227f092009-10-01 16:12:16 -05004684 ppc_avr_t *avr = &env->avr[i];
4685 ppc_avr_t *vreg = &frame->mc_vregs.altivec[i];
Nathan Froydbcd49332009-05-12 19:13:18 -07004686
4687 if (__get_user(avr->u64[0], &vreg->u64[0]) ||
4688 __get_user(avr->u64[1], &vreg->u64[1])) {
4689 return 1;
4690 }
4691 }
4692 /* Set MSR_VEC in the saved MSR value to indicate that
4693 frame->mc_vregs contains valid data. */
4694 if (__get_user(env->spr[SPR_VRSAVE],
4695 (target_ulong *)(&frame->mc_vregs.altivec[32].u32[3])))
4696 return 1;
4697 }
4698
4699 /* Restore floating point registers. */
4700 if (env->insns_flags & PPC_FLOAT) {
4701 uint64_t fpscr;
4702 for (i = 0; i < ARRAY_SIZE(env->fpr); i++) {
4703 if (__get_user(env->fpr[i], &frame->mc_fregs[i])) {
4704 return 1;
4705 }
4706 }
4707 if (__get_user(fpscr, &frame->mc_fregs[32]))
4708 return 1;
4709 env->fpscr = (uint32_t) fpscr;
4710 }
4711
4712 /* Save SPE registers. The kernel only saves the high half. */
4713 if (env->insns_flags & PPC_SPE) {
4714#if defined(TARGET_PPC64)
4715 for (i = 0; i < ARRAY_SIZE(env->gpr); i++) {
4716 uint32_t hi;
4717
4718 if (__get_user(hi, &frame->mc_vregs.spe[i])) {
4719 return 1;
4720 }
4721 env->gpr[i] = ((uint64_t)hi << 32) | ((uint32_t) env->gpr[i]);
4722 }
4723#else
4724 for (i = 0; i < ARRAY_SIZE(env->gprh); i++) {
4725 if (__get_user(env->gprh[i], &frame->mc_vregs.spe[i])) {
4726 return 1;
4727 }
4728 }
4729#endif
4730 if (__get_user(env->spe_fscr, &frame->mc_vregs.spe[32]))
4731 return 1;
4732 }
4733
4734 return 0;
4735}
4736
4737static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01004738 target_sigset_t *set, CPUPPCState *env)
Nathan Froydbcd49332009-05-12 19:13:18 -07004739{
4740 struct target_sigframe *frame;
4741 struct target_sigcontext *sc;
4742 target_ulong frame_addr, newsp;
4743 int err = 0;
4744 int signal;
4745
4746 frame_addr = get_sigframe(ka, env, sizeof(*frame));
4747 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 1))
4748 goto sigsegv;
4749 sc = &frame->sctx;
4750
4751 signal = current_exec_domain_sig(sig);
4752
Riku Voipio1d8b5122014-04-23 10:26:05 +03004753 __put_user(ka->_sa_handler, &sc->handler);
4754 __put_user(set->sig[0], &sc->oldmask);
Nathan Froydbcd49332009-05-12 19:13:18 -07004755#if defined(TARGET_PPC64)
Riku Voipio1d8b5122014-04-23 10:26:05 +03004756 __put_user(set->sig[0] >> 32, &sc->_unused[3]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004757#else
Riku Voipio1d8b5122014-04-23 10:26:05 +03004758 __put_user(set->sig[1], &sc->_unused[3]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004759#endif
Riku Voipio1d8b5122014-04-23 10:26:05 +03004760 __put_user(h2g(&frame->mctx), &sc->regs);
4761 __put_user(sig, &sc->signal);
Nathan Froydbcd49332009-05-12 19:13:18 -07004762
4763 /* Save user regs. */
4764 err |= save_user_regs(env, &frame->mctx, TARGET_NR_sigreturn);
4765
4766 /* The kernel checks for the presence of a VDSO here. We don't
4767 emulate a vdso, so use a sigreturn system call. */
4768 env->lr = (target_ulong) h2g(frame->mctx.tramp);
4769
4770 /* Turn off all fp exceptions. */
4771 env->fpscr = 0;
4772
4773 /* Create a stack frame for the caller of the handler. */
4774 newsp = frame_addr - SIGNAL_FRAMESIZE;
Samuel Seaybeb526b2013-01-02 10:53:46 +00004775 err |= put_user(env->gpr[1], newsp, target_ulong);
Nathan Froydbcd49332009-05-12 19:13:18 -07004776
4777 if (err)
4778 goto sigsegv;
4779
4780 /* Set up registers for signal handler. */
4781 env->gpr[1] = newsp;
4782 env->gpr[3] = signal;
Samuel Seay61993a62013-01-04 14:35:48 +00004783 env->gpr[4] = frame_addr + offsetof(struct target_sigframe, sctx);
Nathan Froydbcd49332009-05-12 19:13:18 -07004784 env->nip = (target_ulong) ka->_sa_handler;
4785 /* Signal handlers are entered in big-endian mode. */
4786 env->msr &= ~MSR_LE;
4787
4788 unlock_user_struct(frame, frame_addr, 1);
4789 return;
4790
4791sigsegv:
4792 unlock_user_struct(frame, frame_addr, 1);
Blue Swirleeacee42012-06-03 16:35:32 +00004793 qemu_log("segfaulting from setup_frame\n");
Riku Voipio66393fb2009-12-04 15:16:32 +02004794 force_sig(TARGET_SIGSEGV);
Nathan Froydbcd49332009-05-12 19:13:18 -07004795}
4796
4797static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05004798 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01004799 target_sigset_t *set, CPUPPCState *env)
Nathan Froydbcd49332009-05-12 19:13:18 -07004800{
4801 struct target_rt_sigframe *rt_sf;
4802 struct target_mcontext *frame;
4803 target_ulong rt_sf_addr, newsp = 0;
4804 int i, err = 0;
4805 int signal;
4806
4807 rt_sf_addr = get_sigframe(ka, env, sizeof(*rt_sf));
4808 if (!lock_user_struct(VERIFY_WRITE, rt_sf, rt_sf_addr, 1))
4809 goto sigsegv;
4810
4811 signal = current_exec_domain_sig(sig);
4812
Riku Voipiob0fd8d12014-04-23 10:46:13 +03004813 copy_siginfo_to_user(&rt_sf->info, info);
Nathan Froydbcd49332009-05-12 19:13:18 -07004814
Riku Voipio1d8b5122014-04-23 10:26:05 +03004815 __put_user(0, &rt_sf->uc.tuc_flags);
4816 __put_user(0, &rt_sf->uc.tuc_link);
4817 __put_user((target_ulong)target_sigaltstack_used.ss_sp,
4818 &rt_sf->uc.tuc_stack.ss_sp);
4819 __put_user(sas_ss_flags(env->gpr[1]),
4820 &rt_sf->uc.tuc_stack.ss_flags);
4821 __put_user(target_sigaltstack_used.ss_size,
4822 &rt_sf->uc.tuc_stack.ss_size);
4823 __put_user(h2g (&rt_sf->uc.tuc_mcontext),
4824 &rt_sf->uc.tuc_regs);
Nathan Froydbcd49332009-05-12 19:13:18 -07004825 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03004826 __put_user(set->sig[i], &rt_sf->uc.tuc_sigmask.sig[i]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004827 }
4828
Aurelien Jarno60e99242010-03-29 02:12:51 +02004829 frame = &rt_sf->uc.tuc_mcontext;
Nathan Froydbcd49332009-05-12 19:13:18 -07004830 err |= save_user_regs(env, frame, TARGET_NR_rt_sigreturn);
4831
4832 /* The kernel checks for the presence of a VDSO here. We don't
4833 emulate a vdso, so use a sigreturn system call. */
4834 env->lr = (target_ulong) h2g(frame->tramp);
4835
4836 /* Turn off all fp exceptions. */
4837 env->fpscr = 0;
4838
4839 /* Create a stack frame for the caller of the handler. */
4840 newsp = rt_sf_addr - (SIGNAL_FRAMESIZE + 16);
Riku Voipio1d8b5122014-04-23 10:26:05 +03004841 __put_user(env->gpr[1], (target_ulong *)(uintptr_t) newsp);
Nathan Froydbcd49332009-05-12 19:13:18 -07004842
4843 if (err)
4844 goto sigsegv;
4845
4846 /* Set up registers for signal handler. */
4847 env->gpr[1] = newsp;
4848 env->gpr[3] = (target_ulong) signal;
4849 env->gpr[4] = (target_ulong) h2g(&rt_sf->info);
4850 env->gpr[5] = (target_ulong) h2g(&rt_sf->uc);
4851 env->gpr[6] = (target_ulong) h2g(rt_sf);
4852 env->nip = (target_ulong) ka->_sa_handler;
4853 /* Signal handlers are entered in big-endian mode. */
4854 env->msr &= ~MSR_LE;
4855
4856 unlock_user_struct(rt_sf, rt_sf_addr, 1);
4857 return;
4858
4859sigsegv:
4860 unlock_user_struct(rt_sf, rt_sf_addr, 1);
Blue Swirleeacee42012-06-03 16:35:32 +00004861 qemu_log("segfaulting from setup_rt_frame\n");
Riku Voipio66393fb2009-12-04 15:16:32 +02004862 force_sig(TARGET_SIGSEGV);
Nathan Froydbcd49332009-05-12 19:13:18 -07004863
4864}
4865
Andreas Färber05390242012-02-25 03:37:53 +01004866long do_sigreturn(CPUPPCState *env)
Nathan Froydbcd49332009-05-12 19:13:18 -07004867{
4868 struct target_sigcontext *sc = NULL;
4869 struct target_mcontext *sr = NULL;
Peter Maydellb04636f2013-07-29 12:00:31 +01004870 target_ulong sr_addr = 0, sc_addr;
Nathan Froydbcd49332009-05-12 19:13:18 -07004871 sigset_t blocked;
Anthony Liguoric227f092009-10-01 16:12:16 -05004872 target_sigset_t set;
Nathan Froydbcd49332009-05-12 19:13:18 -07004873
4874 sc_addr = env->gpr[1] + SIGNAL_FRAMESIZE;
4875 if (!lock_user_struct(VERIFY_READ, sc, sc_addr, 1))
4876 goto sigsegv;
4877
4878#if defined(TARGET_PPC64)
4879 set.sig[0] = sc->oldmask + ((long)(sc->_unused[3]) << 32);
4880#else
4881 if(__get_user(set.sig[0], &sc->oldmask) ||
4882 __get_user(set.sig[1], &sc->_unused[3]))
4883 goto sigsegv;
4884#endif
4885 target_to_host_sigset_internal(&blocked, &set);
Alex Barcelo1c275922014-03-14 14:36:55 +00004886 do_sigprocmask(SIG_SETMASK, &blocked, NULL);
Nathan Froydbcd49332009-05-12 19:13:18 -07004887
4888 if (__get_user(sr_addr, &sc->regs))
4889 goto sigsegv;
4890 if (!lock_user_struct(VERIFY_READ, sr, sr_addr, 1))
4891 goto sigsegv;
4892 if (restore_user_regs(env, sr, 1))
4893 goto sigsegv;
4894
4895 unlock_user_struct(sr, sr_addr, 1);
4896 unlock_user_struct(sc, sc_addr, 1);
4897 return -TARGET_QEMU_ESIGRETURN;
4898
4899sigsegv:
4900 unlock_user_struct(sr, sr_addr, 1);
4901 unlock_user_struct(sc, sc_addr, 1);
Blue Swirleeacee42012-06-03 16:35:32 +00004902 qemu_log("segfaulting from do_sigreturn\n");
Riku Voipio66393fb2009-12-04 15:16:32 +02004903 force_sig(TARGET_SIGSEGV);
Nathan Froydbcd49332009-05-12 19:13:18 -07004904 return 0;
4905}
4906
4907/* See arch/powerpc/kernel/signal_32.c. */
Andreas Färber05390242012-02-25 03:37:53 +01004908static int do_setcontext(struct target_ucontext *ucp, CPUPPCState *env, int sig)
Nathan Froydbcd49332009-05-12 19:13:18 -07004909{
4910 struct target_mcontext *mcp;
4911 target_ulong mcp_addr;
4912 sigset_t blocked;
Anthony Liguoric227f092009-10-01 16:12:16 -05004913 target_sigset_t set;
Nathan Froydbcd49332009-05-12 19:13:18 -07004914
Aurelien Jarno60e99242010-03-29 02:12:51 +02004915 if (copy_from_user(&set, h2g(ucp) + offsetof(struct target_ucontext, tuc_sigmask),
Nathan Froydbcd49332009-05-12 19:13:18 -07004916 sizeof (set)))
4917 return 1;
4918
4919#if defined(TARGET_PPC64)
4920 fprintf (stderr, "do_setcontext: not implemented\n");
4921 return 0;
4922#else
Aurelien Jarno60e99242010-03-29 02:12:51 +02004923 if (__get_user(mcp_addr, &ucp->tuc_regs))
Nathan Froydbcd49332009-05-12 19:13:18 -07004924 return 1;
4925
4926 if (!lock_user_struct(VERIFY_READ, mcp, mcp_addr, 1))
4927 return 1;
4928
4929 target_to_host_sigset_internal(&blocked, &set);
Alex Barcelo1c275922014-03-14 14:36:55 +00004930 do_sigprocmask(SIG_SETMASK, &blocked, NULL);
Nathan Froydbcd49332009-05-12 19:13:18 -07004931 if (restore_user_regs(env, mcp, sig))
4932 goto sigsegv;
4933
4934 unlock_user_struct(mcp, mcp_addr, 1);
4935 return 0;
4936
4937sigsegv:
4938 unlock_user_struct(mcp, mcp_addr, 1);
4939 return 1;
4940#endif
4941}
4942
Andreas Färber05390242012-02-25 03:37:53 +01004943long do_rt_sigreturn(CPUPPCState *env)
Nathan Froydbcd49332009-05-12 19:13:18 -07004944{
4945 struct target_rt_sigframe *rt_sf = NULL;
4946 target_ulong rt_sf_addr;
4947
4948 rt_sf_addr = env->gpr[1] + SIGNAL_FRAMESIZE + 16;
4949 if (!lock_user_struct(VERIFY_READ, rt_sf, rt_sf_addr, 1))
4950 goto sigsegv;
4951
4952 if (do_setcontext(&rt_sf->uc, env, 1))
4953 goto sigsegv;
4954
4955 do_sigaltstack(rt_sf_addr
Aurelien Jarno60e99242010-03-29 02:12:51 +02004956 + offsetof(struct target_rt_sigframe, uc.tuc_stack),
Nathan Froydbcd49332009-05-12 19:13:18 -07004957 0, env->gpr[1]);
4958
4959 unlock_user_struct(rt_sf, rt_sf_addr, 1);
4960 return -TARGET_QEMU_ESIGRETURN;
4961
4962sigsegv:
4963 unlock_user_struct(rt_sf, rt_sf_addr, 1);
Blue Swirleeacee42012-06-03 16:35:32 +00004964 qemu_log("segfaulting from do_rt_sigreturn\n");
Riku Voipio66393fb2009-12-04 15:16:32 +02004965 force_sig(TARGET_SIGSEGV);
Nathan Froydbcd49332009-05-12 19:13:18 -07004966 return 0;
4967}
4968
Laurent Vivier492a8742009-08-03 16:12:17 +02004969#elif defined(TARGET_M68K)
4970
4971struct target_sigcontext {
4972 abi_ulong sc_mask;
4973 abi_ulong sc_usp;
4974 abi_ulong sc_d0;
4975 abi_ulong sc_d1;
4976 abi_ulong sc_a0;
4977 abi_ulong sc_a1;
4978 unsigned short sc_sr;
4979 abi_ulong sc_pc;
4980};
4981
4982struct target_sigframe
4983{
4984 abi_ulong pretcode;
4985 int sig;
4986 int code;
4987 abi_ulong psc;
4988 char retcode[8];
4989 abi_ulong extramask[TARGET_NSIG_WORDS-1];
4990 struct target_sigcontext sc;
4991};
Laurent Vivier71811552009-08-03 16:12:18 +02004992
Anthony Liguoric227f092009-10-01 16:12:16 -05004993typedef int target_greg_t;
Laurent Vivier71811552009-08-03 16:12:18 +02004994#define TARGET_NGREG 18
Anthony Liguoric227f092009-10-01 16:12:16 -05004995typedef target_greg_t target_gregset_t[TARGET_NGREG];
Laurent Vivier71811552009-08-03 16:12:18 +02004996
4997typedef struct target_fpregset {
4998 int f_fpcntl[3];
4999 int f_fpregs[8*3];
Anthony Liguoric227f092009-10-01 16:12:16 -05005000} target_fpregset_t;
Laurent Vivier71811552009-08-03 16:12:18 +02005001
5002struct target_mcontext {
5003 int version;
Anthony Liguoric227f092009-10-01 16:12:16 -05005004 target_gregset_t gregs;
5005 target_fpregset_t fpregs;
Laurent Vivier71811552009-08-03 16:12:18 +02005006};
5007
5008#define TARGET_MCONTEXT_VERSION 2
5009
5010struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02005011 abi_ulong tuc_flags;
5012 abi_ulong tuc_link;
5013 target_stack_t tuc_stack;
5014 struct target_mcontext tuc_mcontext;
5015 abi_long tuc_filler[80];
5016 target_sigset_t tuc_sigmask;
Laurent Vivier71811552009-08-03 16:12:18 +02005017};
5018
5019struct target_rt_sigframe
5020{
5021 abi_ulong pretcode;
5022 int sig;
5023 abi_ulong pinfo;
5024 abi_ulong puc;
5025 char retcode[8];
5026 struct target_siginfo info;
5027 struct target_ucontext uc;
5028};
Laurent Vivier492a8742009-08-03 16:12:17 +02005029
Riku Voipio41ecc722014-04-23 11:01:00 +03005030static void setup_sigcontext(struct target_sigcontext *sc, CPUM68KState *env,
5031 abi_ulong mask)
Laurent Vivier492a8742009-08-03 16:12:17 +02005032{
Riku Voipio1d8b5122014-04-23 10:26:05 +03005033 __put_user(mask, &sc->sc_mask);
5034 __put_user(env->aregs[7], &sc->sc_usp);
5035 __put_user(env->dregs[0], &sc->sc_d0);
5036 __put_user(env->dregs[1], &sc->sc_d1);
5037 __put_user(env->aregs[0], &sc->sc_a0);
5038 __put_user(env->aregs[1], &sc->sc_a1);
5039 __put_user(env->sr, &sc->sc_sr);
5040 __put_user(env->pc, &sc->sc_pc);
Laurent Vivier492a8742009-08-03 16:12:17 +02005041}
5042
Riku Voipio016d2e12014-04-23 11:19:48 +03005043static void
Andreas Färber05390242012-02-25 03:37:53 +01005044restore_sigcontext(CPUM68KState *env, struct target_sigcontext *sc, int *pd0)
Laurent Vivier492a8742009-08-03 16:12:17 +02005045{
Laurent Vivier492a8742009-08-03 16:12:17 +02005046 int temp;
5047
Riku Voipio1d8b5122014-04-23 10:26:05 +03005048 __get_user(env->aregs[7], &sc->sc_usp);
5049 __get_user(env->dregs[1], &sc->sc_d1);
5050 __get_user(env->aregs[0], &sc->sc_a0);
5051 __get_user(env->aregs[1], &sc->sc_a1);
5052 __get_user(env->pc, &sc->sc_pc);
5053 __get_user(temp, &sc->sc_sr);
Laurent Vivier492a8742009-08-03 16:12:17 +02005054 env->sr = (env->sr & 0xff00) | (temp & 0xff);
5055
5056 *pd0 = tswapl(sc->sc_d0);
Laurent Vivier492a8742009-08-03 16:12:17 +02005057}
5058
5059/*
5060 * Determine which stack to use..
5061 */
5062static inline abi_ulong
Andreas Färber05390242012-02-25 03:37:53 +01005063get_sigframe(struct target_sigaction *ka, CPUM68KState *regs,
5064 size_t frame_size)
Laurent Vivier492a8742009-08-03 16:12:17 +02005065{
5066 unsigned long sp;
5067
5068 sp = regs->aregs[7];
5069
5070 /* This is the X/Open sanctioned signal stack switching. */
5071 if ((ka->sa_flags & TARGET_SA_ONSTACK) && (sas_ss_flags (sp) == 0)) {
5072 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
5073 }
5074
5075 return ((sp - frame_size) & -8UL);
5076}
5077
5078static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01005079 target_sigset_t *set, CPUM68KState *env)
Laurent Vivier492a8742009-08-03 16:12:17 +02005080{
5081 struct target_sigframe *frame;
5082 abi_ulong frame_addr;
5083 abi_ulong retcode_addr;
5084 abi_ulong sc_addr;
5085 int err = 0;
5086 int i;
5087
5088 frame_addr = get_sigframe(ka, env, sizeof *frame);
5089 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
5090 goto give_sigsegv;
5091
Riku Voipio1d8b5122014-04-23 10:26:05 +03005092 __put_user(sig, &frame->sig);
Laurent Vivier492a8742009-08-03 16:12:17 +02005093
5094 sc_addr = frame_addr + offsetof(struct target_sigframe, sc);
Riku Voipio1d8b5122014-04-23 10:26:05 +03005095 __put_user(sc_addr, &frame->psc);
Laurent Vivier492a8742009-08-03 16:12:17 +02005096
Riku Voipio41ecc722014-04-23 11:01:00 +03005097 setup_sigcontext(&frame->sc, env, set->sig[0]);
Laurent Vivier492a8742009-08-03 16:12:17 +02005098
5099 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
5100 if (__put_user(set->sig[i], &frame->extramask[i - 1]))
5101 goto give_sigsegv;
5102 }
5103
5104 /* Set up to return from userspace. */
5105
5106 retcode_addr = frame_addr + offsetof(struct target_sigframe, retcode);
Riku Voipio1d8b5122014-04-23 10:26:05 +03005107 __put_user(retcode_addr, &frame->pretcode);
Laurent Vivier492a8742009-08-03 16:12:17 +02005108
5109 /* moveq #,d0; trap #0 */
5110
Riku Voipio1d8b5122014-04-23 10:26:05 +03005111 __put_user(0x70004e40 + (TARGET_NR_sigreturn << 16),
Laurent Vivier492a8742009-08-03 16:12:17 +02005112 (long *)(frame->retcode));
5113
5114 if (err)
5115 goto give_sigsegv;
5116
5117 /* Set up to return from userspace */
5118
5119 env->aregs[7] = frame_addr;
5120 env->pc = ka->_sa_handler;
5121
5122 unlock_user_struct(frame, frame_addr, 1);
5123 return;
5124
5125give_sigsegv:
5126 unlock_user_struct(frame, frame_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02005127 force_sig(TARGET_SIGSEGV);
Laurent Vivier492a8742009-08-03 16:12:17 +02005128}
5129
Laurent Vivier71811552009-08-03 16:12:18 +02005130static inline int target_rt_setup_ucontext(struct target_ucontext *uc,
Andreas Färber05390242012-02-25 03:37:53 +01005131 CPUM68KState *env)
Laurent Vivier71811552009-08-03 16:12:18 +02005132{
Aurelien Jarno60e99242010-03-29 02:12:51 +02005133 target_greg_t *gregs = uc->tuc_mcontext.gregs;
Laurent Vivier71811552009-08-03 16:12:18 +02005134
Riku Voipio1d8b5122014-04-23 10:26:05 +03005135 __put_user(TARGET_MCONTEXT_VERSION, &uc->tuc_mcontext.version);
5136 __put_user(env->dregs[0], &gregs[0]);
5137 __put_user(env->dregs[1], &gregs[1]);
5138 __put_user(env->dregs[2], &gregs[2]);
5139 __put_user(env->dregs[3], &gregs[3]);
5140 __put_user(env->dregs[4], &gregs[4]);
5141 __put_user(env->dregs[5], &gregs[5]);
5142 __put_user(env->dregs[6], &gregs[6]);
5143 __put_user(env->dregs[7], &gregs[7]);
5144 __put_user(env->aregs[0], &gregs[8]);
5145 __put_user(env->aregs[1], &gregs[9]);
5146 __put_user(env->aregs[2], &gregs[10]);
5147 __put_user(env->aregs[3], &gregs[11]);
5148 __put_user(env->aregs[4], &gregs[12]);
5149 __put_user(env->aregs[5], &gregs[13]);
5150 __put_user(env->aregs[6], &gregs[14]);
5151 __put_user(env->aregs[7], &gregs[15]);
5152 __put_user(env->pc, &gregs[16]);
5153 __put_user(env->sr, &gregs[17]);
Laurent Vivier71811552009-08-03 16:12:18 +02005154
Riku Voipio1d8b5122014-04-23 10:26:05 +03005155 return 0;
Laurent Vivier71811552009-08-03 16:12:18 +02005156}
5157
Andreas Färber05390242012-02-25 03:37:53 +01005158static inline int target_rt_restore_ucontext(CPUM68KState *env,
Laurent Vivier71811552009-08-03 16:12:18 +02005159 struct target_ucontext *uc,
5160 int *pd0)
5161{
5162 int temp;
Aurelien Jarno60e99242010-03-29 02:12:51 +02005163 target_greg_t *gregs = uc->tuc_mcontext.gregs;
Laurent Vivier71811552009-08-03 16:12:18 +02005164
Riku Voipio1d8b5122014-04-23 10:26:05 +03005165 __get_user(temp, &uc->tuc_mcontext.version);
Laurent Vivier71811552009-08-03 16:12:18 +02005166 if (temp != TARGET_MCONTEXT_VERSION)
5167 goto badframe;
5168
5169 /* restore passed registers */
Riku Voipio1d8b5122014-04-23 10:26:05 +03005170 __get_user(env->dregs[0], &gregs[0]);
5171 __get_user(env->dregs[1], &gregs[1]);
5172 __get_user(env->dregs[2], &gregs[2]);
5173 __get_user(env->dregs[3], &gregs[3]);
5174 __get_user(env->dregs[4], &gregs[4]);
5175 __get_user(env->dregs[5], &gregs[5]);
5176 __get_user(env->dregs[6], &gregs[6]);
5177 __get_user(env->dregs[7], &gregs[7]);
5178 __get_user(env->aregs[0], &gregs[8]);
5179 __get_user(env->aregs[1], &gregs[9]);
5180 __get_user(env->aregs[2], &gregs[10]);
5181 __get_user(env->aregs[3], &gregs[11]);
5182 __get_user(env->aregs[4], &gregs[12]);
5183 __get_user(env->aregs[5], &gregs[13]);
5184 __get_user(env->aregs[6], &gregs[14]);
5185 __get_user(env->aregs[7], &gregs[15]);
5186 __get_user(env->pc, &gregs[16]);
5187 __get_user(temp, &gregs[17]);
Laurent Vivier71811552009-08-03 16:12:18 +02005188 env->sr = (env->sr & 0xff00) | (temp & 0xff);
5189
5190 *pd0 = env->dregs[0];
Riku Voipio1d8b5122014-04-23 10:26:05 +03005191 return 0;
Laurent Vivier71811552009-08-03 16:12:18 +02005192
5193badframe:
5194 return 1;
5195}
5196
Laurent Vivier492a8742009-08-03 16:12:17 +02005197static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05005198 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01005199 target_sigset_t *set, CPUM68KState *env)
Laurent Vivier492a8742009-08-03 16:12:17 +02005200{
Laurent Vivier71811552009-08-03 16:12:18 +02005201 struct target_rt_sigframe *frame;
5202 abi_ulong frame_addr;
5203 abi_ulong retcode_addr;
5204 abi_ulong info_addr;
5205 abi_ulong uc_addr;
5206 int err = 0;
5207 int i;
5208
5209 frame_addr = get_sigframe(ka, env, sizeof *frame);
5210 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
5211 goto give_sigsegv;
5212
Riku Voipio1d8b5122014-04-23 10:26:05 +03005213 __put_user(sig, &frame->sig);
Laurent Vivier71811552009-08-03 16:12:18 +02005214
5215 info_addr = frame_addr + offsetof(struct target_rt_sigframe, info);
Riku Voipio1d8b5122014-04-23 10:26:05 +03005216 __put_user(info_addr, &frame->pinfo);
Laurent Vivier71811552009-08-03 16:12:18 +02005217
5218 uc_addr = frame_addr + offsetof(struct target_rt_sigframe, uc);
Riku Voipio1d8b5122014-04-23 10:26:05 +03005219 __put_user(uc_addr, &frame->puc);
Laurent Vivier71811552009-08-03 16:12:18 +02005220
Riku Voipiob0fd8d12014-04-23 10:46:13 +03005221 copy_siginfo_to_user(&frame->info, info);
Laurent Vivier71811552009-08-03 16:12:18 +02005222
5223 /* Create the ucontext */
5224
Riku Voipio1d8b5122014-04-23 10:26:05 +03005225 __put_user(0, &frame->uc.tuc_flags);
5226 __put_user(0, &frame->uc.tuc_link);
5227 __put_user(target_sigaltstack_used.ss_sp,
5228 &frame->uc.tuc_stack.ss_sp);
5229 __put_user(sas_ss_flags(env->aregs[7]),
5230 &frame->uc.tuc_stack.ss_flags);
5231 __put_user(target_sigaltstack_used.ss_size,
5232 &frame->uc.tuc_stack.ss_size);
Laurent Vivier71811552009-08-03 16:12:18 +02005233 err |= target_rt_setup_ucontext(&frame->uc, env);
5234
5235 if (err)
5236 goto give_sigsegv;
5237
5238 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
Aurelien Jarno60e99242010-03-29 02:12:51 +02005239 if (__put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]))
Laurent Vivier71811552009-08-03 16:12:18 +02005240 goto give_sigsegv;
5241 }
5242
5243 /* Set up to return from userspace. */
5244
5245 retcode_addr = frame_addr + offsetof(struct target_sigframe, retcode);
Riku Voipio1d8b5122014-04-23 10:26:05 +03005246 __put_user(retcode_addr, &frame->pretcode);
Laurent Vivier71811552009-08-03 16:12:18 +02005247
5248 /* moveq #,d0; notb d0; trap #0 */
5249
Riku Voipio1d8b5122014-04-23 10:26:05 +03005250 __put_user(0x70004600 + ((TARGET_NR_rt_sigreturn ^ 0xff) << 16),
5251 (long *)(frame->retcode + 0));
5252 __put_user(0x4e40, (short *)(frame->retcode + 4));
Laurent Vivier71811552009-08-03 16:12:18 +02005253
5254 if (err)
5255 goto give_sigsegv;
5256
5257 /* Set up to return from userspace */
5258
5259 env->aregs[7] = frame_addr;
5260 env->pc = ka->_sa_handler;
5261
5262 unlock_user_struct(frame, frame_addr, 1);
5263 return;
5264
5265give_sigsegv:
5266 unlock_user_struct(frame, frame_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02005267 force_sig(TARGET_SIGSEGV);
Laurent Vivier492a8742009-08-03 16:12:17 +02005268}
5269
Andreas Färber05390242012-02-25 03:37:53 +01005270long do_sigreturn(CPUM68KState *env)
Laurent Vivier492a8742009-08-03 16:12:17 +02005271{
5272 struct target_sigframe *frame;
5273 abi_ulong frame_addr = env->aregs[7] - 4;
Anthony Liguoric227f092009-10-01 16:12:16 -05005274 target_sigset_t target_set;
Laurent Vivier492a8742009-08-03 16:12:17 +02005275 sigset_t set;
5276 int d0, i;
5277
5278 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
5279 goto badframe;
5280
5281 /* set blocked signals */
5282
5283 if (__get_user(target_set.sig[0], &frame->sc.sc_mask))
5284 goto badframe;
5285
5286 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
5287 if (__get_user(target_set.sig[i], &frame->extramask[i - 1]))
5288 goto badframe;
5289 }
5290
5291 target_to_host_sigset_internal(&set, &target_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00005292 do_sigprocmask(SIG_SETMASK, &set, NULL);
Laurent Vivier492a8742009-08-03 16:12:17 +02005293
5294 /* restore registers */
5295
Riku Voipio016d2e12014-04-23 11:19:48 +03005296 restore_sigcontext(env, &frame->sc, &d0);
Laurent Vivier492a8742009-08-03 16:12:17 +02005297
5298 unlock_user_struct(frame, frame_addr, 0);
5299 return d0;
5300
5301badframe:
5302 unlock_user_struct(frame, frame_addr, 0);
5303 force_sig(TARGET_SIGSEGV);
5304 return 0;
5305}
5306
Andreas Färber05390242012-02-25 03:37:53 +01005307long do_rt_sigreturn(CPUM68KState *env)
Laurent Vivier492a8742009-08-03 16:12:17 +02005308{
Laurent Vivier71811552009-08-03 16:12:18 +02005309 struct target_rt_sigframe *frame;
5310 abi_ulong frame_addr = env->aregs[7] - 4;
Anthony Liguoric227f092009-10-01 16:12:16 -05005311 target_sigset_t target_set;
Laurent Vivier71811552009-08-03 16:12:18 +02005312 sigset_t set;
5313 int d0;
5314
5315 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
5316 goto badframe;
5317
5318 target_to_host_sigset_internal(&set, &target_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00005319 do_sigprocmask(SIG_SETMASK, &set, NULL);
Laurent Vivier71811552009-08-03 16:12:18 +02005320
5321 /* restore registers */
5322
5323 if (target_rt_restore_ucontext(env, &frame->uc, &d0))
5324 goto badframe;
5325
5326 if (do_sigaltstack(frame_addr +
Aurelien Jarno60e99242010-03-29 02:12:51 +02005327 offsetof(struct target_rt_sigframe, uc.tuc_stack),
Laurent Vivier71811552009-08-03 16:12:18 +02005328 0, get_sp_from_cpustate(env)) == -EFAULT)
5329 goto badframe;
5330
5331 unlock_user_struct(frame, frame_addr, 0);
5332 return d0;
5333
5334badframe:
5335 unlock_user_struct(frame, frame_addr, 0);
5336 force_sig(TARGET_SIGSEGV);
5337 return 0;
Laurent Vivier492a8742009-08-03 16:12:17 +02005338}
5339
Richard Henderson6049f4f2009-12-27 18:30:03 -08005340#elif defined(TARGET_ALPHA)
5341
5342struct target_sigcontext {
5343 abi_long sc_onstack;
5344 abi_long sc_mask;
5345 abi_long sc_pc;
5346 abi_long sc_ps;
5347 abi_long sc_regs[32];
5348 abi_long sc_ownedfp;
5349 abi_long sc_fpregs[32];
5350 abi_ulong sc_fpcr;
5351 abi_ulong sc_fp_control;
5352 abi_ulong sc_reserved1;
5353 abi_ulong sc_reserved2;
5354 abi_ulong sc_ssize;
5355 abi_ulong sc_sbase;
5356 abi_ulong sc_traparg_a0;
5357 abi_ulong sc_traparg_a1;
5358 abi_ulong sc_traparg_a2;
5359 abi_ulong sc_fp_trap_pc;
5360 abi_ulong sc_fp_trigger_sum;
5361 abi_ulong sc_fp_trigger_inst;
5362};
5363
5364struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02005365 abi_ulong tuc_flags;
5366 abi_ulong tuc_link;
5367 abi_ulong tuc_osf_sigmask;
5368 target_stack_t tuc_stack;
5369 struct target_sigcontext tuc_mcontext;
5370 target_sigset_t tuc_sigmask;
Richard Henderson6049f4f2009-12-27 18:30:03 -08005371};
5372
5373struct target_sigframe {
5374 struct target_sigcontext sc;
5375 unsigned int retcode[3];
5376};
5377
5378struct target_rt_sigframe {
5379 target_siginfo_t info;
5380 struct target_ucontext uc;
5381 unsigned int retcode[3];
5382};
5383
5384#define INSN_MOV_R30_R16 0x47fe0410
5385#define INSN_LDI_R0 0x201f0000
5386#define INSN_CALLSYS 0x00000083
5387
Riku Voipio41ecc722014-04-23 11:01:00 +03005388static void setup_sigcontext(struct target_sigcontext *sc, CPUAlphaState *env,
Richard Henderson6049f4f2009-12-27 18:30:03 -08005389 abi_ulong frame_addr, target_sigset_t *set)
5390{
Riku Voipio41ecc722014-04-23 11:01:00 +03005391 int i;
Richard Henderson6049f4f2009-12-27 18:30:03 -08005392
Riku Voipio1d8b5122014-04-23 10:26:05 +03005393 __put_user(on_sig_stack(frame_addr), &sc->sc_onstack);
5394 __put_user(set->sig[0], &sc->sc_mask);
5395 __put_user(env->pc, &sc->sc_pc);
5396 __put_user(8, &sc->sc_ps);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005397
5398 for (i = 0; i < 31; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03005399 __put_user(env->ir[i], &sc->sc_regs[i]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005400 }
Riku Voipio1d8b5122014-04-23 10:26:05 +03005401 __put_user(0, &sc->sc_regs[31]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005402
5403 for (i = 0; i < 31; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03005404 __put_user(env->fir[i], &sc->sc_fpregs[i]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005405 }
Riku Voipio1d8b5122014-04-23 10:26:05 +03005406 __put_user(0, &sc->sc_fpregs[31]);
5407 __put_user(cpu_alpha_load_fpcr(env), &sc->sc_fpcr);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005408
Riku Voipio1d8b5122014-04-23 10:26:05 +03005409 __put_user(0, &sc->sc_traparg_a0); /* FIXME */
5410 __put_user(0, &sc->sc_traparg_a1); /* FIXME */
5411 __put_user(0, &sc->sc_traparg_a2); /* FIXME */
Richard Henderson6049f4f2009-12-27 18:30:03 -08005412}
5413
Riku Voipio016d2e12014-04-23 11:19:48 +03005414static void restore_sigcontext(CPUAlphaState *env,
Andreas Färber05390242012-02-25 03:37:53 +01005415 struct target_sigcontext *sc)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005416{
5417 uint64_t fpcr;
Riku Voipio016d2e12014-04-23 11:19:48 +03005418 int i;
Richard Henderson6049f4f2009-12-27 18:30:03 -08005419
Riku Voipio1d8b5122014-04-23 10:26:05 +03005420 __get_user(env->pc, &sc->sc_pc);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005421
5422 for (i = 0; i < 31; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03005423 __get_user(env->ir[i], &sc->sc_regs[i]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005424 }
5425 for (i = 0; i < 31; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03005426 __get_user(env->fir[i], &sc->sc_fpregs[i]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005427 }
5428
Riku Voipio1d8b5122014-04-23 10:26:05 +03005429 __get_user(fpcr, &sc->sc_fpcr);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005430 cpu_alpha_store_fpcr(env, fpcr);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005431}
5432
5433static inline abi_ulong get_sigframe(struct target_sigaction *sa,
Andreas Färber05390242012-02-25 03:37:53 +01005434 CPUAlphaState *env,
5435 unsigned long framesize)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005436{
5437 abi_ulong sp = env->ir[IR_SP];
5438
5439 /* This is the X/Open sanctioned signal stack switching. */
5440 if ((sa->sa_flags & TARGET_SA_ONSTACK) != 0 && !sas_ss_flags(sp)) {
5441 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
5442 }
5443 return (sp - framesize) & -32;
5444}
5445
5446static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01005447 target_sigset_t *set, CPUAlphaState *env)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005448{
5449 abi_ulong frame_addr, r26;
5450 struct target_sigframe *frame;
5451 int err = 0;
5452
5453 frame_addr = get_sigframe(ka, env, sizeof(*frame));
5454 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
5455 goto give_sigsegv;
5456 }
5457
Riku Voipio41ecc722014-04-23 11:01:00 +03005458 setup_sigcontext(&frame->sc, env, frame_addr, set);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005459
5460 if (ka->sa_restorer) {
5461 r26 = ka->sa_restorer;
5462 } else {
Riku Voipio1d8b5122014-04-23 10:26:05 +03005463 __put_user(INSN_MOV_R30_R16, &frame->retcode[0]);
5464 __put_user(INSN_LDI_R0 + TARGET_NR_sigreturn,
5465 &frame->retcode[1]);
5466 __put_user(INSN_CALLSYS, &frame->retcode[2]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005467 /* imb() */
5468 r26 = frame_addr;
5469 }
5470
5471 unlock_user_struct(frame, frame_addr, 1);
5472
5473 if (err) {
5474 give_sigsegv:
5475 if (sig == TARGET_SIGSEGV) {
5476 ka->_sa_handler = TARGET_SIG_DFL;
5477 }
5478 force_sig(TARGET_SIGSEGV);
5479 }
5480
5481 env->ir[IR_RA] = r26;
5482 env->ir[IR_PV] = env->pc = ka->_sa_handler;
5483 env->ir[IR_A0] = sig;
5484 env->ir[IR_A1] = 0;
5485 env->ir[IR_A2] = frame_addr + offsetof(struct target_sigframe, sc);
5486 env->ir[IR_SP] = frame_addr;
5487}
5488
5489static void setup_rt_frame(int sig, struct target_sigaction *ka,
5490 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01005491 target_sigset_t *set, CPUAlphaState *env)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005492{
5493 abi_ulong frame_addr, r26;
5494 struct target_rt_sigframe *frame;
5495 int i, err = 0;
5496
5497 frame_addr = get_sigframe(ka, env, sizeof(*frame));
5498 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
5499 goto give_sigsegv;
5500 }
5501
Riku Voipiob0fd8d12014-04-23 10:46:13 +03005502 copy_siginfo_to_user(&frame->info, info);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005503
Riku Voipio1d8b5122014-04-23 10:26:05 +03005504 __put_user(0, &frame->uc.tuc_flags);
5505 __put_user(0, &frame->uc.tuc_link);
5506 __put_user(set->sig[0], &frame->uc.tuc_osf_sigmask);
5507 __put_user(target_sigaltstack_used.ss_sp,
5508 &frame->uc.tuc_stack.ss_sp);
5509 __put_user(sas_ss_flags(env->ir[IR_SP]),
5510 &frame->uc.tuc_stack.ss_flags);
5511 __put_user(target_sigaltstack_used.ss_size,
5512 &frame->uc.tuc_stack.ss_size);
Riku Voipio41ecc722014-04-23 11:01:00 +03005513 setup_sigcontext(&frame->uc.tuc_mcontext, env, frame_addr, set);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005514 for (i = 0; i < TARGET_NSIG_WORDS; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03005515 __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005516 }
5517
5518 if (ka->sa_restorer) {
5519 r26 = ka->sa_restorer;
5520 } else {
Riku Voipio1d8b5122014-04-23 10:26:05 +03005521 __put_user(INSN_MOV_R30_R16, &frame->retcode[0]);
5522 __put_user(INSN_LDI_R0 + TARGET_NR_rt_sigreturn,
5523 &frame->retcode[1]);
5524 __put_user(INSN_CALLSYS, &frame->retcode[2]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005525 /* imb(); */
5526 r26 = frame_addr;
5527 }
5528
5529 if (err) {
5530 give_sigsegv:
5531 if (sig == TARGET_SIGSEGV) {
5532 ka->_sa_handler = TARGET_SIG_DFL;
5533 }
5534 force_sig(TARGET_SIGSEGV);
5535 }
5536
5537 env->ir[IR_RA] = r26;
5538 env->ir[IR_PV] = env->pc = ka->_sa_handler;
5539 env->ir[IR_A0] = sig;
5540 env->ir[IR_A1] = frame_addr + offsetof(struct target_rt_sigframe, info);
5541 env->ir[IR_A2] = frame_addr + offsetof(struct target_rt_sigframe, uc);
5542 env->ir[IR_SP] = frame_addr;
5543}
5544
Andreas Färber05390242012-02-25 03:37:53 +01005545long do_sigreturn(CPUAlphaState *env)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005546{
5547 struct target_sigcontext *sc;
5548 abi_ulong sc_addr = env->ir[IR_A0];
5549 target_sigset_t target_set;
5550 sigset_t set;
5551
5552 if (!lock_user_struct(VERIFY_READ, sc, sc_addr, 1)) {
5553 goto badframe;
5554 }
5555
5556 target_sigemptyset(&target_set);
5557 if (__get_user(target_set.sig[0], &sc->sc_mask)) {
5558 goto badframe;
5559 }
5560
5561 target_to_host_sigset_internal(&set, &target_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00005562 do_sigprocmask(SIG_SETMASK, &set, NULL);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005563
Riku Voipio016d2e12014-04-23 11:19:48 +03005564 restore_sigcontext(env, sc);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005565 unlock_user_struct(sc, sc_addr, 0);
5566 return env->ir[IR_V0];
5567
5568 badframe:
5569 unlock_user_struct(sc, sc_addr, 0);
5570 force_sig(TARGET_SIGSEGV);
5571}
5572
Andreas Färber05390242012-02-25 03:37:53 +01005573long do_rt_sigreturn(CPUAlphaState *env)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005574{
5575 abi_ulong frame_addr = env->ir[IR_A0];
5576 struct target_rt_sigframe *frame;
5577 sigset_t set;
5578
5579 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
5580 goto badframe;
5581 }
Aurelien Jarno60e99242010-03-29 02:12:51 +02005582 target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
Alex Barcelo1c275922014-03-14 14:36:55 +00005583 do_sigprocmask(SIG_SETMASK, &set, NULL);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005584
Riku Voipio016d2e12014-04-23 11:19:48 +03005585 restore_sigcontext(env, &frame->uc.tuc_mcontext);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005586 if (do_sigaltstack(frame_addr + offsetof(struct target_rt_sigframe,
Aurelien Jarno60e99242010-03-29 02:12:51 +02005587 uc.tuc_stack),
Richard Henderson6049f4f2009-12-27 18:30:03 -08005588 0, env->ir[IR_SP]) == -EFAULT) {
5589 goto badframe;
5590 }
5591
5592 unlock_user_struct(frame, frame_addr, 0);
5593 return env->ir[IR_V0];
5594
5595
5596 badframe:
5597 unlock_user_struct(frame, frame_addr, 0);
5598 force_sig(TARGET_SIGSEGV);
5599}
5600
bellardb346ff42003-06-15 20:05:50 +00005601#else
5602
pbrook624f7972008-05-31 16:11:38 +00005603static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber9349b4f2012-03-14 01:38:32 +01005604 target_sigset_t *set, CPUArchState *env)
bellardb346ff42003-06-15 20:05:50 +00005605{
5606 fprintf(stderr, "setup_frame: not implemented\n");
5607}
5608
pbrook624f7972008-05-31 16:11:38 +00005609static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05005610 target_siginfo_t *info,
Andreas Färber9349b4f2012-03-14 01:38:32 +01005611 target_sigset_t *set, CPUArchState *env)
bellardb346ff42003-06-15 20:05:50 +00005612{
5613 fprintf(stderr, "setup_rt_frame: not implemented\n");
5614}
5615
Andreas Färber9349b4f2012-03-14 01:38:32 +01005616long do_sigreturn(CPUArchState *env)
bellardb346ff42003-06-15 20:05:50 +00005617{
5618 fprintf(stderr, "do_sigreturn: not implemented\n");
bellardf8b0aa22007-11-11 23:03:42 +00005619 return -TARGET_ENOSYS;
bellardb346ff42003-06-15 20:05:50 +00005620}
5621
Andreas Färber9349b4f2012-03-14 01:38:32 +01005622long do_rt_sigreturn(CPUArchState *env)
bellardb346ff42003-06-15 20:05:50 +00005623{
5624 fprintf(stderr, "do_rt_sigreturn: not implemented\n");
bellardf8b0aa22007-11-11 23:03:42 +00005625 return -TARGET_ENOSYS;
bellardb346ff42003-06-15 20:05:50 +00005626}
5627
bellard66fb9762003-03-23 01:06:05 +00005628#endif
5629
Andreas Färber9349b4f2012-03-14 01:38:32 +01005630void process_pending_signals(CPUArchState *cpu_env)
bellard66fb9762003-03-23 01:06:05 +00005631{
Andreas Färberdb6b81d2013-06-27 19:49:31 +02005632 CPUState *cpu = ENV_GET_CPU(cpu_env);
bellard66fb9762003-03-23 01:06:05 +00005633 int sig;
blueswir1992f48a2007-10-14 16:27:31 +00005634 abi_ulong handler;
bellard9de5e442003-03-23 16:49:39 +00005635 sigset_t set, old_set;
Anthony Liguoric227f092009-10-01 16:12:16 -05005636 target_sigset_t target_old_set;
pbrook624f7972008-05-31 16:11:38 +00005637 struct emulated_sigtable *k;
5638 struct target_sigaction *sa;
bellard66fb9762003-03-23 01:06:05 +00005639 struct sigqueue *q;
Andreas Färber0429a972013-08-26 18:14:44 +02005640 TaskState *ts = cpu->opaque;
ths3b46e622007-09-17 08:09:54 +00005641
pbrook624f7972008-05-31 16:11:38 +00005642 if (!ts->signal_pending)
bellard31e31b82003-02-18 22:55:36 +00005643 return;
5644
pbrook624f7972008-05-31 16:11:38 +00005645 /* FIXME: This is not threadsafe. */
5646 k = ts->sigtab;
bellard66fb9762003-03-23 01:06:05 +00005647 for(sig = 1; sig <= TARGET_NSIG; sig++) {
5648 if (k->pending)
bellard31e31b82003-02-18 22:55:36 +00005649 goto handle_signal;
bellard66fb9762003-03-23 01:06:05 +00005650 k++;
bellard31e31b82003-02-18 22:55:36 +00005651 }
5652 /* if no signal is pending, just return */
pbrook624f7972008-05-31 16:11:38 +00005653 ts->signal_pending = 0;
bellard31e31b82003-02-18 22:55:36 +00005654 return;
bellard66fb9762003-03-23 01:06:05 +00005655
bellard31e31b82003-02-18 22:55:36 +00005656 handle_signal:
bellard66fb9762003-03-23 01:06:05 +00005657#ifdef DEBUG_SIGNAL
bellardbc8a22c2003-03-30 21:02:40 +00005658 fprintf(stderr, "qemu: process signal %d\n", sig);
bellard66fb9762003-03-23 01:06:05 +00005659#endif
5660 /* dequeue signal */
5661 q = k->first;
5662 k->first = q->next;
5663 if (!k->first)
5664 k->pending = 0;
ths3b46e622007-09-17 08:09:54 +00005665
Andreas Färberdb6b81d2013-06-27 19:49:31 +02005666 sig = gdb_handlesig(cpu, sig);
bellard1fddef42005-04-17 19:16:13 +00005667 if (!sig) {
aurel32ca587a82008-12-18 22:44:13 +00005668 sa = NULL;
5669 handler = TARGET_SIG_IGN;
5670 } else {
5671 sa = &sigact_table[sig - 1];
5672 handler = sa->_sa_handler;
bellard1fddef42005-04-17 19:16:13 +00005673 }
bellard66fb9762003-03-23 01:06:05 +00005674
Peter Maydella7ec0f92014-03-14 14:36:56 +00005675 if (ts->sigsegv_blocked && sig == TARGET_SIGSEGV) {
5676 /* Guest has blocked SIGSEGV but we got one anyway. Assume this
5677 * is a forced SIGSEGV (ie one the kernel handles via force_sig_info
5678 * because it got a real MMU fault), and treat as if default handler.
5679 */
5680 handler = TARGET_SIG_DFL;
5681 }
5682
bellard66fb9762003-03-23 01:06:05 +00005683 if (handler == TARGET_SIG_DFL) {
aurel32ca587a82008-12-18 22:44:13 +00005684 /* default handler : ignore some signal. The other are job control or fatal */
5685 if (sig == TARGET_SIGTSTP || sig == TARGET_SIGTTIN || sig == TARGET_SIGTTOU) {
5686 kill(getpid(),SIGSTOP);
5687 } else if (sig != TARGET_SIGCHLD &&
5688 sig != TARGET_SIGURG &&
5689 sig != TARGET_SIGWINCH &&
5690 sig != TARGET_SIGCONT) {
bellard66fb9762003-03-23 01:06:05 +00005691 force_sig(sig);
5692 }
5693 } else if (handler == TARGET_SIG_IGN) {
5694 /* ignore sig */
5695 } else if (handler == TARGET_SIG_ERR) {
5696 force_sig(sig);
5697 } else {
bellard9de5e442003-03-23 16:49:39 +00005698 /* compute the blocked signals during the handler execution */
pbrook624f7972008-05-31 16:11:38 +00005699 target_to_host_sigset(&set, &sa->sa_mask);
bellard9de5e442003-03-23 16:49:39 +00005700 /* SA_NODEFER indicates that the current signal should not be
5701 blocked during the handler */
pbrook624f7972008-05-31 16:11:38 +00005702 if (!(sa->sa_flags & TARGET_SA_NODEFER))
bellard9de5e442003-03-23 16:49:39 +00005703 sigaddset(&set, target_to_host_signal(sig));
ths3b46e622007-09-17 08:09:54 +00005704
bellard9de5e442003-03-23 16:49:39 +00005705 /* block signals in the handler using Linux */
Alex Barcelo1c275922014-03-14 14:36:55 +00005706 do_sigprocmask(SIG_BLOCK, &set, &old_set);
bellard9de5e442003-03-23 16:49:39 +00005707 /* save the previous blocked signal state to restore it at the
5708 end of the signal execution (see do_sigreturn) */
bellard92319442004-06-19 16:58:13 +00005709 host_to_target_sigset_internal(&target_old_set, &old_set);
bellard9de5e442003-03-23 16:49:39 +00005710
bellardbc8a22c2003-03-30 21:02:40 +00005711 /* if the CPU is in VM86 mode, we restore the 32 bit values */
j_mayer84409dd2007-04-06 08:56:50 +00005712#if defined(TARGET_I386) && !defined(TARGET_X86_64)
bellardbc8a22c2003-03-30 21:02:40 +00005713 {
5714 CPUX86State *env = cpu_env;
5715 if (env->eflags & VM_MASK)
5716 save_v86_state(env);
5717 }
5718#endif
bellard9de5e442003-03-23 16:49:39 +00005719 /* prepare the stack frame of the virtual CPU */
Richard Hendersonff970902013-02-10 10:30:42 -08005720#if defined(TARGET_ABI_MIPSN32) || defined(TARGET_ABI_MIPSN64)
5721 /* These targets do not have traditional signals. */
5722 setup_rt_frame(sig, sa, &q->info, &target_old_set, cpu_env);
5723#else
pbrook624f7972008-05-31 16:11:38 +00005724 if (sa->sa_flags & TARGET_SA_SIGINFO)
5725 setup_rt_frame(sig, sa, &q->info, &target_old_set, cpu_env);
bellard66fb9762003-03-23 01:06:05 +00005726 else
pbrook624f7972008-05-31 16:11:38 +00005727 setup_frame(sig, sa, &target_old_set, cpu_env);
Richard Hendersonff970902013-02-10 10:30:42 -08005728#endif
pbrook624f7972008-05-31 16:11:38 +00005729 if (sa->sa_flags & TARGET_SA_RESETHAND)
5730 sa->_sa_handler = TARGET_SIG_DFL;
bellard31e31b82003-02-18 22:55:36 +00005731 }
bellard66fb9762003-03-23 01:06:05 +00005732 if (q != &k->info)
pbrook624f7972008-05-31 16:11:38 +00005733 free_sigqueue(cpu_env, q);
bellard31e31b82003-02-18 22:55:36 +00005734}