blob: f55076d41e2ce63c6b9d9de306fb146198cc82aa [file] [log] [blame]
bellard31e31b82003-02-18 22:55:36 +00001/*
bellard66fb9762003-03-23 01:06:05 +00002 * Emulation of Linux signals
ths5fafdf22007-09-16 21:08:06 +00003 *
bellard31e31b82003-02-18 22:55:36 +00004 * Copyright (c) 2003 Fabrice Bellard
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
Blue Swirl8167ee82009-07-16 20:47:01 +000017 * along with this program; if not, see <http://www.gnu.org/licenses/>.
bellard31e31b82003-02-18 22:55:36 +000018 */
19#include <stdlib.h>
20#include <stdio.h>
bellard66fb9762003-03-23 01:06:05 +000021#include <string.h>
bellard31e31b82003-02-18 22:55:36 +000022#include <stdarg.h>
bellard2677e102003-04-10 00:03:27 +000023#include <unistd.h>
bellard66fb9762003-03-23 01:06:05 +000024#include <errno.h>
aurel32603e4fd2009-04-15 16:18:38 +000025#include <assert.h>
bellard31e31b82003-02-18 22:55:36 +000026#include <sys/ucontext.h>
Mika Westerbergedf8e2a2009-04-07 09:57:11 +030027#include <sys/resource.h>
bellard31e31b82003-02-18 22:55:36 +000028
bellard3ef693a2003-03-23 20:17:16 +000029#include "qemu.h"
blueswir17d99a002009-01-14 19:00:36 +000030#include "qemu-common.h"
blueswir1992f48a2007-10-14 16:27:31 +000031#include "target_signal.h"
bellard66fb9762003-03-23 01:06:05 +000032
33//#define DEBUG_SIGNAL
34
blueswir1249c4c32008-10-05 11:09:37 +000035static struct target_sigaltstack target_sigaltstack_used = {
thsa04e1342007-09-27 13:57:58 +000036 .ss_sp = 0,
37 .ss_size = 0,
38 .ss_flags = TARGET_SS_DISABLE,
39};
40
pbrook624f7972008-05-31 16:11:38 +000041static struct target_sigaction sigact_table[TARGET_NSIG];
bellard31e31b82003-02-18 22:55:36 +000042
ths5fafdf22007-09-16 21:08:06 +000043static void host_signal_handler(int host_signum, siginfo_t *info,
bellard66fb9762003-03-23 01:06:05 +000044 void *puc);
45
Arnaud Patard3ca05582009-03-30 01:18:20 +020046static uint8_t host_to_target_signal_table[_NSIG] = {
bellard9e5f5282003-07-13 17:33:54 +000047 [SIGHUP] = TARGET_SIGHUP,
48 [SIGINT] = TARGET_SIGINT,
49 [SIGQUIT] = TARGET_SIGQUIT,
50 [SIGILL] = TARGET_SIGILL,
51 [SIGTRAP] = TARGET_SIGTRAP,
52 [SIGABRT] = TARGET_SIGABRT,
bellard01e3b762003-09-30 21:10:14 +000053/* [SIGIOT] = TARGET_SIGIOT,*/
bellard9e5f5282003-07-13 17:33:54 +000054 [SIGBUS] = TARGET_SIGBUS,
55 [SIGFPE] = TARGET_SIGFPE,
56 [SIGKILL] = TARGET_SIGKILL,
57 [SIGUSR1] = TARGET_SIGUSR1,
58 [SIGSEGV] = TARGET_SIGSEGV,
59 [SIGUSR2] = TARGET_SIGUSR2,
60 [SIGPIPE] = TARGET_SIGPIPE,
61 [SIGALRM] = TARGET_SIGALRM,
62 [SIGTERM] = TARGET_SIGTERM,
63#ifdef SIGSTKFLT
64 [SIGSTKFLT] = TARGET_SIGSTKFLT,
65#endif
66 [SIGCHLD] = TARGET_SIGCHLD,
67 [SIGCONT] = TARGET_SIGCONT,
68 [SIGSTOP] = TARGET_SIGSTOP,
69 [SIGTSTP] = TARGET_SIGTSTP,
70 [SIGTTIN] = TARGET_SIGTTIN,
71 [SIGTTOU] = TARGET_SIGTTOU,
72 [SIGURG] = TARGET_SIGURG,
73 [SIGXCPU] = TARGET_SIGXCPU,
74 [SIGXFSZ] = TARGET_SIGXFSZ,
75 [SIGVTALRM] = TARGET_SIGVTALRM,
76 [SIGPROF] = TARGET_SIGPROF,
77 [SIGWINCH] = TARGET_SIGWINCH,
78 [SIGIO] = TARGET_SIGIO,
79 [SIGPWR] = TARGET_SIGPWR,
80 [SIGSYS] = TARGET_SIGSYS,
81 /* next signals stay the same */
pbrook624f7972008-05-31 16:11:38 +000082 /* Nasty hack: Reverse SIGRTMIN and SIGRTMAX to avoid overlap with
Dong Xu Wangb4916d72011-11-22 18:06:17 +080083 host libpthread signals. This assumes no one actually uses SIGRTMAX :-/
pbrook624f7972008-05-31 16:11:38 +000084 To fix this properly we need to do manual signal delivery multiplexed
85 over a single host signal. */
86 [__SIGRTMIN] = __SIGRTMAX,
87 [__SIGRTMAX] = __SIGRTMIN,
bellard9e5f5282003-07-13 17:33:54 +000088};
Arnaud Patard3ca05582009-03-30 01:18:20 +020089static uint8_t target_to_host_signal_table[_NSIG];
bellard9e5f5282003-07-13 17:33:54 +000090
thsa04e1342007-09-27 13:57:58 +000091static inline int on_sig_stack(unsigned long sp)
92{
93 return (sp - target_sigaltstack_used.ss_sp
94 < target_sigaltstack_used.ss_size);
95}
96
97static inline int sas_ss_flags(unsigned long sp)
98{
99 return (target_sigaltstack_used.ss_size == 0 ? SS_DISABLE
100 : on_sig_stack(sp) ? SS_ONSTACK : 0);
101}
102
pbrook1d9d8b52009-04-16 15:17:02 +0000103int host_to_target_signal(int sig)
bellard31e31b82003-02-18 22:55:36 +0000104{
Andreas Schwab167c50d2013-07-02 14:04:12 +0100105 if (sig < 0 || sig >= _NSIG)
pbrook4cb05962008-05-30 18:05:19 +0000106 return sig;
bellard9e5f5282003-07-13 17:33:54 +0000107 return host_to_target_signal_table[sig];
bellard31e31b82003-02-18 22:55:36 +0000108}
109
pbrook4cb05962008-05-30 18:05:19 +0000110int target_to_host_signal(int sig)
bellard31e31b82003-02-18 22:55:36 +0000111{
Andreas Schwab167c50d2013-07-02 14:04:12 +0100112 if (sig < 0 || sig >= _NSIG)
pbrook4cb05962008-05-30 18:05:19 +0000113 return sig;
bellard9e5f5282003-07-13 17:33:54 +0000114 return target_to_host_signal_table[sig];
bellard31e31b82003-02-18 22:55:36 +0000115}
116
Anthony Liguoric227f092009-10-01 16:12:16 -0500117static inline void target_sigemptyset(target_sigset_t *set)
pbrookf5545b52008-05-30 22:37:07 +0000118{
119 memset(set, 0, sizeof(*set));
120}
121
Anthony Liguoric227f092009-10-01 16:12:16 -0500122static inline void target_sigaddset(target_sigset_t *set, int signum)
pbrookf5545b52008-05-30 22:37:07 +0000123{
124 signum--;
125 abi_ulong mask = (abi_ulong)1 << (signum % TARGET_NSIG_BPW);
126 set->sig[signum / TARGET_NSIG_BPW] |= mask;
127}
128
Anthony Liguoric227f092009-10-01 16:12:16 -0500129static inline int target_sigismember(const target_sigset_t *set, int signum)
pbrookf5545b52008-05-30 22:37:07 +0000130{
131 signum--;
132 abi_ulong mask = (abi_ulong)1 << (signum % TARGET_NSIG_BPW);
133 return ((set->sig[signum / TARGET_NSIG_BPW] & mask) != 0);
134}
135
Anthony Liguoric227f092009-10-01 16:12:16 -0500136static void host_to_target_sigset_internal(target_sigset_t *d,
bellard92319442004-06-19 16:58:13 +0000137 const sigset_t *s)
bellard66fb9762003-03-23 01:06:05 +0000138{
139 int i;
pbrookf5545b52008-05-30 22:37:07 +0000140 target_sigemptyset(d);
141 for (i = 1; i <= TARGET_NSIG; i++) {
142 if (sigismember(s, i)) {
143 target_sigaddset(d, host_to_target_signal(i));
144 }
bellard9e5f5282003-07-13 17:33:54 +0000145 }
bellard66fb9762003-03-23 01:06:05 +0000146}
147
Anthony Liguoric227f092009-10-01 16:12:16 -0500148void host_to_target_sigset(target_sigset_t *d, const sigset_t *s)
bellard92319442004-06-19 16:58:13 +0000149{
Anthony Liguoric227f092009-10-01 16:12:16 -0500150 target_sigset_t d1;
bellard92319442004-06-19 16:58:13 +0000151 int i;
152
153 host_to_target_sigset_internal(&d1, s);
154 for(i = 0;i < TARGET_NSIG_WORDS; i++)
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200155 d->sig[i] = tswapal(d1.sig[i]);
bellard92319442004-06-19 16:58:13 +0000156}
157
blueswir18fcd3692008-08-17 20:26:25 +0000158static void target_to_host_sigset_internal(sigset_t *d,
Anthony Liguoric227f092009-10-01 16:12:16 -0500159 const target_sigset_t *s)
bellard66fb9762003-03-23 01:06:05 +0000160{
161 int i;
pbrookf5545b52008-05-30 22:37:07 +0000162 sigemptyset(d);
163 for (i = 1; i <= TARGET_NSIG; i++) {
164 if (target_sigismember(s, i)) {
165 sigaddset(d, target_to_host_signal(i));
166 }
167 }
bellard66fb9762003-03-23 01:06:05 +0000168}
169
Anthony Liguoric227f092009-10-01 16:12:16 -0500170void target_to_host_sigset(sigset_t *d, const target_sigset_t *s)
bellard92319442004-06-19 16:58:13 +0000171{
Anthony Liguoric227f092009-10-01 16:12:16 -0500172 target_sigset_t s1;
bellard92319442004-06-19 16:58:13 +0000173 int i;
174
175 for(i = 0;i < TARGET_NSIG_WORDS; i++)
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200176 s1.sig[i] = tswapal(s->sig[i]);
bellard92319442004-06-19 16:58:13 +0000177 target_to_host_sigset_internal(d, &s1);
178}
ths3b46e622007-09-17 08:09:54 +0000179
blueswir1992f48a2007-10-14 16:27:31 +0000180void host_to_target_old_sigset(abi_ulong *old_sigset,
bellard66fb9762003-03-23 01:06:05 +0000181 const sigset_t *sigset)
182{
Anthony Liguoric227f092009-10-01 16:12:16 -0500183 target_sigset_t d;
bellard9e5f5282003-07-13 17:33:54 +0000184 host_to_target_sigset(&d, sigset);
185 *old_sigset = d.sig[0];
bellard66fb9762003-03-23 01:06:05 +0000186}
187
ths5fafdf22007-09-16 21:08:06 +0000188void target_to_host_old_sigset(sigset_t *sigset,
blueswir1992f48a2007-10-14 16:27:31 +0000189 const abi_ulong *old_sigset)
bellard66fb9762003-03-23 01:06:05 +0000190{
Anthony Liguoric227f092009-10-01 16:12:16 -0500191 target_sigset_t d;
bellard9e5f5282003-07-13 17:33:54 +0000192 int i;
193
194 d.sig[0] = *old_sigset;
195 for(i = 1;i < TARGET_NSIG_WORDS; i++)
196 d.sig[i] = 0;
197 target_to_host_sigset(sigset, &d);
bellard66fb9762003-03-23 01:06:05 +0000198}
199
Alex Barcelo1c275922014-03-14 14:36:55 +0000200/* Wrapper for sigprocmask function
201 * Emulates a sigprocmask in a safe way for the guest. Note that set and oldset
202 * are host signal set, not guest ones. This wraps the sigprocmask host calls
203 * that should be protected (calls originated from guest)
204 */
205int do_sigprocmask(int how, const sigset_t *set, sigset_t *oldset)
206{
Peter Maydella7ec0f92014-03-14 14:36:56 +0000207 int ret;
208 sigset_t val;
209 sigset_t *temp = NULL;
210 CPUState *cpu = thread_cpu;
211 TaskState *ts = (TaskState *)cpu->opaque;
212 bool segv_was_blocked = ts->sigsegv_blocked;
213
214 if (set) {
215 bool has_sigsegv = sigismember(set, SIGSEGV);
216 val = *set;
217 temp = &val;
218
219 sigdelset(temp, SIGSEGV);
220
221 switch (how) {
222 case SIG_BLOCK:
223 if (has_sigsegv) {
224 ts->sigsegv_blocked = true;
225 }
226 break;
227 case SIG_UNBLOCK:
228 if (has_sigsegv) {
229 ts->sigsegv_blocked = false;
230 }
231 break;
232 case SIG_SETMASK:
233 ts->sigsegv_blocked = has_sigsegv;
234 break;
235 default:
236 g_assert_not_reached();
237 }
238 }
239
240 ret = sigprocmask(how, temp, oldset);
241
242 if (oldset && segv_was_blocked) {
243 sigaddset(oldset, SIGSEGV);
244 }
245
246 return ret;
Alex Barcelo1c275922014-03-14 14:36:55 +0000247}
248
bellard9de5e442003-03-23 16:49:39 +0000249/* siginfo conversion */
250
Anthony Liguoric227f092009-10-01 16:12:16 -0500251static inline void host_to_target_siginfo_noswap(target_siginfo_t *tinfo,
bellard9de5e442003-03-23 16:49:39 +0000252 const siginfo_t *info)
bellard66fb9762003-03-23 01:06:05 +0000253{
Richard Hendersona05c6402012-09-15 11:34:20 -0700254 int sig = host_to_target_signal(info->si_signo);
bellard9de5e442003-03-23 16:49:39 +0000255 tinfo->si_signo = sig;
256 tinfo->si_errno = 0;
pbrookafd7cd92008-05-31 12:14:21 +0000257 tinfo->si_code = info->si_code;
Richard Hendersona05c6402012-09-15 11:34:20 -0700258
259 if (sig == TARGET_SIGILL || sig == TARGET_SIGFPE || sig == TARGET_SIGSEGV
260 || sig == TARGET_SIGBUS || sig == TARGET_SIGTRAP) {
261 /* Should never come here, but who knows. The information for
262 the target is irrelevant. */
bellard9de5e442003-03-23 16:49:39 +0000263 tinfo->_sifields._sigfault._addr = 0;
Richard Hendersona05c6402012-09-15 11:34:20 -0700264 } else if (sig == TARGET_SIGIO) {
265 tinfo->_sifields._sigpoll._band = info->si_band;
ths7f7f7c82007-07-12 11:02:46 +0000266 tinfo->_sifields._sigpoll._fd = info->si_fd;
Richard Hendersona05c6402012-09-15 11:34:20 -0700267 } else if (sig == TARGET_SIGCHLD) {
268 tinfo->_sifields._sigchld._pid = info->si_pid;
269 tinfo->_sifields._sigchld._uid = info->si_uid;
270 tinfo->_sifields._sigchld._status
271 = host_to_target_waitstatus(info->si_status);
272 tinfo->_sifields._sigchld._utime = info->si_utime;
273 tinfo->_sifields._sigchld._stime = info->si_stime;
bellard9de5e442003-03-23 16:49:39 +0000274 } else if (sig >= TARGET_SIGRTMIN) {
275 tinfo->_sifields._rt._pid = info->si_pid;
276 tinfo->_sifields._rt._uid = info->si_uid;
277 /* XXX: potential problem if 64 bit */
Richard Hendersona05c6402012-09-15 11:34:20 -0700278 tinfo->_sifields._rt._sigval.sival_ptr
279 = (abi_ulong)(unsigned long)info->si_value.sival_ptr;
bellard9de5e442003-03-23 16:49:39 +0000280 }
bellard66fb9762003-03-23 01:06:05 +0000281}
282
Anthony Liguoric227f092009-10-01 16:12:16 -0500283static void tswap_siginfo(target_siginfo_t *tinfo,
284 const target_siginfo_t *info)
bellard9de5e442003-03-23 16:49:39 +0000285{
Richard Hendersona05c6402012-09-15 11:34:20 -0700286 int sig = info->si_signo;
bellard9de5e442003-03-23 16:49:39 +0000287 tinfo->si_signo = tswap32(sig);
288 tinfo->si_errno = tswap32(info->si_errno);
289 tinfo->si_code = tswap32(info->si_code);
Richard Hendersona05c6402012-09-15 11:34:20 -0700290
291 if (sig == TARGET_SIGILL || sig == TARGET_SIGFPE || sig == TARGET_SIGSEGV
292 || sig == TARGET_SIGBUS || sig == TARGET_SIGTRAP) {
293 tinfo->_sifields._sigfault._addr
294 = tswapal(info->_sifields._sigfault._addr);
295 } else if (sig == TARGET_SIGIO) {
296 tinfo->_sifields._sigpoll._band
297 = tswap32(info->_sifields._sigpoll._band);
298 tinfo->_sifields._sigpoll._fd = tswap32(info->_sifields._sigpoll._fd);
299 } else if (sig == TARGET_SIGCHLD) {
300 tinfo->_sifields._sigchld._pid
301 = tswap32(info->_sifields._sigchld._pid);
302 tinfo->_sifields._sigchld._uid
303 = tswap32(info->_sifields._sigchld._uid);
304 tinfo->_sifields._sigchld._status
305 = tswap32(info->_sifields._sigchld._status);
306 tinfo->_sifields._sigchld._utime
307 = tswapal(info->_sifields._sigchld._utime);
308 tinfo->_sifields._sigchld._stime
309 = tswapal(info->_sifields._sigchld._stime);
bellard9de5e442003-03-23 16:49:39 +0000310 } else if (sig >= TARGET_SIGRTMIN) {
311 tinfo->_sifields._rt._pid = tswap32(info->_sifields._rt._pid);
312 tinfo->_sifields._rt._uid = tswap32(info->_sifields._rt._uid);
Richard Hendersona05c6402012-09-15 11:34:20 -0700313 tinfo->_sifields._rt._sigval.sival_ptr
314 = tswapal(info->_sifields._rt._sigval.sival_ptr);
bellard9de5e442003-03-23 16:49:39 +0000315 }
316}
317
318
Anthony Liguoric227f092009-10-01 16:12:16 -0500319void host_to_target_siginfo(target_siginfo_t *tinfo, const siginfo_t *info)
bellard9de5e442003-03-23 16:49:39 +0000320{
321 host_to_target_siginfo_noswap(tinfo, info);
322 tswap_siginfo(tinfo, tinfo);
323}
324
325/* XXX: we support only POSIX RT signals are used. */
thsaa1f17c2007-07-11 22:48:58 +0000326/* XXX: find a solution for 64 bit (additional malloced data is needed) */
Anthony Liguoric227f092009-10-01 16:12:16 -0500327void target_to_host_siginfo(siginfo_t *info, const target_siginfo_t *tinfo)
bellard66fb9762003-03-23 01:06:05 +0000328{
329 info->si_signo = tswap32(tinfo->si_signo);
330 info->si_errno = tswap32(tinfo->si_errno);
331 info->si_code = tswap32(tinfo->si_code);
bellard9de5e442003-03-23 16:49:39 +0000332 info->si_pid = tswap32(tinfo->_sifields._rt._pid);
333 info->si_uid = tswap32(tinfo->_sifields._rt._uid);
ths5fafdf22007-09-16 21:08:06 +0000334 info->si_value.sival_ptr =
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200335 (void *)(long)tswapal(tinfo->_sifields._rt._sigval.sival_ptr);
bellard66fb9762003-03-23 01:06:05 +0000336}
337
aurel32ca587a82008-12-18 22:44:13 +0000338static int fatal_signal (int sig)
339{
340 switch (sig) {
341 case TARGET_SIGCHLD:
342 case TARGET_SIGURG:
343 case TARGET_SIGWINCH:
344 /* Ignored by default. */
345 return 0;
346 case TARGET_SIGCONT:
347 case TARGET_SIGSTOP:
348 case TARGET_SIGTSTP:
349 case TARGET_SIGTTIN:
350 case TARGET_SIGTTOU:
351 /* Job control signals. */
352 return 0;
353 default:
354 return 1;
355 }
356}
357
Mika Westerbergedf8e2a2009-04-07 09:57:11 +0300358/* returns 1 if given signal should dump core if not handled */
359static int core_dump_signal(int sig)
360{
361 switch (sig) {
362 case TARGET_SIGABRT:
363 case TARGET_SIGFPE:
364 case TARGET_SIGILL:
365 case TARGET_SIGQUIT:
366 case TARGET_SIGSEGV:
367 case TARGET_SIGTRAP:
368 case TARGET_SIGBUS:
369 return (1);
370 default:
371 return (0);
372 }
373}
374
bellard31e31b82003-02-18 22:55:36 +0000375void signal_init(void)
376{
377 struct sigaction act;
pbrook624f7972008-05-31 16:11:38 +0000378 struct sigaction oact;
bellard9e5f5282003-07-13 17:33:54 +0000379 int i, j;
pbrook624f7972008-05-31 16:11:38 +0000380 int host_sig;
bellard31e31b82003-02-18 22:55:36 +0000381
bellard9e5f5282003-07-13 17:33:54 +0000382 /* generate signal conversion tables */
Arnaud Patard3ca05582009-03-30 01:18:20 +0200383 for(i = 1; i < _NSIG; i++) {
bellard9e5f5282003-07-13 17:33:54 +0000384 if (host_to_target_signal_table[i] == 0)
385 host_to_target_signal_table[i] = i;
386 }
Arnaud Patard3ca05582009-03-30 01:18:20 +0200387 for(i = 1; i < _NSIG; i++) {
bellard9e5f5282003-07-13 17:33:54 +0000388 j = host_to_target_signal_table[i];
389 target_to_host_signal_table[j] = i;
390 }
ths3b46e622007-09-17 08:09:54 +0000391
bellard9de5e442003-03-23 16:49:39 +0000392 /* set all host signal handlers. ALL signals are blocked during
393 the handlers to serialize them. */
pbrook624f7972008-05-31 16:11:38 +0000394 memset(sigact_table, 0, sizeof(sigact_table));
395
bellard9de5e442003-03-23 16:49:39 +0000396 sigfillset(&act.sa_mask);
bellard31e31b82003-02-18 22:55:36 +0000397 act.sa_flags = SA_SIGINFO;
398 act.sa_sigaction = host_signal_handler;
pbrook624f7972008-05-31 16:11:38 +0000399 for(i = 1; i <= TARGET_NSIG; i++) {
400 host_sig = target_to_host_signal(i);
401 sigaction(host_sig, NULL, &oact);
402 if (oact.sa_sigaction == (void *)SIG_IGN) {
403 sigact_table[i - 1]._sa_handler = TARGET_SIG_IGN;
404 } else if (oact.sa_sigaction == (void *)SIG_DFL) {
405 sigact_table[i - 1]._sa_handler = TARGET_SIG_DFL;
406 }
407 /* If there's already a handler installed then something has
408 gone horribly wrong, so don't even try to handle that case. */
aurel32ca587a82008-12-18 22:44:13 +0000409 /* Install some handlers for our own use. We need at least
410 SIGSEGV and SIGBUS, to detect exceptions. We can not just
411 trap all signals because it affects syscall interrupt
412 behavior. But do trap all default-fatal signals. */
413 if (fatal_signal (i))
pbrook624f7972008-05-31 16:11:38 +0000414 sigaction(host_sig, &act, NULL);
bellard31e31b82003-02-18 22:55:36 +0000415 }
bellard31e31b82003-02-18 22:55:36 +0000416}
417
bellard66fb9762003-03-23 01:06:05 +0000418/* signal queue handling */
419
Andreas Färber9349b4f2012-03-14 01:38:32 +0100420static inline struct sigqueue *alloc_sigqueue(CPUArchState *env)
bellard66fb9762003-03-23 01:06:05 +0000421{
Andreas Färber0429a972013-08-26 18:14:44 +0200422 CPUState *cpu = ENV_GET_CPU(env);
423 TaskState *ts = cpu->opaque;
pbrook624f7972008-05-31 16:11:38 +0000424 struct sigqueue *q = ts->first_free;
bellard66fb9762003-03-23 01:06:05 +0000425 if (!q)
426 return NULL;
pbrook624f7972008-05-31 16:11:38 +0000427 ts->first_free = q->next;
bellard66fb9762003-03-23 01:06:05 +0000428 return q;
429}
430
Andreas Färber9349b4f2012-03-14 01:38:32 +0100431static inline void free_sigqueue(CPUArchState *env, struct sigqueue *q)
bellard66fb9762003-03-23 01:06:05 +0000432{
Andreas Färber0429a972013-08-26 18:14:44 +0200433 CPUState *cpu = ENV_GET_CPU(env);
434 TaskState *ts = cpu->opaque;
435
pbrook624f7972008-05-31 16:11:38 +0000436 q->next = ts->first_free;
437 ts->first_free = q;
bellard66fb9762003-03-23 01:06:05 +0000438}
439
bellard9de5e442003-03-23 16:49:39 +0000440/* abort execution with signal */
Riku Voipio66393fb2009-12-04 15:16:32 +0200441static void QEMU_NORETURN force_sig(int target_sig)
bellard66fb9762003-03-23 01:06:05 +0000442{
Andreas Färber0429a972013-08-26 18:14:44 +0200443 CPUState *cpu = thread_cpu;
444 CPUArchState *env = cpu->env_ptr;
445 TaskState *ts = (TaskState *)cpu->opaque;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +0300446 int host_sig, core_dumped = 0;
aurel32603e4fd2009-04-15 16:18:38 +0000447 struct sigaction act;
Riku Voipio66393fb2009-12-04 15:16:32 +0200448 host_sig = target_to_host_signal(target_sig);
Andreas Färbera2247f82013-06-09 19:47:04 +0200449 gdb_signalled(env, target_sig);
aurel32603e4fd2009-04-15 16:18:38 +0000450
Mika Westerbergedf8e2a2009-04-07 09:57:11 +0300451 /* dump core if supported by target binary format */
Riku Voipio66393fb2009-12-04 15:16:32 +0200452 if (core_dump_signal(target_sig) && (ts->bprm->core_dump != NULL)) {
Mika Westerbergedf8e2a2009-04-07 09:57:11 +0300453 stop_all_tasks();
454 core_dumped =
Andreas Färbera2247f82013-06-09 19:47:04 +0200455 ((*ts->bprm->core_dump)(target_sig, env) == 0);
Mika Westerbergedf8e2a2009-04-07 09:57:11 +0300456 }
457 if (core_dumped) {
458 /* we already dumped the core of target process, we don't want
459 * a coredump of qemu itself */
460 struct rlimit nodump;
461 getrlimit(RLIMIT_CORE, &nodump);
462 nodump.rlim_cur=0;
463 setrlimit(RLIMIT_CORE, &nodump);
464 (void) fprintf(stderr, "qemu: uncaught target signal %d (%s) - %s\n",
Riku Voipio66393fb2009-12-04 15:16:32 +0200465 target_sig, strsignal(host_sig), "core dumped" );
Mika Westerbergedf8e2a2009-04-07 09:57:11 +0300466 }
467
Stefan Weil0c587512011-04-28 17:20:32 +0200468 /* The proper exit code for dying from an uncaught signal is
aurel32603e4fd2009-04-15 16:18:38 +0000469 * -<signal>. The kernel doesn't allow exit() or _exit() to pass
470 * a negative value. To get the proper exit code we need to
471 * actually die from an uncaught signal. Here the default signal
472 * handler is installed, we send ourself a signal and we wait for
473 * it to arrive. */
474 sigfillset(&act.sa_mask);
475 act.sa_handler = SIG_DFL;
Peter Maydell3a5d30b2014-02-17 18:55:32 +0000476 act.sa_flags = 0;
aurel32603e4fd2009-04-15 16:18:38 +0000477 sigaction(host_sig, &act, NULL);
478
479 /* For some reason raise(host_sig) doesn't send the signal when
480 * statically linked on x86-64. */
481 kill(getpid(), host_sig);
482
483 /* Make sure the signal isn't masked (just reuse the mask inside
484 of act) */
485 sigdelset(&act.sa_mask, host_sig);
486 sigsuspend(&act.sa_mask);
487
488 /* unreachable */
Blue Swirla6c6f762010-03-13 14:18:50 +0000489 abort();
bellard66fb9762003-03-23 01:06:05 +0000490}
491
bellard9de5e442003-03-23 16:49:39 +0000492/* queue a signal so that it will be send to the virtual CPU as soon
493 as possible */
Andreas Färber9349b4f2012-03-14 01:38:32 +0100494int queue_signal(CPUArchState *env, int sig, target_siginfo_t *info)
bellard31e31b82003-02-18 22:55:36 +0000495{
Andreas Färber0429a972013-08-26 18:14:44 +0200496 CPUState *cpu = ENV_GET_CPU(env);
497 TaskState *ts = cpu->opaque;
pbrook624f7972008-05-31 16:11:38 +0000498 struct emulated_sigtable *k;
bellard9de5e442003-03-23 16:49:39 +0000499 struct sigqueue *q, **pq;
blueswir1992f48a2007-10-14 16:27:31 +0000500 abi_ulong handler;
aurel32ca587a82008-12-18 22:44:13 +0000501 int queue;
bellard66fb9762003-03-23 01:06:05 +0000502
bellard9de5e442003-03-23 16:49:39 +0000503#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000504 fprintf(stderr, "queue_signal: sig=%d\n",
bellard9de5e442003-03-23 16:49:39 +0000505 sig);
bellard66fb9762003-03-23 01:06:05 +0000506#endif
pbrook624f7972008-05-31 16:11:38 +0000507 k = &ts->sigtab[sig - 1];
aurel32ca587a82008-12-18 22:44:13 +0000508 queue = gdb_queuesig ();
pbrook624f7972008-05-31 16:11:38 +0000509 handler = sigact_table[sig - 1]._sa_handler;
Peter Maydella7ec0f92014-03-14 14:36:56 +0000510
511 if (ts->sigsegv_blocked && sig == TARGET_SIGSEGV) {
512 /* Guest has blocked SIGSEGV but we got one anyway. Assume this
513 * is a forced SIGSEGV (ie one the kernel handles via force_sig_info
514 * because it got a real MMU fault). A blocked SIGSEGV in that
515 * situation is treated as if using the default handler. This is
516 * not correct if some other process has randomly sent us a SIGSEGV
517 * via kill(), but that is not easy to distinguish at this point,
518 * so we assume it doesn't happen.
519 */
520 handler = TARGET_SIG_DFL;
521 }
522
aurel32ca587a82008-12-18 22:44:13 +0000523 if (!queue && handler == TARGET_SIG_DFL) {
ths60b19692008-11-27 15:47:15 +0000524 if (sig == TARGET_SIGTSTP || sig == TARGET_SIGTTIN || sig == TARGET_SIGTTOU) {
525 kill(getpid(),SIGSTOP);
526 return 0;
527 } else
bellard66fb9762003-03-23 01:06:05 +0000528 /* default handler : ignore some signal. The other are fatal */
ths5fafdf22007-09-16 21:08:06 +0000529 if (sig != TARGET_SIGCHLD &&
530 sig != TARGET_SIGURG &&
ths60b19692008-11-27 15:47:15 +0000531 sig != TARGET_SIGWINCH &&
532 sig != TARGET_SIGCONT) {
bellard66fb9762003-03-23 01:06:05 +0000533 force_sig(sig);
bellard9de5e442003-03-23 16:49:39 +0000534 } else {
535 return 0; /* indicate ignored */
bellard66fb9762003-03-23 01:06:05 +0000536 }
aurel32ca587a82008-12-18 22:44:13 +0000537 } else if (!queue && handler == TARGET_SIG_IGN) {
bellard66fb9762003-03-23 01:06:05 +0000538 /* ignore signal */
bellard9de5e442003-03-23 16:49:39 +0000539 return 0;
aurel32ca587a82008-12-18 22:44:13 +0000540 } else if (!queue && handler == TARGET_SIG_ERR) {
bellard66fb9762003-03-23 01:06:05 +0000541 force_sig(sig);
542 } else {
bellard9de5e442003-03-23 16:49:39 +0000543 pq = &k->first;
544 if (sig < TARGET_SIGRTMIN) {
545 /* if non real time signal, we queue exactly one signal */
546 if (!k->pending)
547 q = &k->info;
548 else
549 return 0;
550 } else {
551 if (!k->pending) {
552 /* first signal */
553 q = &k->info;
554 } else {
pbrook624f7972008-05-31 16:11:38 +0000555 q = alloc_sigqueue(env);
bellard9de5e442003-03-23 16:49:39 +0000556 if (!q)
557 return -EAGAIN;
558 while (*pq != NULL)
559 pq = &(*pq)->next;
560 }
561 }
562 *pq = q;
563 q->info = *info;
564 q->next = NULL;
565 k->pending = 1;
566 /* signal that a new signal is pending */
pbrook624f7972008-05-31 16:11:38 +0000567 ts->signal_pending = 1;
bellard9de5e442003-03-23 16:49:39 +0000568 return 1; /* indicates that the signal was queued */
569 }
570}
571
ths5fafdf22007-09-16 21:08:06 +0000572static void host_signal_handler(int host_signum, siginfo_t *info,
bellard9de5e442003-03-23 16:49:39 +0000573 void *puc)
574{
Andreas Färbera2247f82013-06-09 19:47:04 +0200575 CPUArchState *env = thread_cpu->env_ptr;
bellard9de5e442003-03-23 16:49:39 +0000576 int sig;
Anthony Liguoric227f092009-10-01 16:12:16 -0500577 target_siginfo_t tinfo;
bellard9de5e442003-03-23 16:49:39 +0000578
579 /* the CPU emulator uses some host signals to detect exceptions,
aurel32eaa449b2009-01-03 13:14:52 +0000580 we forward to it some signals */
aurel32ca587a82008-12-18 22:44:13 +0000581 if ((host_signum == SIGSEGV || host_signum == SIGBUS)
aurel32eaa449b2009-01-03 13:14:52 +0000582 && info->si_code > 0) {
bellardb346ff42003-06-15 20:05:50 +0000583 if (cpu_signal_handler(host_signum, info, puc))
bellard9de5e442003-03-23 16:49:39 +0000584 return;
585 }
586
587 /* get target signal number */
588 sig = host_to_target_signal(host_signum);
589 if (sig < 1 || sig > TARGET_NSIG)
590 return;
591#if defined(DEBUG_SIGNAL)
bellardbc8a22c2003-03-30 21:02:40 +0000592 fprintf(stderr, "qemu: got signal %d\n", sig);
bellard9de5e442003-03-23 16:49:39 +0000593#endif
594 host_to_target_siginfo_noswap(&tinfo, info);
Andreas Färbera2247f82013-06-09 19:47:04 +0200595 if (queue_signal(env, sig, &tinfo) == 1) {
bellard9de5e442003-03-23 16:49:39 +0000596 /* interrupt the virtual CPU as soon as possible */
Andreas Färbera2247f82013-06-09 19:47:04 +0200597 cpu_exit(thread_cpu);
bellard66fb9762003-03-23 01:06:05 +0000598 }
bellard31e31b82003-02-18 22:55:36 +0000599}
600
ths0da46a62007-10-20 20:23:07 +0000601/* do_sigaltstack() returns target values and errnos. */
bellard579a97f2007-11-11 14:26:47 +0000602/* compare linux/kernel/signal.c:do_sigaltstack() */
603abi_long do_sigaltstack(abi_ulong uss_addr, abi_ulong uoss_addr, abi_ulong sp)
thsa04e1342007-09-27 13:57:58 +0000604{
605 int ret;
606 struct target_sigaltstack oss;
607
608 /* XXX: test errors */
bellard579a97f2007-11-11 14:26:47 +0000609 if(uoss_addr)
thsa04e1342007-09-27 13:57:58 +0000610 {
611 __put_user(target_sigaltstack_used.ss_sp, &oss.ss_sp);
612 __put_user(target_sigaltstack_used.ss_size, &oss.ss_size);
613 __put_user(sas_ss_flags(sp), &oss.ss_flags);
614 }
615
bellard579a97f2007-11-11 14:26:47 +0000616 if(uss_addr)
thsa04e1342007-09-27 13:57:58 +0000617 {
bellard579a97f2007-11-11 14:26:47 +0000618 struct target_sigaltstack *uss;
619 struct target_sigaltstack ss;
thsa04e1342007-09-27 13:57:58 +0000620
ths0da46a62007-10-20 20:23:07 +0000621 ret = -TARGET_EFAULT;
Riku Voipio9eeb8302014-04-23 11:26:34 +0300622 if (!lock_user_struct(VERIFY_READ, uss, uss_addr, 1)) {
thsa04e1342007-09-27 13:57:58 +0000623 goto out;
Riku Voipio9eeb8302014-04-23 11:26:34 +0300624 }
625 __get_user(ss.ss_sp, &uss->ss_sp);
626 __get_user(ss.ss_size, &uss->ss_size);
627 __get_user(ss.ss_flags, &uss->ss_flags);
bellard579a97f2007-11-11 14:26:47 +0000628 unlock_user_struct(uss, uss_addr, 0);
thsa04e1342007-09-27 13:57:58 +0000629
ths0da46a62007-10-20 20:23:07 +0000630 ret = -TARGET_EPERM;
thsa04e1342007-09-27 13:57:58 +0000631 if (on_sig_stack(sp))
632 goto out;
633
ths0da46a62007-10-20 20:23:07 +0000634 ret = -TARGET_EINVAL;
thsa04e1342007-09-27 13:57:58 +0000635 if (ss.ss_flags != TARGET_SS_DISABLE
636 && ss.ss_flags != TARGET_SS_ONSTACK
637 && ss.ss_flags != 0)
638 goto out;
639
640 if (ss.ss_flags == TARGET_SS_DISABLE) {
641 ss.ss_size = 0;
642 ss.ss_sp = 0;
643 } else {
ths0da46a62007-10-20 20:23:07 +0000644 ret = -TARGET_ENOMEM;
thsa04e1342007-09-27 13:57:58 +0000645 if (ss.ss_size < MINSIGSTKSZ)
646 goto out;
647 }
648
649 target_sigaltstack_used.ss_sp = ss.ss_sp;
650 target_sigaltstack_used.ss_size = ss.ss_size;
651 }
652
bellard579a97f2007-11-11 14:26:47 +0000653 if (uoss_addr) {
ths0da46a62007-10-20 20:23:07 +0000654 ret = -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +0000655 if (copy_to_user(uoss_addr, &oss, sizeof(oss)))
thsa04e1342007-09-27 13:57:58 +0000656 goto out;
thsa04e1342007-09-27 13:57:58 +0000657 }
658
659 ret = 0;
660out:
661 return ret;
662}
663
ths0da46a62007-10-20 20:23:07 +0000664/* do_sigaction() return host values and errnos */
bellard66fb9762003-03-23 01:06:05 +0000665int do_sigaction(int sig, const struct target_sigaction *act,
666 struct target_sigaction *oact)
bellard31e31b82003-02-18 22:55:36 +0000667{
pbrook624f7972008-05-31 16:11:38 +0000668 struct target_sigaction *k;
bellard773b93e2004-01-04 17:15:59 +0000669 struct sigaction act1;
670 int host_sig;
ths0da46a62007-10-20 20:23:07 +0000671 int ret = 0;
bellard31e31b82003-02-18 22:55:36 +0000672
ths2a913eb2008-11-27 15:46:25 +0000673 if (sig < 1 || sig > TARGET_NSIG || sig == TARGET_SIGKILL || sig == TARGET_SIGSTOP)
bellard66fb9762003-03-23 01:06:05 +0000674 return -EINVAL;
675 k = &sigact_table[sig - 1];
bellard773b93e2004-01-04 17:15:59 +0000676#if defined(DEBUG_SIGNAL)
Blue Swirl0bf9e312009-07-20 17:19:25 +0000677 fprintf(stderr, "sigaction sig=%d act=0x%p, oact=0x%p\n",
678 sig, act, oact);
bellard66fb9762003-03-23 01:06:05 +0000679#endif
680 if (oact) {
Richard Hendersond2565872013-01-04 16:39:32 -0800681 __put_user(k->_sa_handler, &oact->_sa_handler);
682 __put_user(k->sa_flags, &oact->sa_flags);
ths388bb212007-05-13 13:58:00 +0000683#if !defined(TARGET_MIPS)
Richard Hendersond2565872013-01-04 16:39:32 -0800684 __put_user(k->sa_restorer, &oact->sa_restorer);
ths388bb212007-05-13 13:58:00 +0000685#endif
Richard Hendersond2565872013-01-04 16:39:32 -0800686 /* Not swapped. */
pbrook624f7972008-05-31 16:11:38 +0000687 oact->sa_mask = k->sa_mask;
bellard66fb9762003-03-23 01:06:05 +0000688 }
689 if (act) {
pbrook624f7972008-05-31 16:11:38 +0000690 /* FIXME: This is not threadsafe. */
Richard Hendersond2565872013-01-04 16:39:32 -0800691 __get_user(k->_sa_handler, &act->_sa_handler);
692 __get_user(k->sa_flags, &act->sa_flags);
ths388bb212007-05-13 13:58:00 +0000693#if !defined(TARGET_MIPS)
Richard Hendersond2565872013-01-04 16:39:32 -0800694 __get_user(k->sa_restorer, &act->sa_restorer);
ths388bb212007-05-13 13:58:00 +0000695#endif
Richard Hendersond2565872013-01-04 16:39:32 -0800696 /* To be swapped in target_to_host_sigset. */
pbrook624f7972008-05-31 16:11:38 +0000697 k->sa_mask = act->sa_mask;
bellard773b93e2004-01-04 17:15:59 +0000698
699 /* we update the host linux signal state */
700 host_sig = target_to_host_signal(sig);
701 if (host_sig != SIGSEGV && host_sig != SIGBUS) {
702 sigfillset(&act1.sa_mask);
703 act1.sa_flags = SA_SIGINFO;
pbrook624f7972008-05-31 16:11:38 +0000704 if (k->sa_flags & TARGET_SA_RESTART)
bellard773b93e2004-01-04 17:15:59 +0000705 act1.sa_flags |= SA_RESTART;
706 /* NOTE: it is important to update the host kernel signal
707 ignore state to avoid getting unexpected interrupted
708 syscalls */
pbrook624f7972008-05-31 16:11:38 +0000709 if (k->_sa_handler == TARGET_SIG_IGN) {
bellard773b93e2004-01-04 17:15:59 +0000710 act1.sa_sigaction = (void *)SIG_IGN;
pbrook624f7972008-05-31 16:11:38 +0000711 } else if (k->_sa_handler == TARGET_SIG_DFL) {
aurel32ca587a82008-12-18 22:44:13 +0000712 if (fatal_signal (sig))
713 act1.sa_sigaction = host_signal_handler;
714 else
715 act1.sa_sigaction = (void *)SIG_DFL;
bellard773b93e2004-01-04 17:15:59 +0000716 } else {
717 act1.sa_sigaction = host_signal_handler;
718 }
ths0da46a62007-10-20 20:23:07 +0000719 ret = sigaction(host_sig, &act1, NULL);
bellard773b93e2004-01-04 17:15:59 +0000720 }
bellard66fb9762003-03-23 01:06:05 +0000721 }
ths0da46a62007-10-20 20:23:07 +0000722 return ret;
bellard66fb9762003-03-23 01:06:05 +0000723}
bellard31e31b82003-02-18 22:55:36 +0000724
Riku Voipiob0fd8d12014-04-23 10:46:13 +0300725static inline void copy_siginfo_to_user(target_siginfo_t *tinfo,
Anthony Liguoric227f092009-10-01 16:12:16 -0500726 const target_siginfo_t *info)
bellard43fff232003-07-09 19:31:39 +0000727{
728 tswap_siginfo(tinfo, info);
bellard43fff232003-07-09 19:31:39 +0000729}
730
thsc3b5bc82007-12-02 06:31:25 +0000731static inline int current_exec_domain_sig(int sig)
732{
733 return /* current->exec_domain && current->exec_domain->signal_invmap
734 && sig < 32 ? current->exec_domain->signal_invmap[sig] : */ sig;
735}
736
bellard459a4012007-11-11 19:45:10 +0000737#if defined(TARGET_I386) && TARGET_ABI_BITS == 32
bellard66fb9762003-03-23 01:06:05 +0000738
739/* from the Linux kernel */
740
741struct target_fpreg {
742 uint16_t significand[4];
743 uint16_t exponent;
744};
745
746struct target_fpxreg {
747 uint16_t significand[4];
748 uint16_t exponent;
749 uint16_t padding[3];
750};
751
752struct target_xmmreg {
blueswir1992f48a2007-10-14 16:27:31 +0000753 abi_ulong element[4];
bellard66fb9762003-03-23 01:06:05 +0000754};
755
756struct target_fpstate {
757 /* Regular FPU environment */
blueswir1992f48a2007-10-14 16:27:31 +0000758 abi_ulong cw;
759 abi_ulong sw;
760 abi_ulong tag;
761 abi_ulong ipoff;
762 abi_ulong cssel;
763 abi_ulong dataoff;
764 abi_ulong datasel;
bellard66fb9762003-03-23 01:06:05 +0000765 struct target_fpreg _st[8];
766 uint16_t status;
767 uint16_t magic; /* 0xffff = regular FPU data only */
768
769 /* FXSR FPU environment */
blueswir1992f48a2007-10-14 16:27:31 +0000770 abi_ulong _fxsr_env[6]; /* FXSR FPU env is ignored */
771 abi_ulong mxcsr;
772 abi_ulong reserved;
bellard66fb9762003-03-23 01:06:05 +0000773 struct target_fpxreg _fxsr_st[8]; /* FXSR FPU reg data is ignored */
774 struct target_xmmreg _xmm[8];
blueswir1992f48a2007-10-14 16:27:31 +0000775 abi_ulong padding[56];
bellard66fb9762003-03-23 01:06:05 +0000776};
777
778#define X86_FXSR_MAGIC 0x0000
779
780struct target_sigcontext {
781 uint16_t gs, __gsh;
782 uint16_t fs, __fsh;
783 uint16_t es, __esh;
784 uint16_t ds, __dsh;
blueswir1992f48a2007-10-14 16:27:31 +0000785 abi_ulong edi;
786 abi_ulong esi;
787 abi_ulong ebp;
788 abi_ulong esp;
789 abi_ulong ebx;
790 abi_ulong edx;
791 abi_ulong ecx;
792 abi_ulong eax;
793 abi_ulong trapno;
794 abi_ulong err;
795 abi_ulong eip;
bellard66fb9762003-03-23 01:06:05 +0000796 uint16_t cs, __csh;
blueswir1992f48a2007-10-14 16:27:31 +0000797 abi_ulong eflags;
798 abi_ulong esp_at_signal;
bellard66fb9762003-03-23 01:06:05 +0000799 uint16_t ss, __ssh;
blueswir1992f48a2007-10-14 16:27:31 +0000800 abi_ulong fpstate; /* pointer */
801 abi_ulong oldmask;
802 abi_ulong cr2;
bellard66fb9762003-03-23 01:06:05 +0000803};
804
bellard66fb9762003-03-23 01:06:05 +0000805struct target_ucontext {
blueswir1992f48a2007-10-14 16:27:31 +0000806 abi_ulong tuc_flags;
807 abi_ulong tuc_link;
Anthony Liguoric227f092009-10-01 16:12:16 -0500808 target_stack_t tuc_stack;
bellardb8076a72005-04-07 22:20:31 +0000809 struct target_sigcontext tuc_mcontext;
Anthony Liguoric227f092009-10-01 16:12:16 -0500810 target_sigset_t tuc_sigmask; /* mask last for extensibility */
bellard66fb9762003-03-23 01:06:05 +0000811};
812
813struct sigframe
814{
blueswir1992f48a2007-10-14 16:27:31 +0000815 abi_ulong pretcode;
bellard66fb9762003-03-23 01:06:05 +0000816 int sig;
817 struct target_sigcontext sc;
818 struct target_fpstate fpstate;
blueswir1992f48a2007-10-14 16:27:31 +0000819 abi_ulong extramask[TARGET_NSIG_WORDS-1];
bellard66fb9762003-03-23 01:06:05 +0000820 char retcode[8];
821};
822
823struct rt_sigframe
824{
blueswir1992f48a2007-10-14 16:27:31 +0000825 abi_ulong pretcode;
bellard66fb9762003-03-23 01:06:05 +0000826 int sig;
blueswir1992f48a2007-10-14 16:27:31 +0000827 abi_ulong pinfo;
828 abi_ulong puc;
bellard66fb9762003-03-23 01:06:05 +0000829 struct target_siginfo info;
830 struct target_ucontext uc;
831 struct target_fpstate fpstate;
832 char retcode[8];
833};
834
835/*
836 * Set up a signal frame.
837 */
838
bellard66fb9762003-03-23 01:06:05 +0000839/* XXX: save x87 state */
Riku Voipio41ecc722014-04-23 11:01:00 +0300840static void setup_sigcontext(struct target_sigcontext *sc,
841 struct target_fpstate *fpstate, CPUX86State *env, abi_ulong mask,
842 abi_ulong fpstate_addr)
bellard66fb9762003-03-23 01:06:05 +0000843{
Andreas Färber27103422013-08-26 08:31:06 +0200844 CPUState *cs = CPU(x86_env_get_cpu(env));
Andreas Färber27103422013-08-26 08:31:06 +0200845 uint16_t magic;
bellard66fb9762003-03-23 01:06:05 +0000846
bellard579a97f2007-11-11 14:26:47 +0000847 /* already locked in setup_frame() */
Riku Voipio1d8b5122014-04-23 10:26:05 +0300848 __put_user(env->segs[R_GS].selector, (unsigned int *)&sc->gs);
849 __put_user(env->segs[R_FS].selector, (unsigned int *)&sc->fs);
850 __put_user(env->segs[R_ES].selector, (unsigned int *)&sc->es);
851 __put_user(env->segs[R_DS].selector, (unsigned int *)&sc->ds);
852 __put_user(env->regs[R_EDI], &sc->edi);
853 __put_user(env->regs[R_ESI], &sc->esi);
854 __put_user(env->regs[R_EBP], &sc->ebp);
855 __put_user(env->regs[R_ESP], &sc->esp);
856 __put_user(env->regs[R_EBX], &sc->ebx);
857 __put_user(env->regs[R_EDX], &sc->edx);
858 __put_user(env->regs[R_ECX], &sc->ecx);
859 __put_user(env->regs[R_EAX], &sc->eax);
860 __put_user(cs->exception_index, &sc->trapno);
861 __put_user(env->error_code, &sc->err);
862 __put_user(env->eip, &sc->eip);
863 __put_user(env->segs[R_CS].selector, (unsigned int *)&sc->cs);
864 __put_user(env->eflags, &sc->eflags);
865 __put_user(env->regs[R_ESP], &sc->esp_at_signal);
866 __put_user(env->segs[R_SS].selector, (unsigned int *)&sc->ss);
bellarded2dcdf2003-05-29 20:06:27 +0000867
bellard28be6232007-11-11 22:23:38 +0000868 cpu_x86_fsave(env, fpstate_addr, 1);
bellarded2dcdf2003-05-29 20:06:27 +0000869 fpstate->status = fpstate->sw;
bellard775b58d2007-11-11 16:22:17 +0000870 magic = 0xffff;
Riku Voipio1d8b5122014-04-23 10:26:05 +0300871 __put_user(magic, &fpstate->magic);
872 __put_user(fpstate_addr, &sc->fpstate);
bellarded2dcdf2003-05-29 20:06:27 +0000873
bellard66fb9762003-03-23 01:06:05 +0000874 /* non-iBCS2 extensions.. */
Riku Voipio1d8b5122014-04-23 10:26:05 +0300875 __put_user(mask, &sc->oldmask);
876 __put_user(env->cr[2], &sc->cr2);
bellard66fb9762003-03-23 01:06:05 +0000877}
878
879/*
880 * Determine which stack to use..
881 */
882
bellard579a97f2007-11-11 14:26:47 +0000883static inline abi_ulong
pbrook624f7972008-05-31 16:11:38 +0000884get_sigframe(struct target_sigaction *ka, CPUX86State *env, size_t frame_size)
bellard66fb9762003-03-23 01:06:05 +0000885{
886 unsigned long esp;
887
888 /* Default to using normal stack */
889 esp = env->regs[R_ESP];
bellard66fb9762003-03-23 01:06:05 +0000890 /* This is the X/Open sanctioned signal stack switching. */
pbrook624f7972008-05-31 16:11:38 +0000891 if (ka->sa_flags & TARGET_SA_ONSTACK) {
thsa04e1342007-09-27 13:57:58 +0000892 if (sas_ss_flags(esp) == 0)
893 esp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
894 }
bellard66fb9762003-03-23 01:06:05 +0000895
896 /* This is the legacy signal stack switching. */
ths5fafdf22007-09-16 21:08:06 +0000897 else
bellarda52c7572003-06-21 13:14:12 +0000898 if ((env->segs[R_SS].selector & 0xffff) != __USER_DS &&
pbrook624f7972008-05-31 16:11:38 +0000899 !(ka->sa_flags & TARGET_SA_RESTORER) &&
900 ka->sa_restorer) {
901 esp = (unsigned long) ka->sa_restorer;
bellarda52c7572003-06-21 13:14:12 +0000902 }
bellard579a97f2007-11-11 14:26:47 +0000903 return (esp - frame_size) & -8ul;
bellard66fb9762003-03-23 01:06:05 +0000904}
905
bellard579a97f2007-11-11 14:26:47 +0000906/* compare linux/arch/i386/kernel/signal.c:setup_frame() */
pbrook624f7972008-05-31 16:11:38 +0000907static void setup_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -0500908 target_sigset_t *set, CPUX86State *env)
bellard66fb9762003-03-23 01:06:05 +0000909{
bellard579a97f2007-11-11 14:26:47 +0000910 abi_ulong frame_addr;
bellard66fb9762003-03-23 01:06:05 +0000911 struct sigframe *frame;
Riku Voipio7df2fa32014-04-23 10:34:53 +0300912 int i;
bellard66fb9762003-03-23 01:06:05 +0000913
bellard579a97f2007-11-11 14:26:47 +0000914 frame_addr = get_sigframe(ka, env, sizeof(*frame));
bellard66fb9762003-03-23 01:06:05 +0000915
bellard579a97f2007-11-11 14:26:47 +0000916 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
bellard66fb9762003-03-23 01:06:05 +0000917 goto give_sigsegv;
bellard579a97f2007-11-11 14:26:47 +0000918
Riku Voipio1d8b5122014-04-23 10:26:05 +0300919 __put_user(current_exec_domain_sig(sig),
920 &frame->sig);
bellard66fb9762003-03-23 01:06:05 +0000921
bellard28be6232007-11-11 22:23:38 +0000922 setup_sigcontext(&frame->sc, &frame->fpstate, env, set->sig[0],
923 frame_addr + offsetof(struct sigframe, fpstate));
bellard66fb9762003-03-23 01:06:05 +0000924
Riku Voipio7df2fa32014-04-23 10:34:53 +0300925 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
926 __put_user(set->sig[i], &frame->extramask[i - 1]);
927 }
bellard66fb9762003-03-23 01:06:05 +0000928
929 /* Set up to return from userspace. If provided, use a stub
930 already in userspace. */
pbrook624f7972008-05-31 16:11:38 +0000931 if (ka->sa_flags & TARGET_SA_RESTORER) {
Riku Voipio1d8b5122014-04-23 10:26:05 +0300932 __put_user(ka->sa_restorer, &frame->pretcode);
bellard66fb9762003-03-23 01:06:05 +0000933 } else {
bellard775b58d2007-11-11 16:22:17 +0000934 uint16_t val16;
bellard28be6232007-11-11 22:23:38 +0000935 abi_ulong retcode_addr;
936 retcode_addr = frame_addr + offsetof(struct sigframe, retcode);
Riku Voipio1d8b5122014-04-23 10:26:05 +0300937 __put_user(retcode_addr, &frame->pretcode);
bellard66fb9762003-03-23 01:06:05 +0000938 /* This is popl %eax ; movl $,%eax ; int $0x80 */
bellard775b58d2007-11-11 16:22:17 +0000939 val16 = 0xb858;
Riku Voipio1d8b5122014-04-23 10:26:05 +0300940 __put_user(val16, (uint16_t *)(frame->retcode+0));
941 __put_user(TARGET_NR_sigreturn, (int *)(frame->retcode+2));
bellard775b58d2007-11-11 16:22:17 +0000942 val16 = 0x80cd;
Riku Voipio1d8b5122014-04-23 10:26:05 +0300943 __put_user(val16, (uint16_t *)(frame->retcode+6));
bellard66fb9762003-03-23 01:06:05 +0000944 }
945
bellard66fb9762003-03-23 01:06:05 +0000946
947 /* Set up registers for signal handler */
bellard28be6232007-11-11 22:23:38 +0000948 env->regs[R_ESP] = frame_addr;
pbrook624f7972008-05-31 16:11:38 +0000949 env->eip = ka->_sa_handler;
bellard66fb9762003-03-23 01:06:05 +0000950
951 cpu_x86_load_seg(env, R_DS, __USER_DS);
952 cpu_x86_load_seg(env, R_ES, __USER_DS);
953 cpu_x86_load_seg(env, R_SS, __USER_DS);
954 cpu_x86_load_seg(env, R_CS, __USER_CS);
955 env->eflags &= ~TF_MASK;
956
bellard579a97f2007-11-11 14:26:47 +0000957 unlock_user_struct(frame, frame_addr, 1);
958
bellard66fb9762003-03-23 01:06:05 +0000959 return;
960
961give_sigsegv:
962 if (sig == TARGET_SIGSEGV)
pbrook624f7972008-05-31 16:11:38 +0000963 ka->_sa_handler = TARGET_SIG_DFL;
bellard66fb9762003-03-23 01:06:05 +0000964 force_sig(TARGET_SIGSEGV /* , current */);
965}
966
bellard579a97f2007-11-11 14:26:47 +0000967/* compare linux/arch/i386/kernel/signal.c:setup_rt_frame() */
pbrook624f7972008-05-31 16:11:38 +0000968static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -0500969 target_siginfo_t *info,
970 target_sigset_t *set, CPUX86State *env)
bellard66fb9762003-03-23 01:06:05 +0000971{
bellard28be6232007-11-11 22:23:38 +0000972 abi_ulong frame_addr, addr;
bellard66fb9762003-03-23 01:06:05 +0000973 struct rt_sigframe *frame;
bellard92319442004-06-19 16:58:13 +0000974 int i, err = 0;
bellard66fb9762003-03-23 01:06:05 +0000975
bellard579a97f2007-11-11 14:26:47 +0000976 frame_addr = get_sigframe(ka, env, sizeof(*frame));
bellard66fb9762003-03-23 01:06:05 +0000977
bellard579a97f2007-11-11 14:26:47 +0000978 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
bellard66fb9762003-03-23 01:06:05 +0000979 goto give_sigsegv;
bellard66fb9762003-03-23 01:06:05 +0000980
Riku Voipio1d8b5122014-04-23 10:26:05 +0300981 __put_user(current_exec_domain_sig(sig), &frame->sig);
bellard28be6232007-11-11 22:23:38 +0000982 addr = frame_addr + offsetof(struct rt_sigframe, info);
Riku Voipio1d8b5122014-04-23 10:26:05 +0300983 __put_user(addr, &frame->pinfo);
bellard28be6232007-11-11 22:23:38 +0000984 addr = frame_addr + offsetof(struct rt_sigframe, uc);
Riku Voipio1d8b5122014-04-23 10:26:05 +0300985 __put_user(addr, &frame->puc);
Riku Voipiob0fd8d12014-04-23 10:46:13 +0300986 copy_siginfo_to_user(&frame->info, info);
bellard66fb9762003-03-23 01:06:05 +0000987
988 /* Create the ucontext. */
Riku Voipio1d8b5122014-04-23 10:26:05 +0300989 __put_user(0, &frame->uc.tuc_flags);
990 __put_user(0, &frame->uc.tuc_link);
991 __put_user(target_sigaltstack_used.ss_sp, &frame->uc.tuc_stack.ss_sp);
992 __put_user(sas_ss_flags(get_sp_from_cpustate(env)),
993 &frame->uc.tuc_stack.ss_flags);
994 __put_user(target_sigaltstack_used.ss_size,
995 &frame->uc.tuc_stack.ss_size);
Riku Voipio41ecc722014-04-23 11:01:00 +0300996 setup_sigcontext(&frame->uc.tuc_mcontext, &frame->fpstate, env,
997 set->sig[0], frame_addr + offsetof(struct rt_sigframe, fpstate));
998
bellard92319442004-06-19 16:58:13 +0000999 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
bellardb8076a72005-04-07 22:20:31 +00001000 if (__put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]))
bellard92319442004-06-19 16:58:13 +00001001 goto give_sigsegv;
1002 }
bellard66fb9762003-03-23 01:06:05 +00001003
1004 /* Set up to return from userspace. If provided, use a stub
1005 already in userspace. */
pbrook624f7972008-05-31 16:11:38 +00001006 if (ka->sa_flags & TARGET_SA_RESTORER) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03001007 __put_user(ka->sa_restorer, &frame->pretcode);
bellard66fb9762003-03-23 01:06:05 +00001008 } else {
bellard775b58d2007-11-11 16:22:17 +00001009 uint16_t val16;
bellard28be6232007-11-11 22:23:38 +00001010 addr = frame_addr + offsetof(struct rt_sigframe, retcode);
Riku Voipio1d8b5122014-04-23 10:26:05 +03001011 __put_user(addr, &frame->pretcode);
bellard66fb9762003-03-23 01:06:05 +00001012 /* This is movl $,%eax ; int $0x80 */
Riku Voipio1d8b5122014-04-23 10:26:05 +03001013 __put_user(0xb8, (char *)(frame->retcode+0));
1014 __put_user(TARGET_NR_rt_sigreturn, (int *)(frame->retcode+1));
bellard775b58d2007-11-11 16:22:17 +00001015 val16 = 0x80cd;
Riku Voipio1d8b5122014-04-23 10:26:05 +03001016 __put_user(val16, (uint16_t *)(frame->retcode+5));
bellard66fb9762003-03-23 01:06:05 +00001017 }
1018
1019 if (err)
1020 goto give_sigsegv;
1021
1022 /* Set up registers for signal handler */
bellard28be6232007-11-11 22:23:38 +00001023 env->regs[R_ESP] = frame_addr;
pbrook624f7972008-05-31 16:11:38 +00001024 env->eip = ka->_sa_handler;
bellard66fb9762003-03-23 01:06:05 +00001025
1026 cpu_x86_load_seg(env, R_DS, __USER_DS);
1027 cpu_x86_load_seg(env, R_ES, __USER_DS);
1028 cpu_x86_load_seg(env, R_SS, __USER_DS);
1029 cpu_x86_load_seg(env, R_CS, __USER_CS);
1030 env->eflags &= ~TF_MASK;
1031
bellard579a97f2007-11-11 14:26:47 +00001032 unlock_user_struct(frame, frame_addr, 1);
1033
bellard66fb9762003-03-23 01:06:05 +00001034 return;
1035
1036give_sigsegv:
bellard579a97f2007-11-11 14:26:47 +00001037 unlock_user_struct(frame, frame_addr, 1);
bellard66fb9762003-03-23 01:06:05 +00001038 if (sig == TARGET_SIGSEGV)
pbrook624f7972008-05-31 16:11:38 +00001039 ka->_sa_handler = TARGET_SIG_DFL;
bellard66fb9762003-03-23 01:06:05 +00001040 force_sig(TARGET_SIGSEGV /* , current */);
1041}
1042
1043static int
1044restore_sigcontext(CPUX86State *env, struct target_sigcontext *sc, int *peax)
1045{
1046 unsigned int err = 0;
bellard28be6232007-11-11 22:23:38 +00001047 abi_ulong fpstate_addr;
1048 unsigned int tmpflags;
bellard66fb9762003-03-23 01:06:05 +00001049
bellard28be6232007-11-11 22:23:38 +00001050 cpu_x86_load_seg(env, R_GS, tswap16(sc->gs));
1051 cpu_x86_load_seg(env, R_FS, tswap16(sc->fs));
1052 cpu_x86_load_seg(env, R_ES, tswap16(sc->es));
1053 cpu_x86_load_seg(env, R_DS, tswap16(sc->ds));
bellard66fb9762003-03-23 01:06:05 +00001054
bellard28be6232007-11-11 22:23:38 +00001055 env->regs[R_EDI] = tswapl(sc->edi);
1056 env->regs[R_ESI] = tswapl(sc->esi);
1057 env->regs[R_EBP] = tswapl(sc->ebp);
1058 env->regs[R_ESP] = tswapl(sc->esp);
1059 env->regs[R_EBX] = tswapl(sc->ebx);
1060 env->regs[R_EDX] = tswapl(sc->edx);
1061 env->regs[R_ECX] = tswapl(sc->ecx);
1062 env->eip = tswapl(sc->eip);
bellard66fb9762003-03-23 01:06:05 +00001063
Mike McCormack9a826d72011-06-01 15:14:37 +09001064 cpu_x86_load_seg(env, R_CS, lduw_p(&sc->cs) | 3);
1065 cpu_x86_load_seg(env, R_SS, lduw_p(&sc->ss) | 3);
ths5fafdf22007-09-16 21:08:06 +00001066
bellard28be6232007-11-11 22:23:38 +00001067 tmpflags = tswapl(sc->eflags);
1068 env->eflags = (env->eflags & ~0x40DD5) | (tmpflags & 0x40DD5);
1069 // regs->orig_eax = -1; /* disable syscall checks */
1070
1071 fpstate_addr = tswapl(sc->fpstate);
1072 if (fpstate_addr != 0) {
1073 if (!access_ok(VERIFY_READ, fpstate_addr,
1074 sizeof(struct target_fpstate)))
1075 goto badframe;
1076 cpu_x86_frstor(env, fpstate_addr, 1);
bellard66fb9762003-03-23 01:06:05 +00001077 }
1078
bellard28be6232007-11-11 22:23:38 +00001079 *peax = tswapl(sc->eax);
bellard66fb9762003-03-23 01:06:05 +00001080 return err;
bellard66fb9762003-03-23 01:06:05 +00001081badframe:
1082 return 1;
bellard66fb9762003-03-23 01:06:05 +00001083}
1084
1085long do_sigreturn(CPUX86State *env)
1086{
bellard579a97f2007-11-11 14:26:47 +00001087 struct sigframe *frame;
1088 abi_ulong frame_addr = env->regs[R_ESP] - 8;
Anthony Liguoric227f092009-10-01 16:12:16 -05001089 target_sigset_t target_set;
bellard66fb9762003-03-23 01:06:05 +00001090 sigset_t set;
1091 int eax, i;
1092
bellard447db212003-05-10 15:10:36 +00001093#if defined(DEBUG_SIGNAL)
1094 fprintf(stderr, "do_sigreturn\n");
1095#endif
bellard579a97f2007-11-11 14:26:47 +00001096 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
1097 goto badframe;
bellard66fb9762003-03-23 01:06:05 +00001098 /* set blocked signals */
bellard92319442004-06-19 16:58:13 +00001099 if (__get_user(target_set.sig[0], &frame->sc.oldmask))
1100 goto badframe;
1101 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
1102 if (__get_user(target_set.sig[i], &frame->extramask[i - 1]))
1103 goto badframe;
1104 }
bellard66fb9762003-03-23 01:06:05 +00001105
bellard92319442004-06-19 16:58:13 +00001106 target_to_host_sigset_internal(&set, &target_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00001107 do_sigprocmask(SIG_SETMASK, &set, NULL);
ths3b46e622007-09-17 08:09:54 +00001108
bellard66fb9762003-03-23 01:06:05 +00001109 /* restore registers */
1110 if (restore_sigcontext(env, &frame->sc, &eax))
1111 goto badframe;
bellard579a97f2007-11-11 14:26:47 +00001112 unlock_user_struct(frame, frame_addr, 0);
bellard66fb9762003-03-23 01:06:05 +00001113 return eax;
1114
1115badframe:
bellard579a97f2007-11-11 14:26:47 +00001116 unlock_user_struct(frame, frame_addr, 0);
bellard66fb9762003-03-23 01:06:05 +00001117 force_sig(TARGET_SIGSEGV);
1118 return 0;
1119}
1120
1121long do_rt_sigreturn(CPUX86State *env)
1122{
bellard28be6232007-11-11 22:23:38 +00001123 abi_ulong frame_addr;
1124 struct rt_sigframe *frame;
bellard66fb9762003-03-23 01:06:05 +00001125 sigset_t set;
bellard66fb9762003-03-23 01:06:05 +00001126 int eax;
1127
bellard28be6232007-11-11 22:23:38 +00001128 frame_addr = env->regs[R_ESP] - 4;
1129 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
1130 goto badframe;
bellardb8076a72005-04-07 22:20:31 +00001131 target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
Alex Barcelo1c275922014-03-14 14:36:55 +00001132 do_sigprocmask(SIG_SETMASK, &set, NULL);
ths5fafdf22007-09-16 21:08:06 +00001133
bellardb8076a72005-04-07 22:20:31 +00001134 if (restore_sigcontext(env, &frame->uc.tuc_mcontext, &eax))
bellard66fb9762003-03-23 01:06:05 +00001135 goto badframe;
1136
bellard28be6232007-11-11 22:23:38 +00001137 if (do_sigaltstack(frame_addr + offsetof(struct rt_sigframe, uc.tuc_stack), 0,
1138 get_sp_from_cpustate(env)) == -EFAULT)
bellard66fb9762003-03-23 01:06:05 +00001139 goto badframe;
thsa04e1342007-09-27 13:57:58 +00001140
bellard28be6232007-11-11 22:23:38 +00001141 unlock_user_struct(frame, frame_addr, 0);
bellard66fb9762003-03-23 01:06:05 +00001142 return eax;
1143
1144badframe:
bellard28be6232007-11-11 22:23:38 +00001145 unlock_user_struct(frame, frame_addr, 0);
1146 force_sig(TARGET_SIGSEGV);
bellard66fb9762003-03-23 01:06:05 +00001147 return 0;
1148}
1149
Andreas Schwab1744aea2013-09-03 20:12:16 +01001150#elif defined(TARGET_AARCH64)
1151
1152struct target_sigcontext {
1153 uint64_t fault_address;
1154 /* AArch64 registers */
1155 uint64_t regs[31];
1156 uint64_t sp;
1157 uint64_t pc;
1158 uint64_t pstate;
1159 /* 4K reserved for FP/SIMD state and future expansion */
1160 char __reserved[4096] __attribute__((__aligned__(16)));
1161};
1162
1163struct target_ucontext {
1164 abi_ulong tuc_flags;
1165 abi_ulong tuc_link;
1166 target_stack_t tuc_stack;
1167 target_sigset_t tuc_sigmask;
1168 /* glibc uses a 1024-bit sigset_t */
1169 char __unused[1024 / 8 - sizeof(target_sigset_t)];
1170 /* last for future expansion */
1171 struct target_sigcontext tuc_mcontext;
1172};
1173
1174/*
1175 * Header to be used at the beginning of structures extending the user
1176 * context. Such structures must be placed after the rt_sigframe on the stack
1177 * and be 16-byte aligned. The last structure must be a dummy one with the
1178 * magic and size set to 0.
1179 */
1180struct target_aarch64_ctx {
1181 uint32_t magic;
1182 uint32_t size;
1183};
1184
1185#define TARGET_FPSIMD_MAGIC 0x46508001
1186
1187struct target_fpsimd_context {
1188 struct target_aarch64_ctx head;
1189 uint32_t fpsr;
1190 uint32_t fpcr;
1191 uint64_t vregs[32 * 2]; /* really uint128_t vregs[32] */
1192};
1193
1194/*
1195 * Auxiliary context saved in the sigcontext.__reserved array. Not exported to
1196 * user space as it will change with the addition of new context. User space
1197 * should check the magic/size information.
1198 */
1199struct target_aux_context {
1200 struct target_fpsimd_context fpsimd;
1201 /* additional context to be added before "end" */
1202 struct target_aarch64_ctx end;
1203};
1204
1205struct target_rt_sigframe {
1206 struct target_siginfo info;
1207 struct target_ucontext uc;
1208 uint64_t fp;
1209 uint64_t lr;
1210 uint32_t tramp[2];
1211};
1212
1213static int target_setup_sigframe(struct target_rt_sigframe *sf,
1214 CPUARMState *env, target_sigset_t *set)
1215{
1216 int i;
1217 struct target_aux_context *aux =
1218 (struct target_aux_context *)sf->uc.tuc_mcontext.__reserved;
1219
1220 /* set up the stack frame for unwinding */
1221 __put_user(env->xregs[29], &sf->fp);
1222 __put_user(env->xregs[30], &sf->lr);
1223
1224 for (i = 0; i < 31; i++) {
1225 __put_user(env->xregs[i], &sf->uc.tuc_mcontext.regs[i]);
1226 }
1227 __put_user(env->xregs[31], &sf->uc.tuc_mcontext.sp);
1228 __put_user(env->pc, &sf->uc.tuc_mcontext.pc);
Peter Maydelld3563122013-12-17 19:42:30 +00001229 __put_user(pstate_read(env), &sf->uc.tuc_mcontext.pstate);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001230
Peter Maydell7af03922014-05-01 18:36:17 +01001231 __put_user(env->exception.vaddress, &sf->uc.tuc_mcontext.fault_address);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001232
1233 for (i = 0; i < TARGET_NSIG_WORDS; i++) {
1234 __put_user(set->sig[i], &sf->uc.tuc_sigmask.sig[i]);
1235 }
1236
1237 for (i = 0; i < 32; i++) {
1238#ifdef TARGET_WORDS_BIGENDIAN
1239 __put_user(env->vfp.regs[i * 2], &aux->fpsimd.vregs[i * 2 + 1]);
1240 __put_user(env->vfp.regs[i * 2 + 1], &aux->fpsimd.vregs[i * 2]);
1241#else
1242 __put_user(env->vfp.regs[i * 2], &aux->fpsimd.vregs[i * 2]);
1243 __put_user(env->vfp.regs[i * 2 + 1], &aux->fpsimd.vregs[i * 2 + 1]);
1244#endif
1245 }
Will Newtone0ee1382014-01-04 22:15:48 +00001246 __put_user(vfp_get_fpsr(env), &aux->fpsimd.fpsr);
1247 __put_user(vfp_get_fpcr(env), &aux->fpsimd.fpcr);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001248 __put_user(TARGET_FPSIMD_MAGIC, &aux->fpsimd.head.magic);
1249 __put_user(sizeof(struct target_fpsimd_context),
1250 &aux->fpsimd.head.size);
1251
1252 /* set the "end" magic */
1253 __put_user(0, &aux->end.magic);
1254 __put_user(0, &aux->end.size);
1255
1256 return 0;
1257}
1258
1259static int target_restore_sigframe(CPUARMState *env,
1260 struct target_rt_sigframe *sf)
1261{
1262 sigset_t set;
1263 int i;
1264 struct target_aux_context *aux =
1265 (struct target_aux_context *)sf->uc.tuc_mcontext.__reserved;
Will Newtone0ee1382014-01-04 22:15:48 +00001266 uint32_t magic, size, fpsr, fpcr;
Peter Maydelld3563122013-12-17 19:42:30 +00001267 uint64_t pstate;
Andreas Schwab1744aea2013-09-03 20:12:16 +01001268
1269 target_to_host_sigset(&set, &sf->uc.tuc_sigmask);
Alex Barcelo1c275922014-03-14 14:36:55 +00001270 do_sigprocmask(SIG_SETMASK, &set, NULL);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001271
1272 for (i = 0; i < 31; i++) {
1273 __get_user(env->xregs[i], &sf->uc.tuc_mcontext.regs[i]);
1274 }
1275
1276 __get_user(env->xregs[31], &sf->uc.tuc_mcontext.sp);
1277 __get_user(env->pc, &sf->uc.tuc_mcontext.pc);
Peter Maydelld3563122013-12-17 19:42:30 +00001278 __get_user(pstate, &sf->uc.tuc_mcontext.pstate);
1279 pstate_write(env, pstate);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001280
1281 __get_user(magic, &aux->fpsimd.head.magic);
1282 __get_user(size, &aux->fpsimd.head.size);
1283
1284 if (magic != TARGET_FPSIMD_MAGIC
1285 || size != sizeof(struct target_fpsimd_context)) {
1286 return 1;
1287 }
1288
Peter Maydell4cf23482014-03-02 19:36:38 +00001289 for (i = 0; i < 32; i++) {
1290#ifdef TARGET_WORDS_BIGENDIAN
1291 __get_user(env->vfp.regs[i * 2], &aux->fpsimd.vregs[i * 2 + 1]);
1292 __get_user(env->vfp.regs[i * 2 + 1], &aux->fpsimd.vregs[i * 2]);
1293#else
1294 __get_user(env->vfp.regs[i * 2], &aux->fpsimd.vregs[i * 2]);
1295 __get_user(env->vfp.regs[i * 2 + 1], &aux->fpsimd.vregs[i * 2 + 1]);
1296#endif
Andreas Schwab1744aea2013-09-03 20:12:16 +01001297 }
Will Newtone0ee1382014-01-04 22:15:48 +00001298 __get_user(fpsr, &aux->fpsimd.fpsr);
1299 vfp_set_fpsr(env, fpsr);
1300 __get_user(fpcr, &aux->fpsimd.fpcr);
1301 vfp_set_fpcr(env, fpcr);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001302
1303 return 0;
1304}
1305
1306static abi_ulong get_sigframe(struct target_sigaction *ka, CPUARMState *env)
1307{
1308 abi_ulong sp;
1309
1310 sp = env->xregs[31];
1311
1312 /*
1313 * This is the X/Open sanctioned signal stack switching.
1314 */
1315 if ((ka->sa_flags & SA_ONSTACK) && !sas_ss_flags(sp)) {
1316 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
1317 }
1318
1319 sp = (sp - sizeof(struct target_rt_sigframe)) & ~15;
1320
1321 return sp;
1322}
1323
1324static void target_setup_frame(int usig, struct target_sigaction *ka,
1325 target_siginfo_t *info, target_sigset_t *set,
1326 CPUARMState *env)
1327{
1328 struct target_rt_sigframe *frame;
Michael Matz8a3ae912014-03-02 19:36:39 +00001329 abi_ulong frame_addr, return_addr;
Andreas Schwab1744aea2013-09-03 20:12:16 +01001330
1331 frame_addr = get_sigframe(ka, env);
1332 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
1333 goto give_sigsegv;
1334 }
1335
1336 __put_user(0, &frame->uc.tuc_flags);
1337 __put_user(0, &frame->uc.tuc_link);
1338
1339 __put_user(target_sigaltstack_used.ss_sp,
1340 &frame->uc.tuc_stack.ss_sp);
1341 __put_user(sas_ss_flags(env->xregs[31]),
1342 &frame->uc.tuc_stack.ss_flags);
1343 __put_user(target_sigaltstack_used.ss_size,
1344 &frame->uc.tuc_stack.ss_size);
1345 target_setup_sigframe(frame, env, set);
Michael Matz8a3ae912014-03-02 19:36:39 +00001346 if (ka->sa_flags & TARGET_SA_RESTORER) {
1347 return_addr = ka->sa_restorer;
1348 } else {
1349 /* mov x8,#__NR_rt_sigreturn; svc #0 */
1350 __put_user(0xd2801168, &frame->tramp[0]);
1351 __put_user(0xd4000001, &frame->tramp[1]);
1352 return_addr = frame_addr + offsetof(struct target_rt_sigframe, tramp);
1353 }
Andreas Schwab1744aea2013-09-03 20:12:16 +01001354 env->xregs[0] = usig;
1355 env->xregs[31] = frame_addr;
1356 env->xregs[29] = env->xregs[31] + offsetof(struct target_rt_sigframe, fp);
1357 env->pc = ka->_sa_handler;
Michael Matz8a3ae912014-03-02 19:36:39 +00001358 env->xregs[30] = return_addr;
Andreas Schwab1744aea2013-09-03 20:12:16 +01001359 if (info) {
Riku Voipiob0fd8d12014-04-23 10:46:13 +03001360 copy_siginfo_to_user(&frame->info, info);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001361 env->xregs[1] = frame_addr + offsetof(struct target_rt_sigframe, info);
1362 env->xregs[2] = frame_addr + offsetof(struct target_rt_sigframe, uc);
1363 }
1364
1365 unlock_user_struct(frame, frame_addr, 1);
1366 return;
1367
1368 give_sigsegv:
1369 unlock_user_struct(frame, frame_addr, 1);
1370 force_sig(TARGET_SIGSEGV);
1371}
1372
1373static void setup_rt_frame(int sig, struct target_sigaction *ka,
1374 target_siginfo_t *info, target_sigset_t *set,
1375 CPUARMState *env)
1376{
1377 target_setup_frame(sig, ka, info, set, env);
1378}
1379
1380static void setup_frame(int sig, struct target_sigaction *ka,
1381 target_sigset_t *set, CPUARMState *env)
1382{
1383 target_setup_frame(sig, ka, 0, set, env);
1384}
1385
1386long do_rt_sigreturn(CPUARMState *env)
1387{
Peter Maydell7f72cd22014-03-12 13:06:00 +00001388 struct target_rt_sigframe *frame = NULL;
Andreas Schwab1744aea2013-09-03 20:12:16 +01001389 abi_ulong frame_addr = env->xregs[31];
1390
1391 if (frame_addr & 15) {
1392 goto badframe;
1393 }
1394
1395 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
1396 goto badframe;
1397 }
1398
1399 if (target_restore_sigframe(env, frame)) {
1400 goto badframe;
1401 }
1402
1403 if (do_sigaltstack(frame_addr +
1404 offsetof(struct target_rt_sigframe, uc.tuc_stack),
1405 0, get_sp_from_cpustate(env)) == -EFAULT) {
1406 goto badframe;
1407 }
1408
1409 unlock_user_struct(frame, frame_addr, 0);
1410 return env->xregs[0];
1411
1412 badframe:
1413 unlock_user_struct(frame, frame_addr, 0);
1414 force_sig(TARGET_SIGSEGV);
1415 return 0;
1416}
1417
1418long do_sigreturn(CPUARMState *env)
1419{
1420 return do_rt_sigreturn(env);
1421}
1422
bellard43fff232003-07-09 19:31:39 +00001423#elif defined(TARGET_ARM)
1424
1425struct target_sigcontext {
blueswir1992f48a2007-10-14 16:27:31 +00001426 abi_ulong trap_no;
1427 abi_ulong error_code;
1428 abi_ulong oldmask;
1429 abi_ulong arm_r0;
1430 abi_ulong arm_r1;
1431 abi_ulong arm_r2;
1432 abi_ulong arm_r3;
1433 abi_ulong arm_r4;
1434 abi_ulong arm_r5;
1435 abi_ulong arm_r6;
1436 abi_ulong arm_r7;
1437 abi_ulong arm_r8;
1438 abi_ulong arm_r9;
1439 abi_ulong arm_r10;
1440 abi_ulong arm_fp;
1441 abi_ulong arm_ip;
1442 abi_ulong arm_sp;
1443 abi_ulong arm_lr;
1444 abi_ulong arm_pc;
1445 abi_ulong arm_cpsr;
1446 abi_ulong fault_address;
bellard43fff232003-07-09 19:31:39 +00001447};
1448
pbrooka745ec62008-05-06 15:36:17 +00001449struct target_ucontext_v1 {
blueswir1992f48a2007-10-14 16:27:31 +00001450 abi_ulong tuc_flags;
1451 abi_ulong tuc_link;
Anthony Liguoric227f092009-10-01 16:12:16 -05001452 target_stack_t tuc_stack;
bellardb8076a72005-04-07 22:20:31 +00001453 struct target_sigcontext tuc_mcontext;
Anthony Liguoric227f092009-10-01 16:12:16 -05001454 target_sigset_t tuc_sigmask; /* mask last for extensibility */
bellard43fff232003-07-09 19:31:39 +00001455};
1456
pbrooka745ec62008-05-06 15:36:17 +00001457struct target_ucontext_v2 {
1458 abi_ulong tuc_flags;
1459 abi_ulong tuc_link;
Anthony Liguoric227f092009-10-01 16:12:16 -05001460 target_stack_t tuc_stack;
pbrooka745ec62008-05-06 15:36:17 +00001461 struct target_sigcontext tuc_mcontext;
Anthony Liguoric227f092009-10-01 16:12:16 -05001462 target_sigset_t tuc_sigmask; /* mask last for extensibility */
Peter Maydell5f0b7c82010-11-24 15:20:03 +00001463 char __unused[128 - sizeof(target_sigset_t)];
pbrooka745ec62008-05-06 15:36:17 +00001464 abi_ulong tuc_regspace[128] __attribute__((__aligned__(8)));
1465};
1466
Peter Maydell0d871bd2010-11-24 15:20:05 +00001467struct target_user_vfp {
1468 uint64_t fpregs[32];
1469 abi_ulong fpscr;
1470};
1471
1472struct target_user_vfp_exc {
1473 abi_ulong fpexc;
1474 abi_ulong fpinst;
1475 abi_ulong fpinst2;
1476};
1477
1478struct target_vfp_sigframe {
1479 abi_ulong magic;
1480 abi_ulong size;
1481 struct target_user_vfp ufp;
1482 struct target_user_vfp_exc ufp_exc;
1483} __attribute__((__aligned__(8)));
1484
Peter Maydell08e11252010-11-24 15:20:07 +00001485struct target_iwmmxt_sigframe {
1486 abi_ulong magic;
1487 abi_ulong size;
1488 uint64_t regs[16];
1489 /* Note that not all the coprocessor control registers are stored here */
1490 uint32_t wcssf;
1491 uint32_t wcasf;
1492 uint32_t wcgr0;
1493 uint32_t wcgr1;
1494 uint32_t wcgr2;
1495 uint32_t wcgr3;
1496} __attribute__((__aligned__(8)));
1497
Peter Maydell0d871bd2010-11-24 15:20:05 +00001498#define TARGET_VFP_MAGIC 0x56465001
Peter Maydell08e11252010-11-24 15:20:07 +00001499#define TARGET_IWMMXT_MAGIC 0x12ef842a
Peter Maydell0d871bd2010-11-24 15:20:05 +00001500
pbrooka8c33202008-05-07 23:22:46 +00001501struct sigframe_v1
bellard43fff232003-07-09 19:31:39 +00001502{
1503 struct target_sigcontext sc;
blueswir1992f48a2007-10-14 16:27:31 +00001504 abi_ulong extramask[TARGET_NSIG_WORDS-1];
1505 abi_ulong retcode;
bellard43fff232003-07-09 19:31:39 +00001506};
1507
pbrooka8c33202008-05-07 23:22:46 +00001508struct sigframe_v2
1509{
1510 struct target_ucontext_v2 uc;
1511 abi_ulong retcode;
1512};
1513
pbrooka745ec62008-05-06 15:36:17 +00001514struct rt_sigframe_v1
bellard43fff232003-07-09 19:31:39 +00001515{
bellardf8b0aa22007-11-11 23:03:42 +00001516 abi_ulong pinfo;
1517 abi_ulong puc;
bellard43fff232003-07-09 19:31:39 +00001518 struct target_siginfo info;
pbrooka745ec62008-05-06 15:36:17 +00001519 struct target_ucontext_v1 uc;
1520 abi_ulong retcode;
1521};
1522
1523struct rt_sigframe_v2
1524{
1525 struct target_siginfo info;
1526 struct target_ucontext_v2 uc;
blueswir1992f48a2007-10-14 16:27:31 +00001527 abi_ulong retcode;
bellard43fff232003-07-09 19:31:39 +00001528};
1529
1530#define TARGET_CONFIG_CPU_32 1
1531
1532/*
1533 * For ARM syscalls, we encode the syscall number into the instruction.
1534 */
1535#define SWI_SYS_SIGRETURN (0xef000000|(TARGET_NR_sigreturn + ARM_SYSCALL_BASE))
1536#define SWI_SYS_RT_SIGRETURN (0xef000000|(TARGET_NR_rt_sigreturn + ARM_SYSCALL_BASE))
1537
1538/*
1539 * For Thumb syscalls, we pass the syscall number via r7. We therefore
1540 * need two 16-bit instructions.
1541 */
1542#define SWI_THUMB_SIGRETURN (0xdf00 << 16 | 0x2700 | (TARGET_NR_sigreturn))
1543#define SWI_THUMB_RT_SIGRETURN (0xdf00 << 16 | 0x2700 | (TARGET_NR_rt_sigreturn))
1544
blueswir1992f48a2007-10-14 16:27:31 +00001545static const abi_ulong retcodes[4] = {
bellard43fff232003-07-09 19:31:39 +00001546 SWI_SYS_SIGRETURN, SWI_THUMB_SIGRETURN,
1547 SWI_SYS_RT_SIGRETURN, SWI_THUMB_RT_SIGRETURN
1548};
1549
1550
Andreas Färber05390242012-02-25 03:37:53 +01001551static inline int valid_user_regs(CPUARMState *regs)
bellard43fff232003-07-09 19:31:39 +00001552{
1553 return 1;
1554}
1555
pbrooka8c33202008-05-07 23:22:46 +00001556static void
bellard43fff232003-07-09 19:31:39 +00001557setup_sigcontext(struct target_sigcontext *sc, /*struct _fpstate *fpstate,*/
Andreas Färber05390242012-02-25 03:37:53 +01001558 CPUARMState *env, abi_ulong mask)
bellard43fff232003-07-09 19:31:39 +00001559{
pbrooka8c33202008-05-07 23:22:46 +00001560 __put_user(env->regs[0], &sc->arm_r0);
1561 __put_user(env->regs[1], &sc->arm_r1);
1562 __put_user(env->regs[2], &sc->arm_r2);
1563 __put_user(env->regs[3], &sc->arm_r3);
1564 __put_user(env->regs[4], &sc->arm_r4);
1565 __put_user(env->regs[5], &sc->arm_r5);
1566 __put_user(env->regs[6], &sc->arm_r6);
1567 __put_user(env->regs[7], &sc->arm_r7);
1568 __put_user(env->regs[8], &sc->arm_r8);
1569 __put_user(env->regs[9], &sc->arm_r9);
1570 __put_user(env->regs[10], &sc->arm_r10);
1571 __put_user(env->regs[11], &sc->arm_fp);
1572 __put_user(env->regs[12], &sc->arm_ip);
1573 __put_user(env->regs[13], &sc->arm_sp);
1574 __put_user(env->regs[14], &sc->arm_lr);
1575 __put_user(env->regs[15], &sc->arm_pc);
bellard43fff232003-07-09 19:31:39 +00001576#ifdef TARGET_CONFIG_CPU_32
pbrooka8c33202008-05-07 23:22:46 +00001577 __put_user(cpsr_read(env), &sc->arm_cpsr);
bellard43fff232003-07-09 19:31:39 +00001578#endif
1579
pbrooka8c33202008-05-07 23:22:46 +00001580 __put_user(/* current->thread.trap_no */ 0, &sc->trap_no);
1581 __put_user(/* current->thread.error_code */ 0, &sc->error_code);
1582 __put_user(/* current->thread.address */ 0, &sc->fault_address);
1583 __put_user(mask, &sc->oldmask);
bellard43fff232003-07-09 19:31:39 +00001584}
1585
bellard579a97f2007-11-11 14:26:47 +00001586static inline abi_ulong
Andreas Färber05390242012-02-25 03:37:53 +01001587get_sigframe(struct target_sigaction *ka, CPUARMState *regs, int framesize)
bellard43fff232003-07-09 19:31:39 +00001588{
1589 unsigned long sp = regs->regs[13];
1590
bellard43fff232003-07-09 19:31:39 +00001591 /*
1592 * This is the X/Open sanctioned signal stack switching.
1593 */
pbrook624f7972008-05-31 16:11:38 +00001594 if ((ka->sa_flags & TARGET_SA_ONSTACK) && !sas_ss_flags(sp))
thsa04e1342007-09-27 13:57:58 +00001595 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
bellard43fff232003-07-09 19:31:39 +00001596 /*
1597 * ATPCS B01 mandates 8-byte alignment
1598 */
bellard579a97f2007-11-11 14:26:47 +00001599 return (sp - framesize) & ~7;
bellard43fff232003-07-09 19:31:39 +00001600}
1601
1602static int
Andreas Färber05390242012-02-25 03:37:53 +01001603setup_return(CPUARMState *env, struct target_sigaction *ka,
bellardf8b0aa22007-11-11 23:03:42 +00001604 abi_ulong *rc, abi_ulong frame_addr, int usig, abi_ulong rc_addr)
bellard43fff232003-07-09 19:31:39 +00001605{
pbrook624f7972008-05-31 16:11:38 +00001606 abi_ulong handler = ka->_sa_handler;
blueswir1992f48a2007-10-14 16:27:31 +00001607 abi_ulong retcode;
pbrook75b680e2008-03-21 16:07:30 +00001608 int thumb = handler & 1;
Peter Maydell964413d2011-01-14 20:39:19 +01001609 uint32_t cpsr = cpsr_read(env);
1610
1611 cpsr &= ~CPSR_IT;
1612 if (thumb) {
1613 cpsr |= CPSR_T;
1614 } else {
1615 cpsr &= ~CPSR_T;
1616 }
bellard43fff232003-07-09 19:31:39 +00001617
pbrook624f7972008-05-31 16:11:38 +00001618 if (ka->sa_flags & TARGET_SA_RESTORER) {
1619 retcode = ka->sa_restorer;
bellard43fff232003-07-09 19:31:39 +00001620 } else {
1621 unsigned int idx = thumb;
1622
pbrook624f7972008-05-31 16:11:38 +00001623 if (ka->sa_flags & TARGET_SA_SIGINFO)
bellard43fff232003-07-09 19:31:39 +00001624 idx += 2;
1625
1626 if (__put_user(retcodes[idx], rc))
1627 return 1;
Stefan Weilca8a2772011-10-03 22:43:19 +02001628
bellardf8b0aa22007-11-11 23:03:42 +00001629 retcode = rc_addr + thumb;
bellard43fff232003-07-09 19:31:39 +00001630 }
1631
1632 env->regs[0] = usig;
bellardf8b0aa22007-11-11 23:03:42 +00001633 env->regs[13] = frame_addr;
bellard43fff232003-07-09 19:31:39 +00001634 env->regs[14] = retcode;
1635 env->regs[15] = handler & (thumb ? ~1 : ~3);
Peter Maydell964413d2011-01-14 20:39:19 +01001636 cpsr_write(env, cpsr, 0xffffffff);
bellard43fff232003-07-09 19:31:39 +00001637
1638 return 0;
1639}
1640
Andreas Färber05390242012-02-25 03:37:53 +01001641static abi_ulong *setup_sigframe_v2_vfp(abi_ulong *regspace, CPUARMState *env)
Peter Maydell0d871bd2010-11-24 15:20:05 +00001642{
1643 int i;
1644 struct target_vfp_sigframe *vfpframe;
1645 vfpframe = (struct target_vfp_sigframe *)regspace;
1646 __put_user(TARGET_VFP_MAGIC, &vfpframe->magic);
1647 __put_user(sizeof(*vfpframe), &vfpframe->size);
1648 for (i = 0; i < 32; i++) {
Peter Maydell005e1a02011-02-10 13:59:35 +00001649 __put_user(float64_val(env->vfp.regs[i]), &vfpframe->ufp.fpregs[i]);
Peter Maydell0d871bd2010-11-24 15:20:05 +00001650 }
1651 __put_user(vfp_get_fpscr(env), &vfpframe->ufp.fpscr);
1652 __put_user(env->vfp.xregs[ARM_VFP_FPEXC], &vfpframe->ufp_exc.fpexc);
1653 __put_user(env->vfp.xregs[ARM_VFP_FPINST], &vfpframe->ufp_exc.fpinst);
1654 __put_user(env->vfp.xregs[ARM_VFP_FPINST2], &vfpframe->ufp_exc.fpinst2);
1655 return (abi_ulong*)(vfpframe+1);
1656}
1657
Andreas Färber05390242012-02-25 03:37:53 +01001658static abi_ulong *setup_sigframe_v2_iwmmxt(abi_ulong *regspace,
1659 CPUARMState *env)
Peter Maydell08e11252010-11-24 15:20:07 +00001660{
1661 int i;
1662 struct target_iwmmxt_sigframe *iwmmxtframe;
1663 iwmmxtframe = (struct target_iwmmxt_sigframe *)regspace;
1664 __put_user(TARGET_IWMMXT_MAGIC, &iwmmxtframe->magic);
1665 __put_user(sizeof(*iwmmxtframe), &iwmmxtframe->size);
1666 for (i = 0; i < 16; i++) {
1667 __put_user(env->iwmmxt.regs[i], &iwmmxtframe->regs[i]);
1668 }
1669 __put_user(env->vfp.xregs[ARM_IWMMXT_wCSSF], &iwmmxtframe->wcssf);
1670 __put_user(env->vfp.xregs[ARM_IWMMXT_wCASF], &iwmmxtframe->wcssf);
1671 __put_user(env->vfp.xregs[ARM_IWMMXT_wCGR0], &iwmmxtframe->wcgr0);
1672 __put_user(env->vfp.xregs[ARM_IWMMXT_wCGR1], &iwmmxtframe->wcgr1);
1673 __put_user(env->vfp.xregs[ARM_IWMMXT_wCGR2], &iwmmxtframe->wcgr2);
1674 __put_user(env->vfp.xregs[ARM_IWMMXT_wCGR3], &iwmmxtframe->wcgr3);
1675 return (abi_ulong*)(iwmmxtframe+1);
1676}
1677
pbrooka8c33202008-05-07 23:22:46 +00001678static void setup_sigframe_v2(struct target_ucontext_v2 *uc,
Andreas Färber05390242012-02-25 03:37:53 +01001679 target_sigset_t *set, CPUARMState *env)
bellard43fff232003-07-09 19:31:39 +00001680{
pbrooka8c33202008-05-07 23:22:46 +00001681 struct target_sigaltstack stack;
1682 int i;
Peter Maydell0d871bd2010-11-24 15:20:05 +00001683 abi_ulong *regspace;
pbrooka8c33202008-05-07 23:22:46 +00001684
1685 /* Clear all the bits of the ucontext we don't use. */
1686 memset(uc, 0, offsetof(struct target_ucontext_v2, tuc_mcontext));
1687
1688 memset(&stack, 0, sizeof(stack));
1689 __put_user(target_sigaltstack_used.ss_sp, &stack.ss_sp);
1690 __put_user(target_sigaltstack_used.ss_size, &stack.ss_size);
1691 __put_user(sas_ss_flags(get_sp_from_cpustate(env)), &stack.ss_flags);
1692 memcpy(&uc->tuc_stack, &stack, sizeof(stack));
1693
1694 setup_sigcontext(&uc->tuc_mcontext, env, set->sig[0]);
Peter Maydell0d871bd2010-11-24 15:20:05 +00001695 /* Save coprocessor signal frame. */
1696 regspace = uc->tuc_regspace;
1697 if (arm_feature(env, ARM_FEATURE_VFP)) {
1698 regspace = setup_sigframe_v2_vfp(regspace, env);
1699 }
Peter Maydell08e11252010-11-24 15:20:07 +00001700 if (arm_feature(env, ARM_FEATURE_IWMMXT)) {
1701 regspace = setup_sigframe_v2_iwmmxt(regspace, env);
1702 }
1703
Peter Maydell0d871bd2010-11-24 15:20:05 +00001704 /* Write terminating magic word */
1705 __put_user(0, regspace);
1706
pbrooka8c33202008-05-07 23:22:46 +00001707 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
1708 __put_user(set->sig[i], &uc->tuc_sigmask.sig[i]);
1709 }
1710}
1711
1712/* compare linux/arch/arm/kernel/signal.c:setup_frame() */
pbrook624f7972008-05-31 16:11:38 +00001713static void setup_frame_v1(int usig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01001714 target_sigset_t *set, CPUARMState *regs)
pbrooka8c33202008-05-07 23:22:46 +00001715{
1716 struct sigframe_v1 *frame;
bellard579a97f2007-11-11 14:26:47 +00001717 abi_ulong frame_addr = get_sigframe(ka, regs, sizeof(*frame));
pbrooka8c33202008-05-07 23:22:46 +00001718 int i;
bellard43fff232003-07-09 19:31:39 +00001719
bellard579a97f2007-11-11 14:26:47 +00001720 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
1721 return;
1722
pbrooka8c33202008-05-07 23:22:46 +00001723 setup_sigcontext(&frame->sc, regs, set->sig[0]);
bellard43fff232003-07-09 19:31:39 +00001724
bellard92319442004-06-19 16:58:13 +00001725 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
1726 if (__put_user(set->sig[i], &frame->extramask[i - 1]))
bellard579a97f2007-11-11 14:26:47 +00001727 goto end;
bellard43fff232003-07-09 19:31:39 +00001728 }
1729
pbrooka8c33202008-05-07 23:22:46 +00001730 setup_return(regs, ka, &frame->retcode, frame_addr, usig,
1731 frame_addr + offsetof(struct sigframe_v1, retcode));
bellard579a97f2007-11-11 14:26:47 +00001732
1733end:
1734 unlock_user_struct(frame, frame_addr, 1);
pbrooka8c33202008-05-07 23:22:46 +00001735}
1736
pbrook624f7972008-05-31 16:11:38 +00001737static void setup_frame_v2(int usig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01001738 target_sigset_t *set, CPUARMState *regs)
pbrooka8c33202008-05-07 23:22:46 +00001739{
1740 struct sigframe_v2 *frame;
1741 abi_ulong frame_addr = get_sigframe(ka, regs, sizeof(*frame));
1742
1743 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
1744 return;
1745
1746 setup_sigframe_v2(&frame->uc, set, regs);
1747
1748 setup_return(regs, ka, &frame->retcode, frame_addr, usig,
1749 frame_addr + offsetof(struct sigframe_v2, retcode));
1750
1751 unlock_user_struct(frame, frame_addr, 1);
1752}
1753
pbrook624f7972008-05-31 16:11:38 +00001754static void setup_frame(int usig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01001755 target_sigset_t *set, CPUARMState *regs)
pbrooka8c33202008-05-07 23:22:46 +00001756{
1757 if (get_osversion() >= 0x020612) {
1758 setup_frame_v2(usig, ka, set, regs);
1759 } else {
1760 setup_frame_v1(usig, ka, set, regs);
1761 }
bellard43fff232003-07-09 19:31:39 +00001762}
1763
bellard579a97f2007-11-11 14:26:47 +00001764/* compare linux/arch/arm/kernel/signal.c:setup_rt_frame() */
pbrook624f7972008-05-31 16:11:38 +00001765static void setup_rt_frame_v1(int usig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05001766 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01001767 target_sigset_t *set, CPUARMState *env)
bellard43fff232003-07-09 19:31:39 +00001768{
pbrooka745ec62008-05-06 15:36:17 +00001769 struct rt_sigframe_v1 *frame;
bellard579a97f2007-11-11 14:26:47 +00001770 abi_ulong frame_addr = get_sigframe(ka, env, sizeof(*frame));
thsa04e1342007-09-27 13:57:58 +00001771 struct target_sigaltstack stack;
pbrooka8c33202008-05-07 23:22:46 +00001772 int i;
bellardf8b0aa22007-11-11 23:03:42 +00001773 abi_ulong info_addr, uc_addr;
bellard43fff232003-07-09 19:31:39 +00001774
bellard579a97f2007-11-11 14:26:47 +00001775 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
bellardedf779f2004-02-22 13:40:13 +00001776 return /* 1 */;
1777
pbrooka745ec62008-05-06 15:36:17 +00001778 info_addr = frame_addr + offsetof(struct rt_sigframe_v1, info);
pbrooka8c33202008-05-07 23:22:46 +00001779 __put_user(info_addr, &frame->pinfo);
pbrooka745ec62008-05-06 15:36:17 +00001780 uc_addr = frame_addr + offsetof(struct rt_sigframe_v1, uc);
pbrooka8c33202008-05-07 23:22:46 +00001781 __put_user(uc_addr, &frame->puc);
1782 copy_siginfo_to_user(&frame->info, info);
bellard43fff232003-07-09 19:31:39 +00001783
1784 /* Clear all the bits of the ucontext we don't use. */
pbrooka745ec62008-05-06 15:36:17 +00001785 memset(&frame->uc, 0, offsetof(struct target_ucontext_v1, tuc_mcontext));
bellard43fff232003-07-09 19:31:39 +00001786
thsa04e1342007-09-27 13:57:58 +00001787 memset(&stack, 0, sizeof(stack));
1788 __put_user(target_sigaltstack_used.ss_sp, &stack.ss_sp);
1789 __put_user(target_sigaltstack_used.ss_size, &stack.ss_size);
1790 __put_user(sas_ss_flags(get_sp_from_cpustate(env)), &stack.ss_flags);
bellard775b58d2007-11-11 16:22:17 +00001791 memcpy(&frame->uc.tuc_stack, &stack, sizeof(stack));
thsa04e1342007-09-27 13:57:58 +00001792
pbrooka8c33202008-05-07 23:22:46 +00001793 setup_sigcontext(&frame->uc.tuc_mcontext, env, set->sig[0]);
bellard92319442004-06-19 16:58:13 +00001794 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
bellardb8076a72005-04-07 22:20:31 +00001795 if (__put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]))
bellard579a97f2007-11-11 14:26:47 +00001796 goto end;
bellard92319442004-06-19 16:58:13 +00001797 }
bellard43fff232003-07-09 19:31:39 +00001798
pbrooka8c33202008-05-07 23:22:46 +00001799 setup_return(env, ka, &frame->retcode, frame_addr, usig,
1800 frame_addr + offsetof(struct rt_sigframe_v1, retcode));
pbrooka745ec62008-05-06 15:36:17 +00001801
pbrooka8c33202008-05-07 23:22:46 +00001802 env->regs[1] = info_addr;
1803 env->regs[2] = uc_addr;
pbrooka745ec62008-05-06 15:36:17 +00001804
1805end:
1806 unlock_user_struct(frame, frame_addr, 1);
pbrooka745ec62008-05-06 15:36:17 +00001807}
1808
pbrook624f7972008-05-31 16:11:38 +00001809static void setup_rt_frame_v2(int usig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05001810 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01001811 target_sigset_t *set, CPUARMState *env)
pbrooka745ec62008-05-06 15:36:17 +00001812{
1813 struct rt_sigframe_v2 *frame;
1814 abi_ulong frame_addr = get_sigframe(ka, env, sizeof(*frame));
pbrooka745ec62008-05-06 15:36:17 +00001815 abi_ulong info_addr, uc_addr;
1816
1817 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
1818 return /* 1 */;
1819
1820 info_addr = frame_addr + offsetof(struct rt_sigframe_v2, info);
1821 uc_addr = frame_addr + offsetof(struct rt_sigframe_v2, uc);
pbrooka8c33202008-05-07 23:22:46 +00001822 copy_siginfo_to_user(&frame->info, info);
pbrooka745ec62008-05-06 15:36:17 +00001823
pbrooka8c33202008-05-07 23:22:46 +00001824 setup_sigframe_v2(&frame->uc, set, env);
pbrooka745ec62008-05-06 15:36:17 +00001825
pbrooka8c33202008-05-07 23:22:46 +00001826 setup_return(env, ka, &frame->retcode, frame_addr, usig,
1827 frame_addr + offsetof(struct rt_sigframe_v2, retcode));
pbrooka745ec62008-05-06 15:36:17 +00001828
pbrooka8c33202008-05-07 23:22:46 +00001829 env->regs[1] = info_addr;
1830 env->regs[2] = uc_addr;
pbrooka745ec62008-05-06 15:36:17 +00001831
bellard579a97f2007-11-11 14:26:47 +00001832 unlock_user_struct(frame, frame_addr, 1);
bellard43fff232003-07-09 19:31:39 +00001833}
1834
pbrook624f7972008-05-31 16:11:38 +00001835static void setup_rt_frame(int usig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05001836 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01001837 target_sigset_t *set, CPUARMState *env)
pbrooka745ec62008-05-06 15:36:17 +00001838{
1839 if (get_osversion() >= 0x020612) {
1840 setup_rt_frame_v2(usig, ka, info, set, env);
1841 } else {
1842 setup_rt_frame_v1(usig, ka, info, set, env);
1843 }
1844}
1845
bellard43fff232003-07-09 19:31:39 +00001846static int
Andreas Färber05390242012-02-25 03:37:53 +01001847restore_sigcontext(CPUARMState *env, struct target_sigcontext *sc)
bellard43fff232003-07-09 19:31:39 +00001848{
1849 int err = 0;
bellardb5ff1b32005-11-26 10:38:39 +00001850 uint32_t cpsr;
bellard43fff232003-07-09 19:31:39 +00001851
Riku Voipio1d8b5122014-04-23 10:26:05 +03001852 __get_user(env->regs[0], &sc->arm_r0);
1853 __get_user(env->regs[1], &sc->arm_r1);
1854 __get_user(env->regs[2], &sc->arm_r2);
1855 __get_user(env->regs[3], &sc->arm_r3);
1856 __get_user(env->regs[4], &sc->arm_r4);
1857 __get_user(env->regs[5], &sc->arm_r5);
1858 __get_user(env->regs[6], &sc->arm_r6);
1859 __get_user(env->regs[7], &sc->arm_r7);
1860 __get_user(env->regs[8], &sc->arm_r8);
1861 __get_user(env->regs[9], &sc->arm_r9);
1862 __get_user(env->regs[10], &sc->arm_r10);
1863 __get_user(env->regs[11], &sc->arm_fp);
1864 __get_user(env->regs[12], &sc->arm_ip);
1865 __get_user(env->regs[13], &sc->arm_sp);
1866 __get_user(env->regs[14], &sc->arm_lr);
1867 __get_user(env->regs[15], &sc->arm_pc);
bellard43fff232003-07-09 19:31:39 +00001868#ifdef TARGET_CONFIG_CPU_32
Riku Voipio1d8b5122014-04-23 10:26:05 +03001869 __get_user(cpsr, &sc->arm_cpsr);
pbrook75b680e2008-03-21 16:07:30 +00001870 cpsr_write(env, cpsr, CPSR_USER | CPSR_EXEC);
bellard43fff232003-07-09 19:31:39 +00001871#endif
1872
1873 err |= !valid_user_regs(env);
1874
1875 return err;
1876}
1877
Andreas Färber05390242012-02-25 03:37:53 +01001878static long do_sigreturn_v1(CPUARMState *env)
bellard43fff232003-07-09 19:31:39 +00001879{
bellardf8b0aa22007-11-11 23:03:42 +00001880 abi_ulong frame_addr;
Peter Maydell978fae92013-07-29 12:00:32 +01001881 struct sigframe_v1 *frame = NULL;
Anthony Liguoric227f092009-10-01 16:12:16 -05001882 target_sigset_t set;
bellard43fff232003-07-09 19:31:39 +00001883 sigset_t host_set;
bellard92319442004-06-19 16:58:13 +00001884 int i;
bellard43fff232003-07-09 19:31:39 +00001885
1886 /*
1887 * Since we stacked the signal on a 64-bit boundary,
1888 * then 'sp' should be word aligned here. If it's
1889 * not, then the user is trying to mess with us.
1890 */
bellardf8b0aa22007-11-11 23:03:42 +00001891 frame_addr = env->regs[13];
Peter Maydell978fae92013-07-29 12:00:32 +01001892 if (frame_addr & 7) {
1893 goto badframe;
1894 }
1895
bellardf8b0aa22007-11-11 23:03:42 +00001896 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
1897 goto badframe;
bellard43fff232003-07-09 19:31:39 +00001898
bellard92319442004-06-19 16:58:13 +00001899 if (__get_user(set.sig[0], &frame->sc.oldmask))
1900 goto badframe;
1901 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
1902 if (__get_user(set.sig[i], &frame->extramask[i - 1]))
1903 goto badframe;
1904 }
bellard43fff232003-07-09 19:31:39 +00001905
bellard92319442004-06-19 16:58:13 +00001906 target_to_host_sigset_internal(&host_set, &set);
Alex Barcelo1c275922014-03-14 14:36:55 +00001907 do_sigprocmask(SIG_SETMASK, &host_set, NULL);
bellard43fff232003-07-09 19:31:39 +00001908
1909 if (restore_sigcontext(env, &frame->sc))
1910 goto badframe;
1911
1912#if 0
1913 /* Send SIGTRAP if we're single-stepping */
1914 if (ptrace_cancel_bpt(current))
1915 send_sig(SIGTRAP, current, 1);
1916#endif
bellardf8b0aa22007-11-11 23:03:42 +00001917 unlock_user_struct(frame, frame_addr, 0);
1918 return env->regs[0];
bellard43fff232003-07-09 19:31:39 +00001919
1920badframe:
bellardf8b0aa22007-11-11 23:03:42 +00001921 unlock_user_struct(frame, frame_addr, 0);
Riku Voipio66393fb2009-12-04 15:16:32 +02001922 force_sig(TARGET_SIGSEGV /* , current */);
bellard43fff232003-07-09 19:31:39 +00001923 return 0;
1924}
1925
Andreas Färber05390242012-02-25 03:37:53 +01001926static abi_ulong *restore_sigframe_v2_vfp(CPUARMState *env, abi_ulong *regspace)
Peter Maydell5f9099d2010-11-24 15:20:06 +00001927{
1928 int i;
1929 abi_ulong magic, sz;
1930 uint32_t fpscr, fpexc;
1931 struct target_vfp_sigframe *vfpframe;
1932 vfpframe = (struct target_vfp_sigframe *)regspace;
1933
1934 __get_user(magic, &vfpframe->magic);
1935 __get_user(sz, &vfpframe->size);
1936 if (magic != TARGET_VFP_MAGIC || sz != sizeof(*vfpframe)) {
1937 return 0;
1938 }
1939 for (i = 0; i < 32; i++) {
Peter Maydell005e1a02011-02-10 13:59:35 +00001940 __get_user(float64_val(env->vfp.regs[i]), &vfpframe->ufp.fpregs[i]);
Peter Maydell5f9099d2010-11-24 15:20:06 +00001941 }
1942 __get_user(fpscr, &vfpframe->ufp.fpscr);
1943 vfp_set_fpscr(env, fpscr);
1944 __get_user(fpexc, &vfpframe->ufp_exc.fpexc);
1945 /* Sanitise FPEXC: ensure VFP is enabled, FPINST2 is invalid
1946 * and the exception flag is cleared
1947 */
1948 fpexc |= (1 << 30);
1949 fpexc &= ~((1 << 31) | (1 << 28));
1950 env->vfp.xregs[ARM_VFP_FPEXC] = fpexc;
1951 __get_user(env->vfp.xregs[ARM_VFP_FPINST], &vfpframe->ufp_exc.fpinst);
1952 __get_user(env->vfp.xregs[ARM_VFP_FPINST2], &vfpframe->ufp_exc.fpinst2);
1953 return (abi_ulong*)(vfpframe + 1);
1954}
1955
Andreas Färber05390242012-02-25 03:37:53 +01001956static abi_ulong *restore_sigframe_v2_iwmmxt(CPUARMState *env,
1957 abi_ulong *regspace)
Peter Maydella59d69d2010-11-24 15:20:08 +00001958{
1959 int i;
1960 abi_ulong magic, sz;
1961 struct target_iwmmxt_sigframe *iwmmxtframe;
1962 iwmmxtframe = (struct target_iwmmxt_sigframe *)regspace;
1963
1964 __get_user(magic, &iwmmxtframe->magic);
1965 __get_user(sz, &iwmmxtframe->size);
1966 if (magic != TARGET_IWMMXT_MAGIC || sz != sizeof(*iwmmxtframe)) {
1967 return 0;
1968 }
1969 for (i = 0; i < 16; i++) {
1970 __get_user(env->iwmmxt.regs[i], &iwmmxtframe->regs[i]);
1971 }
1972 __get_user(env->vfp.xregs[ARM_IWMMXT_wCSSF], &iwmmxtframe->wcssf);
1973 __get_user(env->vfp.xregs[ARM_IWMMXT_wCASF], &iwmmxtframe->wcssf);
1974 __get_user(env->vfp.xregs[ARM_IWMMXT_wCGR0], &iwmmxtframe->wcgr0);
1975 __get_user(env->vfp.xregs[ARM_IWMMXT_wCGR1], &iwmmxtframe->wcgr1);
1976 __get_user(env->vfp.xregs[ARM_IWMMXT_wCGR2], &iwmmxtframe->wcgr2);
1977 __get_user(env->vfp.xregs[ARM_IWMMXT_wCGR3], &iwmmxtframe->wcgr3);
1978 return (abi_ulong*)(iwmmxtframe + 1);
1979}
1980
Andreas Färber05390242012-02-25 03:37:53 +01001981static int do_sigframe_return_v2(CPUARMState *env, target_ulong frame_addr,
pbrooka8c33202008-05-07 23:22:46 +00001982 struct target_ucontext_v2 *uc)
1983{
1984 sigset_t host_set;
Peter Maydell5f9099d2010-11-24 15:20:06 +00001985 abi_ulong *regspace;
pbrooka8c33202008-05-07 23:22:46 +00001986
1987 target_to_host_sigset(&host_set, &uc->tuc_sigmask);
Alex Barcelo1c275922014-03-14 14:36:55 +00001988 do_sigprocmask(SIG_SETMASK, &host_set, NULL);
pbrooka8c33202008-05-07 23:22:46 +00001989
1990 if (restore_sigcontext(env, &uc->tuc_mcontext))
1991 return 1;
1992
Peter Maydell5f9099d2010-11-24 15:20:06 +00001993 /* Restore coprocessor signal frame */
1994 regspace = uc->tuc_regspace;
1995 if (arm_feature(env, ARM_FEATURE_VFP)) {
1996 regspace = restore_sigframe_v2_vfp(env, regspace);
1997 if (!regspace) {
1998 return 1;
1999 }
2000 }
Peter Maydella59d69d2010-11-24 15:20:08 +00002001 if (arm_feature(env, ARM_FEATURE_IWMMXT)) {
2002 regspace = restore_sigframe_v2_iwmmxt(env, regspace);
2003 if (!regspace) {
2004 return 1;
2005 }
2006 }
Peter Maydell5f9099d2010-11-24 15:20:06 +00002007
pbrooka8c33202008-05-07 23:22:46 +00002008 if (do_sigaltstack(frame_addr + offsetof(struct target_ucontext_v2, tuc_stack), 0, get_sp_from_cpustate(env)) == -EFAULT)
2009 return 1;
2010
2011#if 0
2012 /* Send SIGTRAP if we're single-stepping */
2013 if (ptrace_cancel_bpt(current))
2014 send_sig(SIGTRAP, current, 1);
2015#endif
2016
2017 return 0;
2018}
2019
Andreas Färber05390242012-02-25 03:37:53 +01002020static long do_sigreturn_v2(CPUARMState *env)
pbrooka8c33202008-05-07 23:22:46 +00002021{
2022 abi_ulong frame_addr;
Peter Maydell978fae92013-07-29 12:00:32 +01002023 struct sigframe_v2 *frame = NULL;
pbrooka8c33202008-05-07 23:22:46 +00002024
2025 /*
2026 * Since we stacked the signal on a 64-bit boundary,
2027 * then 'sp' should be word aligned here. If it's
2028 * not, then the user is trying to mess with us.
2029 */
pbrooka8c33202008-05-07 23:22:46 +00002030 frame_addr = env->regs[13];
Peter Maydell978fae92013-07-29 12:00:32 +01002031 if (frame_addr & 7) {
2032 goto badframe;
2033 }
2034
pbrooka8c33202008-05-07 23:22:46 +00002035 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
2036 goto badframe;
2037
2038 if (do_sigframe_return_v2(env, frame_addr, &frame->uc))
2039 goto badframe;
2040
2041 unlock_user_struct(frame, frame_addr, 0);
2042 return env->regs[0];
2043
2044badframe:
2045 unlock_user_struct(frame, frame_addr, 0);
Riku Voipio66393fb2009-12-04 15:16:32 +02002046 force_sig(TARGET_SIGSEGV /* , current */);
pbrooka8c33202008-05-07 23:22:46 +00002047 return 0;
2048}
2049
Andreas Färber05390242012-02-25 03:37:53 +01002050long do_sigreturn(CPUARMState *env)
pbrooka8c33202008-05-07 23:22:46 +00002051{
2052 if (get_osversion() >= 0x020612) {
2053 return do_sigreturn_v2(env);
2054 } else {
2055 return do_sigreturn_v1(env);
2056 }
2057}
2058
Andreas Färber05390242012-02-25 03:37:53 +01002059static long do_rt_sigreturn_v1(CPUARMState *env)
bellard43fff232003-07-09 19:31:39 +00002060{
bellardf8b0aa22007-11-11 23:03:42 +00002061 abi_ulong frame_addr;
Peter Maydell978fae92013-07-29 12:00:32 +01002062 struct rt_sigframe_v1 *frame = NULL;
bellard43fff232003-07-09 19:31:39 +00002063 sigset_t host_set;
2064
2065 /*
2066 * Since we stacked the signal on a 64-bit boundary,
2067 * then 'sp' should be word aligned here. If it's
2068 * not, then the user is trying to mess with us.
2069 */
bellardf8b0aa22007-11-11 23:03:42 +00002070 frame_addr = env->regs[13];
Peter Maydell978fae92013-07-29 12:00:32 +01002071 if (frame_addr & 7) {
2072 goto badframe;
2073 }
2074
bellardf8b0aa22007-11-11 23:03:42 +00002075 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
2076 goto badframe;
bellard43fff232003-07-09 19:31:39 +00002077
bellardb8076a72005-04-07 22:20:31 +00002078 target_to_host_sigset(&host_set, &frame->uc.tuc_sigmask);
Alex Barcelo1c275922014-03-14 14:36:55 +00002079 do_sigprocmask(SIG_SETMASK, &host_set, NULL);
bellard43fff232003-07-09 19:31:39 +00002080
bellardb8076a72005-04-07 22:20:31 +00002081 if (restore_sigcontext(env, &frame->uc.tuc_mcontext))
bellard43fff232003-07-09 19:31:39 +00002082 goto badframe;
2083
pbrooka745ec62008-05-06 15:36:17 +00002084 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 +00002085 goto badframe;
2086
bellard43fff232003-07-09 19:31:39 +00002087#if 0
2088 /* Send SIGTRAP if we're single-stepping */
2089 if (ptrace_cancel_bpt(current))
2090 send_sig(SIGTRAP, current, 1);
2091#endif
bellardf8b0aa22007-11-11 23:03:42 +00002092 unlock_user_struct(frame, frame_addr, 0);
bellard43fff232003-07-09 19:31:39 +00002093 return env->regs[0];
2094
2095badframe:
bellardf8b0aa22007-11-11 23:03:42 +00002096 unlock_user_struct(frame, frame_addr, 0);
Riku Voipio66393fb2009-12-04 15:16:32 +02002097 force_sig(TARGET_SIGSEGV /* , current */);
bellard43fff232003-07-09 19:31:39 +00002098 return 0;
2099}
2100
Andreas Färber05390242012-02-25 03:37:53 +01002101static long do_rt_sigreturn_v2(CPUARMState *env)
pbrooka745ec62008-05-06 15:36:17 +00002102{
2103 abi_ulong frame_addr;
Peter Maydell978fae92013-07-29 12:00:32 +01002104 struct rt_sigframe_v2 *frame = NULL;
pbrooka745ec62008-05-06 15:36:17 +00002105
2106 /*
2107 * Since we stacked the signal on a 64-bit boundary,
2108 * then 'sp' should be word aligned here. If it's
2109 * not, then the user is trying to mess with us.
2110 */
pbrooka745ec62008-05-06 15:36:17 +00002111 frame_addr = env->regs[13];
Peter Maydell978fae92013-07-29 12:00:32 +01002112 if (frame_addr & 7) {
2113 goto badframe;
2114 }
2115
pbrooka745ec62008-05-06 15:36:17 +00002116 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
2117 goto badframe;
2118
pbrooka8c33202008-05-07 23:22:46 +00002119 if (do_sigframe_return_v2(env, frame_addr, &frame->uc))
2120 goto badframe;
pbrooka745ec62008-05-06 15:36:17 +00002121
pbrooka745ec62008-05-06 15:36:17 +00002122 unlock_user_struct(frame, frame_addr, 0);
2123 return env->regs[0];
2124
2125badframe:
2126 unlock_user_struct(frame, frame_addr, 0);
Riku Voipio66393fb2009-12-04 15:16:32 +02002127 force_sig(TARGET_SIGSEGV /* , current */);
pbrooka745ec62008-05-06 15:36:17 +00002128 return 0;
2129}
2130
Andreas Färber05390242012-02-25 03:37:53 +01002131long do_rt_sigreturn(CPUARMState *env)
pbrooka745ec62008-05-06 15:36:17 +00002132{
2133 if (get_osversion() >= 0x020612) {
2134 return do_rt_sigreturn_v2(env);
2135 } else {
2136 return do_rt_sigreturn_v1(env);
2137 }
2138}
2139
bellard6d5e2162004-09-30 22:04:13 +00002140#elif defined(TARGET_SPARC)
bellard80a9d032005-01-03 23:31:27 +00002141
bellard6d5e2162004-09-30 22:04:13 +00002142#define __SUNOS_MAXWIN 31
2143
2144/* This is what SunOS does, so shall I. */
2145struct target_sigcontext {
blueswir1992f48a2007-10-14 16:27:31 +00002146 abi_ulong sigc_onstack; /* state to restore */
bellard6d5e2162004-09-30 22:04:13 +00002147
blueswir1992f48a2007-10-14 16:27:31 +00002148 abi_ulong sigc_mask; /* sigmask to restore */
2149 abi_ulong sigc_sp; /* stack pointer */
2150 abi_ulong sigc_pc; /* program counter */
2151 abi_ulong sigc_npc; /* next program counter */
2152 abi_ulong sigc_psr; /* for condition codes etc */
2153 abi_ulong sigc_g1; /* User uses these two registers */
2154 abi_ulong sigc_o0; /* within the trampoline code. */
bellard6d5e2162004-09-30 22:04:13 +00002155
2156 /* Now comes information regarding the users window set
2157 * at the time of the signal.
2158 */
blueswir1992f48a2007-10-14 16:27:31 +00002159 abi_ulong sigc_oswins; /* outstanding windows */
bellard6d5e2162004-09-30 22:04:13 +00002160
2161 /* stack ptrs for each regwin buf */
2162 char *sigc_spbuf[__SUNOS_MAXWIN];
2163
2164 /* Windows to restore after signal */
2165 struct {
blueswir1992f48a2007-10-14 16:27:31 +00002166 abi_ulong locals[8];
2167 abi_ulong ins[8];
bellard6d5e2162004-09-30 22:04:13 +00002168 } sigc_wbuf[__SUNOS_MAXWIN];
2169};
2170/* A Sparc stack frame */
2171struct sparc_stackf {
blueswir1992f48a2007-10-14 16:27:31 +00002172 abi_ulong locals[8];
Peter Maydelle321c342011-02-01 15:54:52 +00002173 abi_ulong ins[8];
2174 /* It's simpler to treat fp and callers_pc as elements of ins[]
2175 * since we never need to access them ourselves.
2176 */
bellard6d5e2162004-09-30 22:04:13 +00002177 char *structptr;
blueswir1992f48a2007-10-14 16:27:31 +00002178 abi_ulong xargs[6];
2179 abi_ulong xxargs[1];
bellard6d5e2162004-09-30 22:04:13 +00002180};
2181
2182typedef struct {
2183 struct {
blueswir1992f48a2007-10-14 16:27:31 +00002184 abi_ulong psr;
2185 abi_ulong pc;
2186 abi_ulong npc;
2187 abi_ulong y;
2188 abi_ulong u_regs[16]; /* globals and ins */
bellard6d5e2162004-09-30 22:04:13 +00002189 } si_regs;
2190 int si_mask;
2191} __siginfo_t;
2192
2193typedef struct {
Blue Swirl8954bae2012-07-30 15:29:11 +00002194 abi_ulong si_float_regs[32];
bellard6d5e2162004-09-30 22:04:13 +00002195 unsigned long si_fsr;
2196 unsigned long si_fpqdepth;
2197 struct {
2198 unsigned long *insn_addr;
2199 unsigned long insn;
2200 } si_fpqueue [16];
Anthony Liguoric227f092009-10-01 16:12:16 -05002201} qemu_siginfo_fpu_t;
bellard6d5e2162004-09-30 22:04:13 +00002202
2203
2204struct target_signal_frame {
2205 struct sparc_stackf ss;
2206 __siginfo_t info;
bellardf8b0aa22007-11-11 23:03:42 +00002207 abi_ulong fpu_save;
blueswir1992f48a2007-10-14 16:27:31 +00002208 abi_ulong insns[2] __attribute__ ((aligned (8)));
2209 abi_ulong extramask[TARGET_NSIG_WORDS - 1];
2210 abi_ulong extra_size; /* Should be 0 */
Anthony Liguoric227f092009-10-01 16:12:16 -05002211 qemu_siginfo_fpu_t fpu_state;
bellard6d5e2162004-09-30 22:04:13 +00002212};
2213struct target_rt_signal_frame {
2214 struct sparc_stackf ss;
2215 siginfo_t info;
blueswir1992f48a2007-10-14 16:27:31 +00002216 abi_ulong regs[20];
bellard6d5e2162004-09-30 22:04:13 +00002217 sigset_t mask;
bellardf8b0aa22007-11-11 23:03:42 +00002218 abi_ulong fpu_save;
bellard6d5e2162004-09-30 22:04:13 +00002219 unsigned int insns[2];
2220 stack_t stack;
2221 unsigned int extra_size; /* Should be 0 */
Anthony Liguoric227f092009-10-01 16:12:16 -05002222 qemu_siginfo_fpu_t fpu_state;
bellard6d5e2162004-09-30 22:04:13 +00002223};
2224
bellarde80cfcf2004-12-19 23:18:01 +00002225#define UREG_O0 16
2226#define UREG_O6 22
2227#define UREG_I0 0
2228#define UREG_I1 1
2229#define UREG_I2 2
blueswir15bfb56b2007-10-05 17:01:51 +00002230#define UREG_I3 3
2231#define UREG_I4 4
2232#define UREG_I5 5
bellarde80cfcf2004-12-19 23:18:01 +00002233#define UREG_I6 6
2234#define UREG_I7 7
2235#define UREG_L0 8
bellard6d5e2162004-09-30 22:04:13 +00002236#define UREG_FP UREG_I6
2237#define UREG_SP UREG_O6
2238
pbrook624f7972008-05-31 16:11:38 +00002239static inline abi_ulong get_sigframe(struct target_sigaction *sa,
Andreas Färber05390242012-02-25 03:37:53 +01002240 CPUSPARCState *env,
2241 unsigned long framesize)
bellard6d5e2162004-09-30 22:04:13 +00002242{
bellard459a4012007-11-11 19:45:10 +00002243 abi_ulong sp;
bellard6d5e2162004-09-30 22:04:13 +00002244
2245 sp = env->regwptr[UREG_FP];
bellard6d5e2162004-09-30 22:04:13 +00002246
2247 /* This is the X/Open sanctioned signal stack switching. */
pbrook624f7972008-05-31 16:11:38 +00002248 if (sa->sa_flags & TARGET_SA_ONSTACK) {
thsa04e1342007-09-27 13:57:58 +00002249 if (!on_sig_stack(sp)
2250 && !((target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size) & 7))
2251 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
bellard6d5e2162004-09-30 22:04:13 +00002252 }
bellard459a4012007-11-11 19:45:10 +00002253 return sp - framesize;
bellard6d5e2162004-09-30 22:04:13 +00002254}
2255
2256static int
Andreas Färber05390242012-02-25 03:37:53 +01002257setup___siginfo(__siginfo_t *si, CPUSPARCState *env, abi_ulong mask)
bellard6d5e2162004-09-30 22:04:13 +00002258{
2259 int err = 0, i;
2260
Riku Voipio1d8b5122014-04-23 10:26:05 +03002261 __put_user(env->psr, &si->si_regs.psr);
2262 __put_user(env->pc, &si->si_regs.pc);
2263 __put_user(env->npc, &si->si_regs.npc);
2264 __put_user(env->y, &si->si_regs.y);
bellarda315a142005-01-30 22:59:18 +00002265 for (i=0; i < 8; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002266 __put_user(env->gregs[i], &si->si_regs.u_regs[i]);
bellard6d5e2162004-09-30 22:04:13 +00002267 }
bellarda315a142005-01-30 22:59:18 +00002268 for (i=0; i < 8; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002269 __put_user(env->regwptr[UREG_I0 + i], &si->si_regs.u_regs[i+8]);
bellard6d5e2162004-09-30 22:04:13 +00002270 }
Riku Voipio1d8b5122014-04-23 10:26:05 +03002271 __put_user(mask, &si->si_mask);
bellard6d5e2162004-09-30 22:04:13 +00002272 return err;
2273}
bellarde80cfcf2004-12-19 23:18:01 +00002274
bellard80a9d032005-01-03 23:31:27 +00002275#if 0
bellard6d5e2162004-09-30 22:04:13 +00002276static int
2277setup_sigcontext(struct target_sigcontext *sc, /*struct _fpstate *fpstate,*/
Andreas Färber05390242012-02-25 03:37:53 +01002278 CPUSPARCState *env, unsigned long mask)
bellard6d5e2162004-09-30 22:04:13 +00002279{
2280 int err = 0;
2281
Riku Voipio1d8b5122014-04-23 10:26:05 +03002282 __put_user(mask, &sc->sigc_mask);
2283 __put_user(env->regwptr[UREG_SP], &sc->sigc_sp);
2284 __put_user(env->pc, &sc->sigc_pc);
2285 __put_user(env->npc, &sc->sigc_npc);
2286 __put_user(env->psr, &sc->sigc_psr);
2287 __put_user(env->gregs[1], &sc->sigc_g1);
2288 __put_user(env->regwptr[UREG_O0], &sc->sigc_o0);
bellard6d5e2162004-09-30 22:04:13 +00002289
2290 return err;
2291}
bellard80a9d032005-01-03 23:31:27 +00002292#endif
bellard6d5e2162004-09-30 22:04:13 +00002293#define NF_ALIGNEDSZ (((sizeof(struct target_signal_frame) + 7) & (~7)))
2294
pbrook624f7972008-05-31 16:11:38 +00002295static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01002296 target_sigset_t *set, CPUSPARCState *env)
bellard6d5e2162004-09-30 22:04:13 +00002297{
bellard459a4012007-11-11 19:45:10 +00002298 abi_ulong sf_addr;
bellard6d5e2162004-09-30 22:04:13 +00002299 struct target_signal_frame *sf;
2300 int sigframe_size, err, i;
2301
2302 /* 1. Make sure everything is clean */
2303 //synchronize_user_stack();
2304
2305 sigframe_size = NF_ALIGNEDSZ;
bellard459a4012007-11-11 19:45:10 +00002306 sf_addr = get_sigframe(ka, env, sigframe_size);
bellard6d5e2162004-09-30 22:04:13 +00002307
bellard459a4012007-11-11 19:45:10 +00002308 sf = lock_user(VERIFY_WRITE, sf_addr,
2309 sizeof(struct target_signal_frame), 0);
2310 if (!sf)
2311 goto sigsegv;
2312
bellarde80cfcf2004-12-19 23:18:01 +00002313 //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 +00002314#if 0
2315 if (invalid_frame_pointer(sf, sigframe_size))
2316 goto sigill_and_return;
2317#endif
2318 /* 2. Save the current process state */
2319 err = setup___siginfo(&sf->info, env, set->sig[0]);
Riku Voipio1d8b5122014-04-23 10:26:05 +03002320 __put_user(0, &sf->extra_size);
bellard6d5e2162004-09-30 22:04:13 +00002321
Riku Voipio1d8b5122014-04-23 10:26:05 +03002322 //save_fpu_state(regs, &sf->fpu_state);
2323 //__put_user(&sf->fpu_state, &sf->fpu_save);
bellard6d5e2162004-09-30 22:04:13 +00002324
Riku Voipio1d8b5122014-04-23 10:26:05 +03002325 __put_user(set->sig[0], &sf->info.si_mask);
bellard6d5e2162004-09-30 22:04:13 +00002326 for (i = 0; i < TARGET_NSIG_WORDS - 1; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002327 __put_user(set->sig[i + 1], &sf->extramask[i]);
bellard6d5e2162004-09-30 22:04:13 +00002328 }
2329
bellarda315a142005-01-30 22:59:18 +00002330 for (i = 0; i < 8; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002331 __put_user(env->regwptr[i + UREG_L0], &sf->ss.locals[i]);
bellard6d5e2162004-09-30 22:04:13 +00002332 }
bellarda315a142005-01-30 22:59:18 +00002333 for (i = 0; i < 8; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002334 __put_user(env->regwptr[i + UREG_I0], &sf->ss.ins[i]);
bellard6d5e2162004-09-30 22:04:13 +00002335 }
bellard6d5e2162004-09-30 22:04:13 +00002336 if (err)
2337 goto sigsegv;
2338
2339 /* 3. signal handler back-trampoline and parameters */
bellard459a4012007-11-11 19:45:10 +00002340 env->regwptr[UREG_FP] = sf_addr;
bellard6d5e2162004-09-30 22:04:13 +00002341 env->regwptr[UREG_I0] = sig;
bellard459a4012007-11-11 19:45:10 +00002342 env->regwptr[UREG_I1] = sf_addr +
2343 offsetof(struct target_signal_frame, info);
2344 env->regwptr[UREG_I2] = sf_addr +
2345 offsetof(struct target_signal_frame, info);
bellard6d5e2162004-09-30 22:04:13 +00002346
2347 /* 4. signal handler */
pbrook624f7972008-05-31 16:11:38 +00002348 env->pc = ka->_sa_handler;
bellard6d5e2162004-09-30 22:04:13 +00002349 env->npc = (env->pc + 4);
2350 /* 5. return to kernel instructions */
pbrook624f7972008-05-31 16:11:38 +00002351 if (ka->sa_restorer)
2352 env->regwptr[UREG_I7] = ka->sa_restorer;
bellard6d5e2162004-09-30 22:04:13 +00002353 else {
bellard775b58d2007-11-11 16:22:17 +00002354 uint32_t val32;
bellard459a4012007-11-11 19:45:10 +00002355
2356 env->regwptr[UREG_I7] = sf_addr +
2357 offsetof(struct target_signal_frame, insns) - 2 * 4;
bellard6d5e2162004-09-30 22:04:13 +00002358
2359 /* mov __NR_sigreturn, %g1 */
bellard775b58d2007-11-11 16:22:17 +00002360 val32 = 0x821020d8;
Riku Voipio1d8b5122014-04-23 10:26:05 +03002361 __put_user(val32, &sf->insns[0]);
bellard6d5e2162004-09-30 22:04:13 +00002362
2363 /* t 0x10 */
bellard775b58d2007-11-11 16:22:17 +00002364 val32 = 0x91d02010;
Riku Voipio1d8b5122014-04-23 10:26:05 +03002365 __put_user(val32, &sf->insns[1]);
bellard6d5e2162004-09-30 22:04:13 +00002366 if (err)
2367 goto sigsegv;
2368
2369 /* Flush instruction space. */
2370 //flush_sig_insns(current->mm, (unsigned long) &(sf->insns[0]));
bellard80a9d032005-01-03 23:31:27 +00002371 // tb_flush(env);
bellard6d5e2162004-09-30 22:04:13 +00002372 }
bellard459a4012007-11-11 19:45:10 +00002373 unlock_user(sf, sf_addr, sizeof(struct target_signal_frame));
bellard6d5e2162004-09-30 22:04:13 +00002374 return;
bellard459a4012007-11-11 19:45:10 +00002375#if 0
2376sigill_and_return:
bellard6d5e2162004-09-30 22:04:13 +00002377 force_sig(TARGET_SIGILL);
bellard459a4012007-11-11 19:45:10 +00002378#endif
bellard6d5e2162004-09-30 22:04:13 +00002379sigsegv:
bellarde80cfcf2004-12-19 23:18:01 +00002380 //fprintf(stderr, "force_sig\n");
bellard459a4012007-11-11 19:45:10 +00002381 unlock_user(sf, sf_addr, sizeof(struct target_signal_frame));
bellard6d5e2162004-09-30 22:04:13 +00002382 force_sig(TARGET_SIGSEGV);
2383}
bellard6d5e2162004-09-30 22:04:13 +00002384
pbrook624f7972008-05-31 16:11:38 +00002385static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05002386 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01002387 target_sigset_t *set, CPUSPARCState *env)
bellard6d5e2162004-09-30 22:04:13 +00002388{
2389 fprintf(stderr, "setup_rt_frame: not implemented\n");
2390}
2391
Andreas Färber05390242012-02-25 03:37:53 +01002392long do_sigreturn(CPUSPARCState *env)
bellard6d5e2162004-09-30 22:04:13 +00002393{
bellardf8b0aa22007-11-11 23:03:42 +00002394 abi_ulong sf_addr;
bellard6d5e2162004-09-30 22:04:13 +00002395 struct target_signal_frame *sf;
bellarde80cfcf2004-12-19 23:18:01 +00002396 uint32_t up_psr, pc, npc;
Anthony Liguoric227f092009-10-01 16:12:16 -05002397 target_sigset_t set;
bellarde80cfcf2004-12-19 23:18:01 +00002398 sigset_t host_set;
Riku Voipio1d8b5122014-04-23 10:26:05 +03002399 int err=0, i;
bellard6d5e2162004-09-30 22:04:13 +00002400
bellardf8b0aa22007-11-11 23:03:42 +00002401 sf_addr = env->regwptr[UREG_FP];
2402 if (!lock_user_struct(VERIFY_READ, sf, sf_addr, 1))
2403 goto segv_and_exit;
bellard80a9d032005-01-03 23:31:27 +00002404#if 0
bellarde80cfcf2004-12-19 23:18:01 +00002405 fprintf(stderr, "sigreturn\n");
2406 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 +00002407#endif
bellarde80cfcf2004-12-19 23:18:01 +00002408 //cpu_dump_state(env, stderr, fprintf, 0);
bellard6d5e2162004-09-30 22:04:13 +00002409
2410 /* 1. Make sure we are not getting garbage from the user */
bellard6d5e2162004-09-30 22:04:13 +00002411
bellardf8b0aa22007-11-11 23:03:42 +00002412 if (sf_addr & 3)
bellard6d5e2162004-09-30 22:04:13 +00002413 goto segv_and_exit;
2414
Riku Voipio1d8b5122014-04-23 10:26:05 +03002415 __get_user(pc, &sf->info.si_regs.pc);
2416 __get_user(npc, &sf->info.si_regs.npc);
bellard6d5e2162004-09-30 22:04:13 +00002417
bellard6d5e2162004-09-30 22:04:13 +00002418 if ((pc | npc) & 3)
2419 goto segv_and_exit;
2420
2421 /* 2. Restore the state */
Riku Voipio1d8b5122014-04-23 10:26:05 +03002422 __get_user(up_psr, &sf->info.si_regs.psr);
bellarde80cfcf2004-12-19 23:18:01 +00002423
bellard6d5e2162004-09-30 22:04:13 +00002424 /* User can only change condition codes and FPU enabling in %psr. */
bellarda315a142005-01-30 22:59:18 +00002425 env->psr = (up_psr & (PSR_ICC /* | PSR_EF */))
2426 | (env->psr & ~(PSR_ICC /* | PSR_EF */));
2427
2428 env->pc = pc;
2429 env->npc = npc;
Riku Voipio1d8b5122014-04-23 10:26:05 +03002430 __get_user(env->y, &sf->info.si_regs.y);
bellarda315a142005-01-30 22:59:18 +00002431 for (i=0; i < 8; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002432 __get_user(env->gregs[i], &sf->info.si_regs.u_regs[i]);
bellarde80cfcf2004-12-19 23:18:01 +00002433 }
bellarda315a142005-01-30 22:59:18 +00002434 for (i=0; i < 8; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002435 __get_user(env->regwptr[i + UREG_I0], &sf->info.si_regs.u_regs[i+8]);
bellarde80cfcf2004-12-19 23:18:01 +00002436 }
bellard6d5e2162004-09-30 22:04:13 +00002437
Peter Maydell2aec3a22011-06-16 17:37:14 +01002438 /* FIXME: implement FPU save/restore:
2439 * __get_user(fpu_save, &sf->fpu_save);
2440 * if (fpu_save)
2441 * err |= restore_fpu_state(env, fpu_save);
2442 */
bellard6d5e2162004-09-30 22:04:13 +00002443
2444 /* This is pretty much atomic, no amount locking would prevent
2445 * the races which exist anyways.
2446 */
Riku Voipio1d8b5122014-04-23 10:26:05 +03002447 __get_user(set.sig[0], &sf->info.si_mask);
bellarde80cfcf2004-12-19 23:18:01 +00002448 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002449 __get_user(set.sig[i], &sf->extramask[i - 1]);
bellarde80cfcf2004-12-19 23:18:01 +00002450 }
2451
2452 target_to_host_sigset_internal(&host_set, &set);
Alex Barcelo1c275922014-03-14 14:36:55 +00002453 do_sigprocmask(SIG_SETMASK, &host_set, NULL);
bellard6d5e2162004-09-30 22:04:13 +00002454
2455 if (err)
2456 goto segv_and_exit;
bellardf8b0aa22007-11-11 23:03:42 +00002457 unlock_user_struct(sf, sf_addr, 0);
bellard6d5e2162004-09-30 22:04:13 +00002458 return env->regwptr[0];
2459
2460segv_and_exit:
bellardf8b0aa22007-11-11 23:03:42 +00002461 unlock_user_struct(sf, sf_addr, 0);
bellard6d5e2162004-09-30 22:04:13 +00002462 force_sig(TARGET_SIGSEGV);
2463}
2464
Andreas Färber05390242012-02-25 03:37:53 +01002465long do_rt_sigreturn(CPUSPARCState *env)
bellard6d5e2162004-09-30 22:04:13 +00002466{
2467 fprintf(stderr, "do_rt_sigreturn: not implemented\n");
bellardf8b0aa22007-11-11 23:03:42 +00002468 return -TARGET_ENOSYS;
bellard6d5e2162004-09-30 22:04:13 +00002469}
2470
bellard459a4012007-11-11 19:45:10 +00002471#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
blueswir15bfb56b2007-10-05 17:01:51 +00002472#define MC_TSTATE 0
2473#define MC_PC 1
2474#define MC_NPC 2
2475#define MC_Y 3
2476#define MC_G1 4
2477#define MC_G2 5
2478#define MC_G3 6
2479#define MC_G4 7
2480#define MC_G5 8
2481#define MC_G6 9
2482#define MC_G7 10
2483#define MC_O0 11
2484#define MC_O1 12
2485#define MC_O2 13
2486#define MC_O3 14
2487#define MC_O4 15
2488#define MC_O5 16
2489#define MC_O6 17
2490#define MC_O7 18
2491#define MC_NGREG 19
2492
Anthony Liguoric227f092009-10-01 16:12:16 -05002493typedef abi_ulong target_mc_greg_t;
2494typedef target_mc_greg_t target_mc_gregset_t[MC_NGREG];
blueswir15bfb56b2007-10-05 17:01:51 +00002495
2496struct target_mc_fq {
blueswir1992f48a2007-10-14 16:27:31 +00002497 abi_ulong *mcfq_addr;
blueswir15bfb56b2007-10-05 17:01:51 +00002498 uint32_t mcfq_insn;
2499};
2500
2501struct target_mc_fpu {
2502 union {
2503 uint32_t sregs[32];
2504 uint64_t dregs[32];
2505 //uint128_t qregs[16];
2506 } mcfpu_fregs;
blueswir1992f48a2007-10-14 16:27:31 +00002507 abi_ulong mcfpu_fsr;
2508 abi_ulong mcfpu_fprs;
2509 abi_ulong mcfpu_gsr;
blueswir15bfb56b2007-10-05 17:01:51 +00002510 struct target_mc_fq *mcfpu_fq;
2511 unsigned char mcfpu_qcnt;
2512 unsigned char mcfpu_qentsz;
2513 unsigned char mcfpu_enab;
2514};
Anthony Liguoric227f092009-10-01 16:12:16 -05002515typedef struct target_mc_fpu target_mc_fpu_t;
blueswir15bfb56b2007-10-05 17:01:51 +00002516
2517typedef struct {
Anthony Liguoric227f092009-10-01 16:12:16 -05002518 target_mc_gregset_t mc_gregs;
2519 target_mc_greg_t mc_fp;
2520 target_mc_greg_t mc_i7;
2521 target_mc_fpu_t mc_fpregs;
2522} target_mcontext_t;
blueswir15bfb56b2007-10-05 17:01:51 +00002523
2524struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02002525 struct target_ucontext *tuc_link;
2526 abi_ulong tuc_flags;
2527 target_sigset_t tuc_sigmask;
2528 target_mcontext_t tuc_mcontext;
blueswir15bfb56b2007-10-05 17:01:51 +00002529};
2530
2531/* A V9 register window */
2532struct target_reg_window {
blueswir1992f48a2007-10-14 16:27:31 +00002533 abi_ulong locals[8];
2534 abi_ulong ins[8];
blueswir15bfb56b2007-10-05 17:01:51 +00002535};
2536
2537#define TARGET_STACK_BIAS 2047
2538
2539/* {set, get}context() needed for 64-bit SparcLinux userland. */
2540void sparc64_set_context(CPUSPARCState *env)
2541{
bellard459a4012007-11-11 19:45:10 +00002542 abi_ulong ucp_addr;
2543 struct target_ucontext *ucp;
Anthony Liguoric227f092009-10-01 16:12:16 -05002544 target_mc_gregset_t *grp;
blueswir1992f48a2007-10-14 16:27:31 +00002545 abi_ulong pc, npc, tstate;
bellard459a4012007-11-11 19:45:10 +00002546 abi_ulong fp, i7, w_addr;
Riku Voipio1d8b5122014-04-23 10:26:05 +03002547 int err = 0;
blueswir15bfb56b2007-10-05 17:01:51 +00002548 unsigned int i;
blueswir15bfb56b2007-10-05 17:01:51 +00002549
bellard459a4012007-11-11 19:45:10 +00002550 ucp_addr = env->regwptr[UREG_I0];
2551 if (!lock_user_struct(VERIFY_READ, ucp, ucp_addr, 1))
2552 goto do_sigsegv;
Aurelien Jarno60e99242010-03-29 02:12:51 +02002553 grp = &ucp->tuc_mcontext.mc_gregs;
Riku Voipio1d8b5122014-04-23 10:26:05 +03002554 __get_user(pc, &((*grp)[MC_PC]));
2555 __get_user(npc, &((*grp)[MC_NPC]));
blueswir15bfb56b2007-10-05 17:01:51 +00002556 if (err || ((pc | npc) & 3))
2557 goto do_sigsegv;
2558 if (env->regwptr[UREG_I1]) {
Anthony Liguoric227f092009-10-01 16:12:16 -05002559 target_sigset_t target_set;
blueswir15bfb56b2007-10-05 17:01:51 +00002560 sigset_t set;
2561
2562 if (TARGET_NSIG_WORDS == 1) {
Aurelien Jarno60e99242010-03-29 02:12:51 +02002563 if (__get_user(target_set.sig[0], &ucp->tuc_sigmask.sig[0]))
blueswir15bfb56b2007-10-05 17:01:51 +00002564 goto do_sigsegv;
2565 } else {
bellard459a4012007-11-11 19:45:10 +00002566 abi_ulong *src, *dst;
Aurelien Jarno60e99242010-03-29 02:12:51 +02002567 src = ucp->tuc_sigmask.sig;
bellard459a4012007-11-11 19:45:10 +00002568 dst = target_set.sig;
Stefan Weil0d9e61c2013-12-07 14:48:08 +01002569 for (i = 0; i < TARGET_NSIG_WORDS; i++, dst++, src++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002570 __get_user(*dst, src);
Stefan Weil0d9e61c2013-12-07 14:48:08 +01002571 }
blueswir15bfb56b2007-10-05 17:01:51 +00002572 if (err)
2573 goto do_sigsegv;
2574 }
2575 target_to_host_sigset_internal(&set, &target_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00002576 do_sigprocmask(SIG_SETMASK, &set, NULL);
blueswir15bfb56b2007-10-05 17:01:51 +00002577 }
2578 env->pc = pc;
2579 env->npc = npc;
Riku Voipio1d8b5122014-04-23 10:26:05 +03002580 __get_user(env->y, &((*grp)[MC_Y]));
2581 __get_user(tstate, &((*grp)[MC_TSTATE]));
blueswir15bfb56b2007-10-05 17:01:51 +00002582 env->asi = (tstate >> 24) & 0xff;
Blue Swirl5a834bb2010-05-09 20:19:04 +00002583 cpu_put_ccr(env, tstate >> 32);
2584 cpu_put_cwp64(env, tstate & 0x1f);
Riku Voipio1d8b5122014-04-23 10:26:05 +03002585 __get_user(env->gregs[1], (&(*grp)[MC_G1]));
2586 __get_user(env->gregs[2], (&(*grp)[MC_G2]));
2587 __get_user(env->gregs[3], (&(*grp)[MC_G3]));
2588 __get_user(env->gregs[4], (&(*grp)[MC_G4]));
2589 __get_user(env->gregs[5], (&(*grp)[MC_G5]));
2590 __get_user(env->gregs[6], (&(*grp)[MC_G6]));
2591 __get_user(env->gregs[7], (&(*grp)[MC_G7]));
2592 __get_user(env->regwptr[UREG_I0], (&(*grp)[MC_O0]));
2593 __get_user(env->regwptr[UREG_I1], (&(*grp)[MC_O1]));
2594 __get_user(env->regwptr[UREG_I2], (&(*grp)[MC_O2]));
2595 __get_user(env->regwptr[UREG_I3], (&(*grp)[MC_O3]));
2596 __get_user(env->regwptr[UREG_I4], (&(*grp)[MC_O4]));
2597 __get_user(env->regwptr[UREG_I5], (&(*grp)[MC_O5]));
2598 __get_user(env->regwptr[UREG_I6], (&(*grp)[MC_O6]));
2599 __get_user(env->regwptr[UREG_I7], (&(*grp)[MC_O7]));
blueswir15bfb56b2007-10-05 17:01:51 +00002600
Riku Voipio1d8b5122014-04-23 10:26:05 +03002601 __get_user(fp, &(ucp->tuc_mcontext.mc_fp));
2602 __get_user(i7, &(ucp->tuc_mcontext.mc_i7));
blueswir15bfb56b2007-10-05 17:01:51 +00002603
bellard459a4012007-11-11 19:45:10 +00002604 w_addr = TARGET_STACK_BIAS+env->regwptr[UREG_I6];
2605 if (put_user(fp, w_addr + offsetof(struct target_reg_window, ins[6]),
2606 abi_ulong) != 0)
2607 goto do_sigsegv;
2608 if (put_user(i7, w_addr + offsetof(struct target_reg_window, ins[7]),
2609 abi_ulong) != 0)
2610 goto do_sigsegv;
Peter Maydellc7b016b2011-06-16 17:37:15 +01002611 /* FIXME this does not match how the kernel handles the FPU in
2612 * its sparc64_set_context implementation. In particular the FPU
2613 * is only restored if fenab is non-zero in:
2614 * __get_user(fenab, &(ucp->tuc_mcontext.mc_fpregs.mcfpu_enab));
2615 */
Aurelien Jarno60e99242010-03-29 02:12:51 +02002616 err |= __get_user(env->fprs, &(ucp->tuc_mcontext.mc_fpregs.mcfpu_fprs));
bellard459a4012007-11-11 19:45:10 +00002617 {
Richard Henderson30038fd2011-10-17 10:42:49 -07002618 uint32_t *src = ucp->tuc_mcontext.mc_fpregs.mcfpu_fregs.sregs;
2619 for (i = 0; i < 64; i++, src++) {
2620 if (i & 1) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002621 __get_user(env->fpr[i/2].l.lower, src);
Richard Henderson30038fd2011-10-17 10:42:49 -07002622 } else {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002623 __get_user(env->fpr[i/2].l.upper, src);
Richard Henderson30038fd2011-10-17 10:42:49 -07002624 }
2625 }
bellard459a4012007-11-11 19:45:10 +00002626 }
Riku Voipio1d8b5122014-04-23 10:26:05 +03002627 __get_user(env->fsr,
2628 &(ucp->tuc_mcontext.mc_fpregs.mcfpu_fsr));
2629 __get_user(env->gsr,
2630 &(ucp->tuc_mcontext.mc_fpregs.mcfpu_gsr));
blueswir15bfb56b2007-10-05 17:01:51 +00002631 if (err)
2632 goto do_sigsegv;
bellard459a4012007-11-11 19:45:10 +00002633 unlock_user_struct(ucp, ucp_addr, 0);
blueswir15bfb56b2007-10-05 17:01:51 +00002634 return;
2635 do_sigsegv:
bellard459a4012007-11-11 19:45:10 +00002636 unlock_user_struct(ucp, ucp_addr, 0);
Riku Voipio66393fb2009-12-04 15:16:32 +02002637 force_sig(TARGET_SIGSEGV);
blueswir15bfb56b2007-10-05 17:01:51 +00002638}
2639
2640void sparc64_get_context(CPUSPARCState *env)
2641{
bellard459a4012007-11-11 19:45:10 +00002642 abi_ulong ucp_addr;
2643 struct target_ucontext *ucp;
Anthony Liguoric227f092009-10-01 16:12:16 -05002644 target_mc_gregset_t *grp;
2645 target_mcontext_t *mcp;
bellard459a4012007-11-11 19:45:10 +00002646 abi_ulong fp, i7, w_addr;
blueswir15bfb56b2007-10-05 17:01:51 +00002647 int err;
2648 unsigned int i;
Anthony Liguoric227f092009-10-01 16:12:16 -05002649 target_sigset_t target_set;
blueswir15bfb56b2007-10-05 17:01:51 +00002650 sigset_t set;
2651
bellard459a4012007-11-11 19:45:10 +00002652 ucp_addr = env->regwptr[UREG_I0];
2653 if (!lock_user_struct(VERIFY_WRITE, ucp, ucp_addr, 0))
2654 goto do_sigsegv;
2655
Aurelien Jarno60e99242010-03-29 02:12:51 +02002656 mcp = &ucp->tuc_mcontext;
blueswir15bfb56b2007-10-05 17:01:51 +00002657 grp = &mcp->mc_gregs;
2658
2659 /* Skip over the trap instruction, first. */
2660 env->pc = env->npc;
2661 env->npc += 4;
2662
2663 err = 0;
2664
Alex Barcelo1c275922014-03-14 14:36:55 +00002665 do_sigprocmask(0, NULL, &set);
blueswir15bfb56b2007-10-05 17:01:51 +00002666 host_to_target_sigset_internal(&target_set, &set);
bellard459a4012007-11-11 19:45:10 +00002667 if (TARGET_NSIG_WORDS == 1) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002668 __put_user(target_set.sig[0],
2669 (abi_ulong *)&ucp->tuc_sigmask);
bellard459a4012007-11-11 19:45:10 +00002670 } else {
2671 abi_ulong *src, *dst;
2672 src = target_set.sig;
Aurelien Jarno60e99242010-03-29 02:12:51 +02002673 dst = ucp->tuc_sigmask.sig;
Stefan Weil0d9e61c2013-12-07 14:48:08 +01002674 for (i = 0; i < TARGET_NSIG_WORDS; i++, dst++, src++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002675 __put_user(*src, dst);
Stefan Weil0d9e61c2013-12-07 14:48:08 +01002676 }
blueswir15bfb56b2007-10-05 17:01:51 +00002677 if (err)
2678 goto do_sigsegv;
2679 }
2680
bellard459a4012007-11-11 19:45:10 +00002681 /* XXX: tstate must be saved properly */
Riku Voipio1d8b5122014-04-23 10:26:05 +03002682 // __put_user(env->tstate, &((*grp)[MC_TSTATE]));
2683 __put_user(env->pc, &((*grp)[MC_PC]));
2684 __put_user(env->npc, &((*grp)[MC_NPC]));
2685 __put_user(env->y, &((*grp)[MC_Y]));
2686 __put_user(env->gregs[1], &((*grp)[MC_G1]));
2687 __put_user(env->gregs[2], &((*grp)[MC_G2]));
2688 __put_user(env->gregs[3], &((*grp)[MC_G3]));
2689 __put_user(env->gregs[4], &((*grp)[MC_G4]));
2690 __put_user(env->gregs[5], &((*grp)[MC_G5]));
2691 __put_user(env->gregs[6], &((*grp)[MC_G6]));
2692 __put_user(env->gregs[7], &((*grp)[MC_G7]));
2693 __put_user(env->regwptr[UREG_I0], &((*grp)[MC_O0]));
2694 __put_user(env->regwptr[UREG_I1], &((*grp)[MC_O1]));
2695 __put_user(env->regwptr[UREG_I2], &((*grp)[MC_O2]));
2696 __put_user(env->regwptr[UREG_I3], &((*grp)[MC_O3]));
2697 __put_user(env->regwptr[UREG_I4], &((*grp)[MC_O4]));
2698 __put_user(env->regwptr[UREG_I5], &((*grp)[MC_O5]));
2699 __put_user(env->regwptr[UREG_I6], &((*grp)[MC_O6]));
2700 __put_user(env->regwptr[UREG_I7], &((*grp)[MC_O7]));
blueswir15bfb56b2007-10-05 17:01:51 +00002701
bellard459a4012007-11-11 19:45:10 +00002702 w_addr = TARGET_STACK_BIAS+env->regwptr[UREG_I6];
2703 fp = i7 = 0;
2704 if (get_user(fp, w_addr + offsetof(struct target_reg_window, ins[6]),
2705 abi_ulong) != 0)
2706 goto do_sigsegv;
2707 if (get_user(i7, w_addr + offsetof(struct target_reg_window, ins[7]),
2708 abi_ulong) != 0)
2709 goto do_sigsegv;
Riku Voipio1d8b5122014-04-23 10:26:05 +03002710 __put_user(fp, &(mcp->mc_fp));
2711 __put_user(i7, &(mcp->mc_i7));
blueswir15bfb56b2007-10-05 17:01:51 +00002712
bellard459a4012007-11-11 19:45:10 +00002713 {
Richard Henderson30038fd2011-10-17 10:42:49 -07002714 uint32_t *dst = ucp->tuc_mcontext.mc_fpregs.mcfpu_fregs.sregs;
2715 for (i = 0; i < 64; i++, dst++) {
2716 if (i & 1) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002717 __put_user(env->fpr[i/2].l.lower, dst);
Richard Henderson30038fd2011-10-17 10:42:49 -07002718 } else {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002719 __put_user(env->fpr[i/2].l.upper, dst);
Richard Henderson30038fd2011-10-17 10:42:49 -07002720 }
2721 }
bellard459a4012007-11-11 19:45:10 +00002722 }
Riku Voipio1d8b5122014-04-23 10:26:05 +03002723 __put_user(env->fsr, &(mcp->mc_fpregs.mcfpu_fsr));
2724 __put_user(env->gsr, &(mcp->mc_fpregs.mcfpu_gsr));
2725 __put_user(env->fprs, &(mcp->mc_fpregs.mcfpu_fprs));
blueswir15bfb56b2007-10-05 17:01:51 +00002726
2727 if (err)
2728 goto do_sigsegv;
bellard459a4012007-11-11 19:45:10 +00002729 unlock_user_struct(ucp, ucp_addr, 1);
blueswir15bfb56b2007-10-05 17:01:51 +00002730 return;
2731 do_sigsegv:
bellard459a4012007-11-11 19:45:10 +00002732 unlock_user_struct(ucp, ucp_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02002733 force_sig(TARGET_SIGSEGV);
blueswir15bfb56b2007-10-05 17:01:51 +00002734}
2735#endif
Richard Hendersonff970902013-02-10 10:30:42 -08002736#elif defined(TARGET_MIPS) || defined(TARGET_MIPS64)
bellard106ec872006-06-27 21:08:10 +00002737
Richard Hendersonff970902013-02-10 10:30:42 -08002738# if defined(TARGET_ABI_MIPSO32)
bellard106ec872006-06-27 21:08:10 +00002739struct target_sigcontext {
2740 uint32_t sc_regmask; /* Unused */
2741 uint32_t sc_status;
2742 uint64_t sc_pc;
2743 uint64_t sc_regs[32];
2744 uint64_t sc_fpregs[32];
2745 uint32_t sc_ownedfp; /* Unused */
2746 uint32_t sc_fpc_csr;
2747 uint32_t sc_fpc_eir; /* Unused */
2748 uint32_t sc_used_math;
2749 uint32_t sc_dsp; /* dsp status, was sc_ssflags */
Paul Brook94c54952009-07-09 18:40:15 +01002750 uint32_t pad0;
bellard106ec872006-06-27 21:08:10 +00002751 uint64_t sc_mdhi;
2752 uint64_t sc_mdlo;
2753 target_ulong sc_hi1; /* Was sc_cause */
2754 target_ulong sc_lo1; /* Was sc_badvaddr */
2755 target_ulong sc_hi2; /* Was sc_sigset[4] */
2756 target_ulong sc_lo2;
2757 target_ulong sc_hi3;
2758 target_ulong sc_lo3;
2759};
Richard Hendersonff970902013-02-10 10:30:42 -08002760# else /* N32 || N64 */
2761struct target_sigcontext {
2762 uint64_t sc_regs[32];
2763 uint64_t sc_fpregs[32];
2764 uint64_t sc_mdhi;
2765 uint64_t sc_hi1;
2766 uint64_t sc_hi2;
2767 uint64_t sc_hi3;
2768 uint64_t sc_mdlo;
2769 uint64_t sc_lo1;
2770 uint64_t sc_lo2;
2771 uint64_t sc_lo3;
2772 uint64_t sc_pc;
2773 uint32_t sc_fpc_csr;
2774 uint32_t sc_used_math;
2775 uint32_t sc_dsp;
2776 uint32_t sc_reserved;
2777};
2778# endif /* O32 */
bellard106ec872006-06-27 21:08:10 +00002779
2780struct sigframe {
2781 uint32_t sf_ass[4]; /* argument save space for o32 */
2782 uint32_t sf_code[2]; /* signal trampoline */
2783 struct target_sigcontext sf_sc;
Anthony Liguoric227f092009-10-01 16:12:16 -05002784 target_sigset_t sf_mask;
bellard106ec872006-06-27 21:08:10 +00002785};
2786
pbrook0b1bcb02009-04-21 01:41:10 +00002787struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02002788 target_ulong tuc_flags;
2789 target_ulong tuc_link;
2790 target_stack_t tuc_stack;
Paul Brook94c54952009-07-09 18:40:15 +01002791 target_ulong pad0;
Aurelien Jarno60e99242010-03-29 02:12:51 +02002792 struct target_sigcontext tuc_mcontext;
2793 target_sigset_t tuc_sigmask;
pbrook0b1bcb02009-04-21 01:41:10 +00002794};
2795
2796struct target_rt_sigframe {
2797 uint32_t rs_ass[4]; /* argument save space for o32 */
2798 uint32_t rs_code[2]; /* signal trampoline */
2799 struct target_siginfo rs_info;
2800 struct target_ucontext rs_uc;
2801};
2802
bellard106ec872006-06-27 21:08:10 +00002803/* Install trampoline to jump back from signal handler */
2804static inline int install_sigtramp(unsigned int *tramp, unsigned int syscall)
2805{
Richard Henderson084d0492013-02-10 10:30:44 -08002806 int err = 0;
bellard106ec872006-06-27 21:08:10 +00002807
2808 /*
Richard Henderson084d0492013-02-10 10:30:44 -08002809 * Set up the return code ...
2810 *
2811 * li v0, __NR__foo_sigreturn
2812 * syscall
2813 */
bellard106ec872006-06-27 21:08:10 +00002814
Riku Voipio1d8b5122014-04-23 10:26:05 +03002815 __put_user(0x24020000 + syscall, tramp + 0);
2816 __put_user(0x0000000c , tramp + 1);
bellard106ec872006-06-27 21:08:10 +00002817 return err;
2818}
2819
Riku Voipio41ecc722014-04-23 11:01:00 +03002820static inline void setup_sigcontext(CPUMIPSState *regs,
2821 struct target_sigcontext *sc)
bellard106ec872006-06-27 21:08:10 +00002822{
Richard Henderson084d0492013-02-10 10:30:44 -08002823 int i;
bellard106ec872006-06-27 21:08:10 +00002824
Riku Voipio1d8b5122014-04-23 10:26:05 +03002825 __put_user(exception_resume_pc(regs), &sc->sc_pc);
Kwok Cheung Yeung1239b472013-05-17 14:51:21 -07002826 regs->hflags &= ~MIPS_HFLAG_BMASK;
bellard106ec872006-06-27 21:08:10 +00002827
Richard Henderson084d0492013-02-10 10:30:44 -08002828 __put_user(0, &sc->sc_regs[0]);
2829 for (i = 1; i < 32; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002830 __put_user(regs->active_tc.gpr[i], &sc->sc_regs[i]);
Richard Henderson084d0492013-02-10 10:30:44 -08002831 }
bellard106ec872006-06-27 21:08:10 +00002832
Riku Voipio1d8b5122014-04-23 10:26:05 +03002833 __put_user(regs->active_tc.HI[0], &sc->sc_mdhi);
2834 __put_user(regs->active_tc.LO[0], &sc->sc_mdlo);
bellard106ec872006-06-27 21:08:10 +00002835
Richard Henderson084d0492013-02-10 10:30:44 -08002836 /* Rather than checking for dsp existence, always copy. The storage
2837 would just be garbage otherwise. */
Riku Voipio1d8b5122014-04-23 10:26:05 +03002838 __put_user(regs->active_tc.HI[1], &sc->sc_hi1);
2839 __put_user(regs->active_tc.HI[2], &sc->sc_hi2);
2840 __put_user(regs->active_tc.HI[3], &sc->sc_hi3);
2841 __put_user(regs->active_tc.LO[1], &sc->sc_lo1);
2842 __put_user(regs->active_tc.LO[2], &sc->sc_lo2);
2843 __put_user(regs->active_tc.LO[3], &sc->sc_lo3);
Richard Henderson084d0492013-02-10 10:30:44 -08002844 {
2845 uint32_t dsp = cpu_rddsp(0x3ff, regs);
Riku Voipio1d8b5122014-04-23 10:26:05 +03002846 __put_user(dsp, &sc->sc_dsp);
bellard106ec872006-06-27 21:08:10 +00002847 }
Richard Henderson084d0492013-02-10 10:30:44 -08002848
Riku Voipio1d8b5122014-04-23 10:26:05 +03002849 __put_user(1, &sc->sc_used_math);
Richard Henderson084d0492013-02-10 10:30:44 -08002850
2851 for (i = 0; i < 32; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002852 __put_user(regs->active_fpu.fpr[i].d, &sc->sc_fpregs[i]);
bellard106ec872006-06-27 21:08:10 +00002853 }
bellard106ec872006-06-27 21:08:10 +00002854}
2855
Riku Voipio016d2e12014-04-23 11:19:48 +03002856static inline void
Andreas Färber05390242012-02-25 03:37:53 +01002857restore_sigcontext(CPUMIPSState *regs, struct target_sigcontext *sc)
bellard106ec872006-06-27 21:08:10 +00002858{
Richard Henderson084d0492013-02-10 10:30:44 -08002859 int i;
bellard106ec872006-06-27 21:08:10 +00002860
Riku Voipio1d8b5122014-04-23 10:26:05 +03002861 __get_user(regs->CP0_EPC, &sc->sc_pc);
bellard106ec872006-06-27 21:08:10 +00002862
Riku Voipio1d8b5122014-04-23 10:26:05 +03002863 __get_user(regs->active_tc.HI[0], &sc->sc_mdhi);
2864 __get_user(regs->active_tc.LO[0], &sc->sc_mdlo);
bellard106ec872006-06-27 21:08:10 +00002865
Richard Henderson084d0492013-02-10 10:30:44 -08002866 for (i = 1; i < 32; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002867 __get_user(regs->active_tc.gpr[i], &sc->sc_regs[i]);
bellard106ec872006-06-27 21:08:10 +00002868 }
2869
Riku Voipio1d8b5122014-04-23 10:26:05 +03002870 __get_user(regs->active_tc.HI[1], &sc->sc_hi1);
2871 __get_user(regs->active_tc.HI[2], &sc->sc_hi2);
2872 __get_user(regs->active_tc.HI[3], &sc->sc_hi3);
2873 __get_user(regs->active_tc.LO[1], &sc->sc_lo1);
2874 __get_user(regs->active_tc.LO[2], &sc->sc_lo2);
2875 __get_user(regs->active_tc.LO[3], &sc->sc_lo3);
Richard Henderson084d0492013-02-10 10:30:44 -08002876 {
2877 uint32_t dsp;
Riku Voipio1d8b5122014-04-23 10:26:05 +03002878 __get_user(dsp, &sc->sc_dsp);
Richard Henderson084d0492013-02-10 10:30:44 -08002879 cpu_wrdsp(dsp, 0x3ff, regs);
2880 }
2881
2882 for (i = 0; i < 32; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002883 __get_user(regs->active_fpu.fpr[i].d, &sc->sc_fpregs[i]);
Richard Henderson084d0492013-02-10 10:30:44 -08002884 }
bellard106ec872006-06-27 21:08:10 +00002885}
Richard Hendersonff970902013-02-10 10:30:42 -08002886
bellard106ec872006-06-27 21:08:10 +00002887/*
2888 * Determine which stack to use..
2889 */
bellard579a97f2007-11-11 14:26:47 +00002890static inline abi_ulong
Andreas Färber05390242012-02-25 03:37:53 +01002891get_sigframe(struct target_sigaction *ka, CPUMIPSState *regs, size_t frame_size)
bellard106ec872006-06-27 21:08:10 +00002892{
2893 unsigned long sp;
2894
2895 /* Default to using normal stack */
thsb5dc7732008-06-27 10:02:35 +00002896 sp = regs->active_tc.gpr[29];
bellard106ec872006-06-27 21:08:10 +00002897
2898 /*
Stefan Weil93148aa2012-02-26 18:46:12 +01002899 * FPU emulator may have its own trampoline active just
bellard106ec872006-06-27 21:08:10 +00002900 * above the user stack, 16-bytes before the next lowest
2901 * 16 byte boundary. Try to avoid trashing it.
2902 */
2903 sp -= 32;
2904
bellard106ec872006-06-27 21:08:10 +00002905 /* This is the X/Open sanctioned signal stack switching. */
pbrook624f7972008-05-31 16:11:38 +00002906 if ((ka->sa_flags & TARGET_SA_ONSTACK) && (sas_ss_flags (sp) == 0)) {
thsa04e1342007-09-27 13:57:58 +00002907 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
2908 }
bellard106ec872006-06-27 21:08:10 +00002909
bellard579a97f2007-11-11 14:26:47 +00002910 return (sp - frame_size) & ~7;
bellard106ec872006-06-27 21:08:10 +00002911}
2912
Kwok Cheung Yeungea3164a2013-05-17 14:51:20 -07002913static void mips_set_hflags_isa_mode_from_pc(CPUMIPSState *env)
2914{
2915 if (env->insn_flags & (ASE_MIPS16 | ASE_MICROMIPS)) {
2916 env->hflags &= ~MIPS_HFLAG_M16;
2917 env->hflags |= (env->active_tc.PC & 1) << MIPS_HFLAG_M16_SHIFT;
2918 env->active_tc.PC &= ~(target_ulong) 1;
2919 }
2920}
2921
Richard Hendersonff970902013-02-10 10:30:42 -08002922# if defined(TARGET_ABI_MIPSO32)
bellard579a97f2007-11-11 14:26:47 +00002923/* compare linux/arch/mips/kernel/signal.c:setup_frame() */
pbrook624f7972008-05-31 16:11:38 +00002924static void setup_frame(int sig, struct target_sigaction * ka,
Andreas Färber05390242012-02-25 03:37:53 +01002925 target_sigset_t *set, CPUMIPSState *regs)
bellard106ec872006-06-27 21:08:10 +00002926{
2927 struct sigframe *frame;
bellard579a97f2007-11-11 14:26:47 +00002928 abi_ulong frame_addr;
bellard106ec872006-06-27 21:08:10 +00002929 int i;
2930
bellard579a97f2007-11-11 14:26:47 +00002931 frame_addr = get_sigframe(ka, regs, sizeof(*frame));
2932 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
bellard106ec872006-06-27 21:08:10 +00002933 goto give_sigsegv;
2934
2935 install_sigtramp(frame->sf_code, TARGET_NR_sigreturn);
2936
Riku Voipio41ecc722014-04-23 11:01:00 +03002937 setup_sigcontext(regs, &frame->sf_sc);
bellard106ec872006-06-27 21:08:10 +00002938
2939 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
2940 if(__put_user(set->sig[i], &frame->sf_mask.sig[i]))
2941 goto give_sigsegv;
2942 }
2943
2944 /*
2945 * Arguments to signal handler:
2946 *
2947 * a0 = signal number
2948 * a1 = 0 (should be cause)
2949 * a2 = pointer to struct sigcontext
2950 *
2951 * $25 and PC point to the signal handler, $29 points to the
2952 * struct sigframe.
2953 */
thsb5dc7732008-06-27 10:02:35 +00002954 regs->active_tc.gpr[ 4] = sig;
2955 regs->active_tc.gpr[ 5] = 0;
2956 regs->active_tc.gpr[ 6] = frame_addr + offsetof(struct sigframe, sf_sc);
2957 regs->active_tc.gpr[29] = frame_addr;
2958 regs->active_tc.gpr[31] = frame_addr + offsetof(struct sigframe, sf_code);
bellard106ec872006-06-27 21:08:10 +00002959 /* The original kernel code sets CP0_EPC to the handler
2960 * since it returns to userland using eret
2961 * we cannot do this here, and we must set PC directly */
thsb5dc7732008-06-27 10:02:35 +00002962 regs->active_tc.PC = regs->active_tc.gpr[25] = ka->_sa_handler;
Kwok Cheung Yeungea3164a2013-05-17 14:51:20 -07002963 mips_set_hflags_isa_mode_from_pc(regs);
bellard579a97f2007-11-11 14:26:47 +00002964 unlock_user_struct(frame, frame_addr, 1);
bellard106ec872006-06-27 21:08:10 +00002965 return;
2966
2967give_sigsegv:
bellard579a97f2007-11-11 14:26:47 +00002968 unlock_user_struct(frame, frame_addr, 1);
bellard106ec872006-06-27 21:08:10 +00002969 force_sig(TARGET_SIGSEGV/*, current*/);
bellard106ec872006-06-27 21:08:10 +00002970}
2971
Andreas Färber05390242012-02-25 03:37:53 +01002972long do_sigreturn(CPUMIPSState *regs)
bellard106ec872006-06-27 21:08:10 +00002973{
ths388bb212007-05-13 13:58:00 +00002974 struct sigframe *frame;
bellard579a97f2007-11-11 14:26:47 +00002975 abi_ulong frame_addr;
ths388bb212007-05-13 13:58:00 +00002976 sigset_t blocked;
Anthony Liguoric227f092009-10-01 16:12:16 -05002977 target_sigset_t target_set;
ths388bb212007-05-13 13:58:00 +00002978 int i;
bellard106ec872006-06-27 21:08:10 +00002979
2980#if defined(DEBUG_SIGNAL)
ths388bb212007-05-13 13:58:00 +00002981 fprintf(stderr, "do_sigreturn\n");
bellard106ec872006-06-27 21:08:10 +00002982#endif
thsb5dc7732008-06-27 10:02:35 +00002983 frame_addr = regs->active_tc.gpr[29];
bellard579a97f2007-11-11 14:26:47 +00002984 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
bellard106ec872006-06-27 21:08:10 +00002985 goto badframe;
2986
ths388bb212007-05-13 13:58:00 +00002987 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
bellard106ec872006-06-27 21:08:10 +00002988 if(__get_user(target_set.sig[i], &frame->sf_mask.sig[i]))
2989 goto badframe;
ths388bb212007-05-13 13:58:00 +00002990 }
bellard106ec872006-06-27 21:08:10 +00002991
ths388bb212007-05-13 13:58:00 +00002992 target_to_host_sigset_internal(&blocked, &target_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00002993 do_sigprocmask(SIG_SETMASK, &blocked, NULL);
bellard106ec872006-06-27 21:08:10 +00002994
Riku Voipio016d2e12014-04-23 11:19:48 +03002995 restore_sigcontext(regs, &frame->sf_sc);
bellard106ec872006-06-27 21:08:10 +00002996
2997#if 0
ths388bb212007-05-13 13:58:00 +00002998 /*
2999 * Don't let your children do this ...
3000 */
3001 __asm__ __volatile__(
bellard106ec872006-06-27 21:08:10 +00003002 "move\t$29, %0\n\t"
3003 "j\tsyscall_exit"
3004 :/* no outputs */
3005 :"r" (&regs));
ths388bb212007-05-13 13:58:00 +00003006 /* Unreached */
bellard106ec872006-06-27 21:08:10 +00003007#endif
ths3b46e622007-09-17 08:09:54 +00003008
thsb5dc7732008-06-27 10:02:35 +00003009 regs->active_tc.PC = regs->CP0_EPC;
Kwok Cheung Yeungea3164a2013-05-17 14:51:20 -07003010 mips_set_hflags_isa_mode_from_pc(regs);
ths388bb212007-05-13 13:58:00 +00003011 /* I am not sure this is right, but it seems to work
bellard106ec872006-06-27 21:08:10 +00003012 * maybe a problem with nested signals ? */
3013 regs->CP0_EPC = 0;
pbrook0b1bcb02009-04-21 01:41:10 +00003014 return -TARGET_QEMU_ESIGRETURN;
bellard106ec872006-06-27 21:08:10 +00003015
3016badframe:
ths388bb212007-05-13 13:58:00 +00003017 force_sig(TARGET_SIGSEGV/*, current*/);
3018 return 0;
bellard106ec872006-06-27 21:08:10 +00003019}
Richard Hendersonff970902013-02-10 10:30:42 -08003020# endif /* O32 */
bellard106ec872006-06-27 21:08:10 +00003021
pbrook624f7972008-05-31 16:11:38 +00003022static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05003023 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01003024 target_sigset_t *set, CPUMIPSState *env)
bellard106ec872006-06-27 21:08:10 +00003025{
pbrook0b1bcb02009-04-21 01:41:10 +00003026 struct target_rt_sigframe *frame;
3027 abi_ulong frame_addr;
3028 int i;
3029
3030 frame_addr = get_sigframe(ka, env, sizeof(*frame));
3031 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
3032 goto give_sigsegv;
3033
3034 install_sigtramp(frame->rs_code, TARGET_NR_rt_sigreturn);
3035
3036 copy_siginfo_to_user(&frame->rs_info, info);
3037
Aurelien Jarno60e99242010-03-29 02:12:51 +02003038 __put_user(0, &frame->rs_uc.tuc_flags);
3039 __put_user(0, &frame->rs_uc.tuc_link);
3040 __put_user(target_sigaltstack_used.ss_sp, &frame->rs_uc.tuc_stack.ss_sp);
3041 __put_user(target_sigaltstack_used.ss_size, &frame->rs_uc.tuc_stack.ss_size);
pbrook0b1bcb02009-04-21 01:41:10 +00003042 __put_user(sas_ss_flags(get_sp_from_cpustate(env)),
Aurelien Jarno60e99242010-03-29 02:12:51 +02003043 &frame->rs_uc.tuc_stack.ss_flags);
pbrook0b1bcb02009-04-21 01:41:10 +00003044
Aurelien Jarno60e99242010-03-29 02:12:51 +02003045 setup_sigcontext(env, &frame->rs_uc.tuc_mcontext);
pbrook0b1bcb02009-04-21 01:41:10 +00003046
3047 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
Aurelien Jarno60e99242010-03-29 02:12:51 +02003048 __put_user(set->sig[i], &frame->rs_uc.tuc_sigmask.sig[i]);
pbrook0b1bcb02009-04-21 01:41:10 +00003049 }
3050
3051 /*
3052 * Arguments to signal handler:
3053 *
3054 * a0 = signal number
Richard W.M. Jones02d2bd52012-07-05 03:32:44 +00003055 * a1 = pointer to siginfo_t
pbrook0b1bcb02009-04-21 01:41:10 +00003056 * a2 = pointer to struct ucontext
3057 *
3058 * $25 and PC point to the signal handler, $29 points to the
3059 * struct sigframe.
3060 */
3061 env->active_tc.gpr[ 4] = sig;
3062 env->active_tc.gpr[ 5] = frame_addr
3063 + offsetof(struct target_rt_sigframe, rs_info);
3064 env->active_tc.gpr[ 6] = frame_addr
3065 + offsetof(struct target_rt_sigframe, rs_uc);
3066 env->active_tc.gpr[29] = frame_addr;
3067 env->active_tc.gpr[31] = frame_addr
3068 + offsetof(struct target_rt_sigframe, rs_code);
3069 /* The original kernel code sets CP0_EPC to the handler
3070 * since it returns to userland using eret
3071 * we cannot do this here, and we must set PC directly */
3072 env->active_tc.PC = env->active_tc.gpr[25] = ka->_sa_handler;
Kwok Cheung Yeungea3164a2013-05-17 14:51:20 -07003073 mips_set_hflags_isa_mode_from_pc(env);
pbrook0b1bcb02009-04-21 01:41:10 +00003074 unlock_user_struct(frame, frame_addr, 1);
3075 return;
3076
3077give_sigsegv:
3078 unlock_user_struct(frame, frame_addr, 1);
3079 force_sig(TARGET_SIGSEGV/*, current*/);
bellard106ec872006-06-27 21:08:10 +00003080}
3081
Andreas Färber05390242012-02-25 03:37:53 +01003082long do_rt_sigreturn(CPUMIPSState *env)
bellard106ec872006-06-27 21:08:10 +00003083{
pbrook0b1bcb02009-04-21 01:41:10 +00003084 struct target_rt_sigframe *frame;
3085 abi_ulong frame_addr;
3086 sigset_t blocked;
3087
3088#if defined(DEBUG_SIGNAL)
3089 fprintf(stderr, "do_rt_sigreturn\n");
3090#endif
3091 frame_addr = env->active_tc.gpr[29];
3092 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
3093 goto badframe;
3094
Aurelien Jarno60e99242010-03-29 02:12:51 +02003095 target_to_host_sigset(&blocked, &frame->rs_uc.tuc_sigmask);
Alex Barcelo1c275922014-03-14 14:36:55 +00003096 do_sigprocmask(SIG_SETMASK, &blocked, NULL);
pbrook0b1bcb02009-04-21 01:41:10 +00003097
Riku Voipio016d2e12014-04-23 11:19:48 +03003098 restore_sigcontext(env, &frame->rs_uc.tuc_mcontext);
pbrook0b1bcb02009-04-21 01:41:10 +00003099
3100 if (do_sigaltstack(frame_addr +
Aurelien Jarno60e99242010-03-29 02:12:51 +02003101 offsetof(struct target_rt_sigframe, rs_uc.tuc_stack),
pbrook0b1bcb02009-04-21 01:41:10 +00003102 0, get_sp_from_cpustate(env)) == -EFAULT)
3103 goto badframe;
3104
3105 env->active_tc.PC = env->CP0_EPC;
Kwok Cheung Yeungea3164a2013-05-17 14:51:20 -07003106 mips_set_hflags_isa_mode_from_pc(env);
pbrook0b1bcb02009-04-21 01:41:10 +00003107 /* I am not sure this is right, but it seems to work
3108 * maybe a problem with nested signals ? */
3109 env->CP0_EPC = 0;
3110 return -TARGET_QEMU_ESIGRETURN;
3111
3112badframe:
3113 force_sig(TARGET_SIGSEGV/*, current*/);
3114 return 0;
bellard106ec872006-06-27 21:08:10 +00003115}
bellard6d5e2162004-09-30 22:04:13 +00003116
thsc3b5bc82007-12-02 06:31:25 +00003117#elif defined(TARGET_SH4)
3118
3119/*
3120 * code and data structures from linux kernel:
3121 * include/asm-sh/sigcontext.h
3122 * arch/sh/kernel/signal.c
3123 */
3124
3125struct target_sigcontext {
3126 target_ulong oldmask;
3127
3128 /* CPU registers */
3129 target_ulong sc_gregs[16];
3130 target_ulong sc_pc;
3131 target_ulong sc_pr;
3132 target_ulong sc_sr;
3133 target_ulong sc_gbr;
3134 target_ulong sc_mach;
3135 target_ulong sc_macl;
3136
3137 /* FPU registers */
3138 target_ulong sc_fpregs[16];
3139 target_ulong sc_xfpregs[16];
3140 unsigned int sc_fpscr;
3141 unsigned int sc_fpul;
3142 unsigned int sc_ownedfp;
3143};
3144
3145struct target_sigframe
3146{
3147 struct target_sigcontext sc;
3148 target_ulong extramask[TARGET_NSIG_WORDS-1];
3149 uint16_t retcode[3];
3150};
3151
3152
3153struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02003154 target_ulong tuc_flags;
3155 struct target_ucontext *tuc_link;
3156 target_stack_t tuc_stack;
3157 struct target_sigcontext tuc_mcontext;
3158 target_sigset_t tuc_sigmask; /* mask last for extensibility */
thsc3b5bc82007-12-02 06:31:25 +00003159};
3160
3161struct target_rt_sigframe
3162{
3163 struct target_siginfo info;
3164 struct target_ucontext uc;
3165 uint16_t retcode[3];
3166};
3167
3168
3169#define MOVW(n) (0x9300|((n)-2)) /* Move mem word at PC+n to R3 */
3170#define TRAP_NOARG 0xc310 /* Syscall w/no args (NR in R3) SH3/4 */
3171
pbrook624f7972008-05-31 16:11:38 +00003172static abi_ulong get_sigframe(struct target_sigaction *ka,
thsc3b5bc82007-12-02 06:31:25 +00003173 unsigned long sp, size_t frame_size)
3174{
pbrook624f7972008-05-31 16:11:38 +00003175 if ((ka->sa_flags & TARGET_SA_ONSTACK) && (sas_ss_flags(sp) == 0)) {
thsc3b5bc82007-12-02 06:31:25 +00003176 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
3177 }
3178
3179 return (sp - frame_size) & -8ul;
3180}
3181
Riku Voipio41ecc722014-04-23 11:01:00 +03003182static void setup_sigcontext(struct target_sigcontext *sc,
Andreas Färber05390242012-02-25 03:37:53 +01003183 CPUSH4State *regs, unsigned long mask)
thsc3b5bc82007-12-02 06:31:25 +00003184{
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003185 int i;
thsc3b5bc82007-12-02 06:31:25 +00003186
Riku Voipio1d8b5122014-04-23 10:26:05 +03003187#define COPY(x) __put_user(regs->x, &sc->sc_##x)
thsc3b5bc82007-12-02 06:31:25 +00003188 COPY(gregs[0]); COPY(gregs[1]);
3189 COPY(gregs[2]); COPY(gregs[3]);
3190 COPY(gregs[4]); COPY(gregs[5]);
3191 COPY(gregs[6]); COPY(gregs[7]);
3192 COPY(gregs[8]); COPY(gregs[9]);
3193 COPY(gregs[10]); COPY(gregs[11]);
3194 COPY(gregs[12]); COPY(gregs[13]);
3195 COPY(gregs[14]); COPY(gregs[15]);
3196 COPY(gbr); COPY(mach);
3197 COPY(macl); COPY(pr);
3198 COPY(sr); COPY(pc);
3199#undef COPY
3200
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003201 for (i=0; i<16; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03003202 __put_user(regs->fregs[i], &sc->sc_fpregs[i]);
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003203 }
Riku Voipio1d8b5122014-04-23 10:26:05 +03003204 __put_user(regs->fpscr, &sc->sc_fpscr);
3205 __put_user(regs->fpul, &sc->sc_fpul);
thsc3b5bc82007-12-02 06:31:25 +00003206
3207 /* non-iBCS2 extensions.. */
Riku Voipio1d8b5122014-04-23 10:26:05 +03003208 __put_user(mask, &sc->oldmask);
thsc3b5bc82007-12-02 06:31:25 +00003209}
3210
Riku Voipio016d2e12014-04-23 11:19:48 +03003211static void restore_sigcontext(CPUSH4State *regs, struct target_sigcontext *sc,
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003212 target_ulong *r0_p)
thsc3b5bc82007-12-02 06:31:25 +00003213{
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003214 int i;
thsc3b5bc82007-12-02 06:31:25 +00003215
Riku Voipio1d8b5122014-04-23 10:26:05 +03003216#define COPY(x) __get_user(regs->x, &sc->sc_##x)
thsc3b5bc82007-12-02 06:31:25 +00003217 COPY(gregs[1]);
3218 COPY(gregs[2]); COPY(gregs[3]);
3219 COPY(gregs[4]); COPY(gregs[5]);
3220 COPY(gregs[6]); COPY(gregs[7]);
3221 COPY(gregs[8]); COPY(gregs[9]);
3222 COPY(gregs[10]); COPY(gregs[11]);
3223 COPY(gregs[12]); COPY(gregs[13]);
3224 COPY(gregs[14]); COPY(gregs[15]);
3225 COPY(gbr); COPY(mach);
3226 COPY(macl); COPY(pr);
3227 COPY(sr); COPY(pc);
3228#undef COPY
3229
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003230 for (i=0; i<16; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03003231 __get_user(regs->fregs[i], &sc->sc_fpregs[i]);
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003232 }
Riku Voipio1d8b5122014-04-23 10:26:05 +03003233 __get_user(regs->fpscr, &sc->sc_fpscr);
3234 __get_user(regs->fpul, &sc->sc_fpul);
thsc3b5bc82007-12-02 06:31:25 +00003235
3236 regs->tra = -1; /* disable syscall checks */
Riku Voipio1d8b5122014-04-23 10:26:05 +03003237 __get_user(*r0_p, &sc->sc_gregs[0]);
thsc3b5bc82007-12-02 06:31:25 +00003238}
3239
pbrook624f7972008-05-31 16:11:38 +00003240static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01003241 target_sigset_t *set, CPUSH4State *regs)
thsc3b5bc82007-12-02 06:31:25 +00003242{
3243 struct target_sigframe *frame;
3244 abi_ulong frame_addr;
3245 int i;
3246 int err = 0;
3247 int signal;
3248
3249 frame_addr = get_sigframe(ka, regs->gregs[15], sizeof(*frame));
3250 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
3251 goto give_sigsegv;
3252
3253 signal = current_exec_domain_sig(sig);
3254
Riku Voipio41ecc722014-04-23 11:01:00 +03003255 setup_sigcontext(&frame->sc, regs, set->sig[0]);
thsc3b5bc82007-12-02 06:31:25 +00003256
3257 for (i = 0; i < TARGET_NSIG_WORDS - 1; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03003258 __put_user(set->sig[i + 1], &frame->extramask[i]);
thsc3b5bc82007-12-02 06:31:25 +00003259 }
3260
3261 /* Set up to return from userspace. If provided, use a stub
3262 already in userspace. */
pbrook624f7972008-05-31 16:11:38 +00003263 if (ka->sa_flags & TARGET_SA_RESTORER) {
3264 regs->pr = (unsigned long) ka->sa_restorer;
thsc3b5bc82007-12-02 06:31:25 +00003265 } else {
3266 /* Generate return code (system call to sigreturn) */
Riku Voipio1d8b5122014-04-23 10:26:05 +03003267 __put_user(MOVW(2), &frame->retcode[0]);
3268 __put_user(TRAP_NOARG, &frame->retcode[1]);
3269 __put_user((TARGET_NR_sigreturn), &frame->retcode[2]);
thsc3b5bc82007-12-02 06:31:25 +00003270 regs->pr = (unsigned long) frame->retcode;
3271 }
3272
3273 if (err)
3274 goto give_sigsegv;
3275
3276 /* Set up registers for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003277 regs->gregs[15] = frame_addr;
thsc3b5bc82007-12-02 06:31:25 +00003278 regs->gregs[4] = signal; /* Arg for signal handler */
3279 regs->gregs[5] = 0;
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003280 regs->gregs[6] = frame_addr += offsetof(typeof(*frame), sc);
pbrook624f7972008-05-31 16:11:38 +00003281 regs->pc = (unsigned long) ka->_sa_handler;
thsc3b5bc82007-12-02 06:31:25 +00003282
3283 unlock_user_struct(frame, frame_addr, 1);
3284 return;
3285
3286give_sigsegv:
3287 unlock_user_struct(frame, frame_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02003288 force_sig(TARGET_SIGSEGV);
thsc3b5bc82007-12-02 06:31:25 +00003289}
3290
pbrook624f7972008-05-31 16:11:38 +00003291static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05003292 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01003293 target_sigset_t *set, CPUSH4State *regs)
thsc3b5bc82007-12-02 06:31:25 +00003294{
3295 struct target_rt_sigframe *frame;
3296 abi_ulong frame_addr;
3297 int i;
3298 int err = 0;
3299 int signal;
3300
3301 frame_addr = get_sigframe(ka, regs->gregs[15], sizeof(*frame));
3302 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
3303 goto give_sigsegv;
3304
3305 signal = current_exec_domain_sig(sig);
3306
Riku Voipiob0fd8d12014-04-23 10:46:13 +03003307 copy_siginfo_to_user(&frame->info, info);
thsc3b5bc82007-12-02 06:31:25 +00003308
3309 /* Create the ucontext. */
Riku Voipio1d8b5122014-04-23 10:26:05 +03003310 __put_user(0, &frame->uc.tuc_flags);
3311 __put_user(0, (unsigned long *)&frame->uc.tuc_link);
3312 __put_user((unsigned long)target_sigaltstack_used.ss_sp,
3313 &frame->uc.tuc_stack.ss_sp);
3314 __put_user(sas_ss_flags(regs->gregs[15]),
3315 &frame->uc.tuc_stack.ss_flags);
3316 __put_user(target_sigaltstack_used.ss_size,
3317 &frame->uc.tuc_stack.ss_size);
3318 setup_sigcontext(&frame->uc.tuc_mcontext,
thsc3b5bc82007-12-02 06:31:25 +00003319 regs, set->sig[0]);
3320 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03003321 __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
thsc3b5bc82007-12-02 06:31:25 +00003322 }
3323
3324 /* Set up to return from userspace. If provided, use a stub
3325 already in userspace. */
pbrook624f7972008-05-31 16:11:38 +00003326 if (ka->sa_flags & TARGET_SA_RESTORER) {
3327 regs->pr = (unsigned long) ka->sa_restorer;
thsc3b5bc82007-12-02 06:31:25 +00003328 } else {
3329 /* Generate return code (system call to sigreturn) */
Riku Voipio1d8b5122014-04-23 10:26:05 +03003330 __put_user(MOVW(2), &frame->retcode[0]);
3331 __put_user(TRAP_NOARG, &frame->retcode[1]);
3332 __put_user((TARGET_NR_rt_sigreturn), &frame->retcode[2]);
thsc3b5bc82007-12-02 06:31:25 +00003333 regs->pr = (unsigned long) frame->retcode;
3334 }
3335
3336 if (err)
3337 goto give_sigsegv;
3338
3339 /* Set up registers for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003340 regs->gregs[15] = frame_addr;
thsc3b5bc82007-12-02 06:31:25 +00003341 regs->gregs[4] = signal; /* Arg for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003342 regs->gregs[5] = frame_addr + offsetof(typeof(*frame), info);
3343 regs->gregs[6] = frame_addr + offsetof(typeof(*frame), uc);
pbrook624f7972008-05-31 16:11:38 +00003344 regs->pc = (unsigned long) ka->_sa_handler;
thsc3b5bc82007-12-02 06:31:25 +00003345
3346 unlock_user_struct(frame, frame_addr, 1);
3347 return;
3348
3349give_sigsegv:
3350 unlock_user_struct(frame, frame_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02003351 force_sig(TARGET_SIGSEGV);
thsc3b5bc82007-12-02 06:31:25 +00003352}
3353
Andreas Färber05390242012-02-25 03:37:53 +01003354long do_sigreturn(CPUSH4State *regs)
thsc3b5bc82007-12-02 06:31:25 +00003355{
3356 struct target_sigframe *frame;
3357 abi_ulong frame_addr;
3358 sigset_t blocked;
Anthony Liguoric227f092009-10-01 16:12:16 -05003359 target_sigset_t target_set;
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003360 target_ulong r0;
thsc3b5bc82007-12-02 06:31:25 +00003361 int i;
3362 int err = 0;
3363
3364#if defined(DEBUG_SIGNAL)
3365 fprintf(stderr, "do_sigreturn\n");
3366#endif
3367 frame_addr = regs->gregs[15];
3368 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
3369 goto badframe;
3370
Riku Voipio1d8b5122014-04-23 10:26:05 +03003371 __get_user(target_set.sig[0], &frame->sc.oldmask);
thsc3b5bc82007-12-02 06:31:25 +00003372 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03003373 __get_user(target_set.sig[i], &frame->extramask[i - 1]);
thsc3b5bc82007-12-02 06:31:25 +00003374 }
3375
3376 if (err)
3377 goto badframe;
3378
3379 target_to_host_sigset_internal(&blocked, &target_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00003380 do_sigprocmask(SIG_SETMASK, &blocked, NULL);
thsc3b5bc82007-12-02 06:31:25 +00003381
Riku Voipio016d2e12014-04-23 11:19:48 +03003382 restore_sigcontext(regs, &frame->sc, &r0);
thsc3b5bc82007-12-02 06:31:25 +00003383
3384 unlock_user_struct(frame, frame_addr, 0);
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003385 return r0;
thsc3b5bc82007-12-02 06:31:25 +00003386
3387badframe:
3388 unlock_user_struct(frame, frame_addr, 0);
3389 force_sig(TARGET_SIGSEGV);
3390 return 0;
3391}
3392
Andreas Färber05390242012-02-25 03:37:53 +01003393long do_rt_sigreturn(CPUSH4State *regs)
thsc3b5bc82007-12-02 06:31:25 +00003394{
3395 struct target_rt_sigframe *frame;
3396 abi_ulong frame_addr;
3397 sigset_t blocked;
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003398 target_ulong r0;
thsc3b5bc82007-12-02 06:31:25 +00003399
3400#if defined(DEBUG_SIGNAL)
3401 fprintf(stderr, "do_rt_sigreturn\n");
3402#endif
3403 frame_addr = regs->gregs[15];
3404 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
3405 goto badframe;
3406
Aurelien Jarno60e99242010-03-29 02:12:51 +02003407 target_to_host_sigset(&blocked, &frame->uc.tuc_sigmask);
Alex Barcelo1c275922014-03-14 14:36:55 +00003408 do_sigprocmask(SIG_SETMASK, &blocked, NULL);
thsc3b5bc82007-12-02 06:31:25 +00003409
Riku Voipio016d2e12014-04-23 11:19:48 +03003410 restore_sigcontext(regs, &frame->uc.tuc_mcontext, &r0);
thsc3b5bc82007-12-02 06:31:25 +00003411
3412 if (do_sigaltstack(frame_addr +
Aurelien Jarno60e99242010-03-29 02:12:51 +02003413 offsetof(struct target_rt_sigframe, uc.tuc_stack),
thsc3b5bc82007-12-02 06:31:25 +00003414 0, get_sp_from_cpustate(regs)) == -EFAULT)
3415 goto badframe;
3416
3417 unlock_user_struct(frame, frame_addr, 0);
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003418 return r0;
thsc3b5bc82007-12-02 06:31:25 +00003419
3420badframe:
3421 unlock_user_struct(frame, frame_addr, 0);
3422 force_sig(TARGET_SIGSEGV);
3423 return 0;
3424}
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003425#elif defined(TARGET_MICROBLAZE)
3426
3427struct target_sigcontext {
3428 struct target_pt_regs regs; /* needs to be first */
3429 uint32_t oldmask;
3430};
3431
Edgar E. Iglesiasb2178702010-07-23 09:30:37 +02003432struct target_stack_t {
3433 abi_ulong ss_sp;
3434 int ss_flags;
3435 unsigned int ss_size;
3436};
3437
3438struct target_ucontext {
Richard Hendersonf711df62010-11-22 14:57:52 -08003439 abi_ulong tuc_flags;
3440 abi_ulong tuc_link;
3441 struct target_stack_t tuc_stack;
3442 struct target_sigcontext tuc_mcontext;
3443 uint32_t tuc_extramask[TARGET_NSIG_WORDS - 1];
Edgar E. Iglesiasb2178702010-07-23 09:30:37 +02003444};
3445
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003446/* Signal frames. */
3447struct target_signal_frame {
Edgar E. Iglesiasb2178702010-07-23 09:30:37 +02003448 struct target_ucontext uc;
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003449 uint32_t extramask[TARGET_NSIG_WORDS - 1];
3450 uint32_t tramp[2];
3451};
3452
3453struct rt_signal_frame {
Richard W.M. Jones02d2bd52012-07-05 03:32:44 +00003454 siginfo_t info;
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003455 struct ucontext uc;
3456 uint32_t tramp[2];
3457};
3458
Andreas Färber05390242012-02-25 03:37:53 +01003459static void setup_sigcontext(struct target_sigcontext *sc, CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003460{
3461 __put_user(env->regs[0], &sc->regs.r0);
3462 __put_user(env->regs[1], &sc->regs.r1);
3463 __put_user(env->regs[2], &sc->regs.r2);
3464 __put_user(env->regs[3], &sc->regs.r3);
3465 __put_user(env->regs[4], &sc->regs.r4);
3466 __put_user(env->regs[5], &sc->regs.r5);
3467 __put_user(env->regs[6], &sc->regs.r6);
3468 __put_user(env->regs[7], &sc->regs.r7);
3469 __put_user(env->regs[8], &sc->regs.r8);
3470 __put_user(env->regs[9], &sc->regs.r9);
3471 __put_user(env->regs[10], &sc->regs.r10);
3472 __put_user(env->regs[11], &sc->regs.r11);
3473 __put_user(env->regs[12], &sc->regs.r12);
3474 __put_user(env->regs[13], &sc->regs.r13);
3475 __put_user(env->regs[14], &sc->regs.r14);
3476 __put_user(env->regs[15], &sc->regs.r15);
3477 __put_user(env->regs[16], &sc->regs.r16);
3478 __put_user(env->regs[17], &sc->regs.r17);
3479 __put_user(env->regs[18], &sc->regs.r18);
3480 __put_user(env->regs[19], &sc->regs.r19);
3481 __put_user(env->regs[20], &sc->regs.r20);
3482 __put_user(env->regs[21], &sc->regs.r21);
3483 __put_user(env->regs[22], &sc->regs.r22);
3484 __put_user(env->regs[23], &sc->regs.r23);
3485 __put_user(env->regs[24], &sc->regs.r24);
3486 __put_user(env->regs[25], &sc->regs.r25);
3487 __put_user(env->regs[26], &sc->regs.r26);
3488 __put_user(env->regs[27], &sc->regs.r27);
3489 __put_user(env->regs[28], &sc->regs.r28);
3490 __put_user(env->regs[29], &sc->regs.r29);
3491 __put_user(env->regs[30], &sc->regs.r30);
3492 __put_user(env->regs[31], &sc->regs.r31);
3493 __put_user(env->sregs[SR_PC], &sc->regs.pc);
3494}
3495
Andreas Färber05390242012-02-25 03:37:53 +01003496static void restore_sigcontext(struct target_sigcontext *sc, CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003497{
3498 __get_user(env->regs[0], &sc->regs.r0);
3499 __get_user(env->regs[1], &sc->regs.r1);
3500 __get_user(env->regs[2], &sc->regs.r2);
3501 __get_user(env->regs[3], &sc->regs.r3);
3502 __get_user(env->regs[4], &sc->regs.r4);
3503 __get_user(env->regs[5], &sc->regs.r5);
3504 __get_user(env->regs[6], &sc->regs.r6);
3505 __get_user(env->regs[7], &sc->regs.r7);
3506 __get_user(env->regs[8], &sc->regs.r8);
3507 __get_user(env->regs[9], &sc->regs.r9);
3508 __get_user(env->regs[10], &sc->regs.r10);
3509 __get_user(env->regs[11], &sc->regs.r11);
3510 __get_user(env->regs[12], &sc->regs.r12);
3511 __get_user(env->regs[13], &sc->regs.r13);
3512 __get_user(env->regs[14], &sc->regs.r14);
3513 __get_user(env->regs[15], &sc->regs.r15);
3514 __get_user(env->regs[16], &sc->regs.r16);
3515 __get_user(env->regs[17], &sc->regs.r17);
3516 __get_user(env->regs[18], &sc->regs.r18);
3517 __get_user(env->regs[19], &sc->regs.r19);
3518 __get_user(env->regs[20], &sc->regs.r20);
3519 __get_user(env->regs[21], &sc->regs.r21);
3520 __get_user(env->regs[22], &sc->regs.r22);
3521 __get_user(env->regs[23], &sc->regs.r23);
3522 __get_user(env->regs[24], &sc->regs.r24);
3523 __get_user(env->regs[25], &sc->regs.r25);
3524 __get_user(env->regs[26], &sc->regs.r26);
3525 __get_user(env->regs[27], &sc->regs.r27);
3526 __get_user(env->regs[28], &sc->regs.r28);
3527 __get_user(env->regs[29], &sc->regs.r29);
3528 __get_user(env->regs[30], &sc->regs.r30);
3529 __get_user(env->regs[31], &sc->regs.r31);
3530 __get_user(env->sregs[SR_PC], &sc->regs.pc);
3531}
3532
3533static abi_ulong get_sigframe(struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01003534 CPUMBState *env, int frame_size)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003535{
3536 abi_ulong sp = env->regs[1];
3537
3538 if ((ka->sa_flags & SA_ONSTACK) != 0 && !on_sig_stack(sp))
3539 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
3540
3541 return ((sp - frame_size) & -8UL);
3542}
3543
3544static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01003545 target_sigset_t *set, CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003546{
3547 struct target_signal_frame *frame;
3548 abi_ulong frame_addr;
3549 int err = 0;
3550 int i;
3551
3552 frame_addr = get_sigframe(ka, env, sizeof *frame);
3553 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
3554 goto badframe;
3555
3556 /* Save the mask. */
Riku Voipio1d8b5122014-04-23 10:26:05 +03003557 __put_user(set->sig[0], &frame->uc.tuc_mcontext.oldmask);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003558 if (err)
3559 goto badframe;
3560
3561 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
3562 if (__put_user(set->sig[i], &frame->extramask[i - 1]))
3563 goto badframe;
3564 }
3565
Richard Hendersonf711df62010-11-22 14:57:52 -08003566 setup_sigcontext(&frame->uc.tuc_mcontext, env);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003567
3568 /* Set up to return from userspace. If provided, use a stub
3569 already in userspace. */
3570 /* minus 8 is offset to cater for "rtsd r15,8" offset */
3571 if (ka->sa_flags & TARGET_SA_RESTORER) {
3572 env->regs[15] = ((unsigned long)ka->sa_restorer)-8;
3573 } else {
3574 uint32_t t;
3575 /* Note, these encodings are _big endian_! */
3576 /* addi r12, r0, __NR_sigreturn */
3577 t = 0x31800000UL | TARGET_NR_sigreturn;
Riku Voipio1d8b5122014-04-23 10:26:05 +03003578 __put_user(t, frame->tramp + 0);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003579 /* brki r14, 0x8 */
3580 t = 0xb9cc0008UL;
Riku Voipio1d8b5122014-04-23 10:26:05 +03003581 __put_user(t, frame->tramp + 1);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003582
3583 /* Return from sighandler will jump to the tramp.
3584 Negative 8 offset because return is rtsd r15, 8 */
3585 env->regs[15] = ((unsigned long)frame->tramp) - 8;
3586 }
3587
3588 if (err)
3589 goto badframe;
3590
3591 /* Set up registers for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003592 env->regs[1] = frame_addr;
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003593 /* Signal handler args: */
3594 env->regs[5] = sig; /* Arg 0: signum */
Edgar E. Iglesias187b4e02010-07-15 15:32:51 +02003595 env->regs[6] = 0;
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003596 /* arg 1: sigcontext */
3597 env->regs[7] = frame_addr += offsetof(typeof(*frame), uc);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003598
3599 /* Offset of 4 to handle microblaze rtid r14, 0 */
3600 env->sregs[SR_PC] = (unsigned long)ka->_sa_handler;
3601
3602 unlock_user_struct(frame, frame_addr, 1);
3603 return;
3604 badframe:
3605 unlock_user_struct(frame, frame_addr, 1);
3606 force_sig(TARGET_SIGSEGV);
3607}
3608
3609static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05003610 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01003611 target_sigset_t *set, CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003612{
3613 fprintf(stderr, "Microblaze setup_rt_frame: not implemented\n");
3614}
3615
Andreas Färber05390242012-02-25 03:37:53 +01003616long do_sigreturn(CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003617{
3618 struct target_signal_frame *frame;
3619 abi_ulong frame_addr;
Anthony Liguoric227f092009-10-01 16:12:16 -05003620 target_sigset_t target_set;
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003621 sigset_t set;
3622 int i;
3623
3624 frame_addr = env->regs[R_SP];
3625 /* Make sure the guest isn't playing games. */
3626 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 1))
3627 goto badframe;
3628
3629 /* Restore blocked signals */
Richard Hendersonf711df62010-11-22 14:57:52 -08003630 if (__get_user(target_set.sig[0], &frame->uc.tuc_mcontext.oldmask))
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003631 goto badframe;
3632 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
3633 if (__get_user(target_set.sig[i], &frame->extramask[i - 1]))
3634 goto badframe;
3635 }
3636 target_to_host_sigset_internal(&set, &target_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00003637 do_sigprocmask(SIG_SETMASK, &set, NULL);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003638
Richard Hendersonf711df62010-11-22 14:57:52 -08003639 restore_sigcontext(&frame->uc.tuc_mcontext, env);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003640 /* We got here through a sigreturn syscall, our path back is via an
3641 rtb insn so setup r14 for that. */
3642 env->regs[14] = env->sregs[SR_PC];
3643
3644 unlock_user_struct(frame, frame_addr, 0);
3645 return env->regs[10];
3646 badframe:
3647 unlock_user_struct(frame, frame_addr, 0);
3648 force_sig(TARGET_SIGSEGV);
3649}
3650
Andreas Färber05390242012-02-25 03:37:53 +01003651long do_rt_sigreturn(CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003652{
3653 fprintf(stderr, "Microblaze do_rt_sigreturn: not implemented\n");
3654 return -TARGET_ENOSYS;
3655}
3656
edgar_iglb6d3abd2008-02-28 11:29:27 +00003657#elif defined(TARGET_CRIS)
3658
3659struct target_sigcontext {
3660 struct target_pt_regs regs; /* needs to be first */
3661 uint32_t oldmask;
3662 uint32_t usp; /* usp before stacking this gunk on it */
3663};
3664
3665/* Signal frames. */
3666struct target_signal_frame {
3667 struct target_sigcontext sc;
3668 uint32_t extramask[TARGET_NSIG_WORDS - 1];
Stefan Weil8cfc1142014-02-01 09:41:09 +01003669 uint16_t retcode[4]; /* Trampoline code. */
edgar_iglb6d3abd2008-02-28 11:29:27 +00003670};
3671
3672struct rt_signal_frame {
Richard W.M. Jones02d2bd52012-07-05 03:32:44 +00003673 siginfo_t *pinfo;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003674 void *puc;
Richard W.M. Jones02d2bd52012-07-05 03:32:44 +00003675 siginfo_t info;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003676 struct ucontext uc;
Stefan Weil8cfc1142014-02-01 09:41:09 +01003677 uint16_t retcode[4]; /* Trampoline code. */
edgar_iglb6d3abd2008-02-28 11:29:27 +00003678};
3679
Andreas Färber05390242012-02-25 03:37:53 +01003680static void setup_sigcontext(struct target_sigcontext *sc, CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003681{
edgar_igl9664d922008-03-03 22:23:53 +00003682 __put_user(env->regs[0], &sc->regs.r0);
3683 __put_user(env->regs[1], &sc->regs.r1);
3684 __put_user(env->regs[2], &sc->regs.r2);
3685 __put_user(env->regs[3], &sc->regs.r3);
3686 __put_user(env->regs[4], &sc->regs.r4);
3687 __put_user(env->regs[5], &sc->regs.r5);
3688 __put_user(env->regs[6], &sc->regs.r6);
3689 __put_user(env->regs[7], &sc->regs.r7);
3690 __put_user(env->regs[8], &sc->regs.r8);
3691 __put_user(env->regs[9], &sc->regs.r9);
3692 __put_user(env->regs[10], &sc->regs.r10);
3693 __put_user(env->regs[11], &sc->regs.r11);
3694 __put_user(env->regs[12], &sc->regs.r12);
3695 __put_user(env->regs[13], &sc->regs.r13);
3696 __put_user(env->regs[14], &sc->usp);
3697 __put_user(env->regs[15], &sc->regs.acr);
3698 __put_user(env->pregs[PR_MOF], &sc->regs.mof);
3699 __put_user(env->pregs[PR_SRP], &sc->regs.srp);
3700 __put_user(env->pc, &sc->regs.erp);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003701}
edgar_igl9664d922008-03-03 22:23:53 +00003702
Andreas Färber05390242012-02-25 03:37:53 +01003703static void restore_sigcontext(struct target_sigcontext *sc, CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003704{
edgar_igl9664d922008-03-03 22:23:53 +00003705 __get_user(env->regs[0], &sc->regs.r0);
3706 __get_user(env->regs[1], &sc->regs.r1);
3707 __get_user(env->regs[2], &sc->regs.r2);
3708 __get_user(env->regs[3], &sc->regs.r3);
3709 __get_user(env->regs[4], &sc->regs.r4);
3710 __get_user(env->regs[5], &sc->regs.r5);
3711 __get_user(env->regs[6], &sc->regs.r6);
3712 __get_user(env->regs[7], &sc->regs.r7);
3713 __get_user(env->regs[8], &sc->regs.r8);
3714 __get_user(env->regs[9], &sc->regs.r9);
3715 __get_user(env->regs[10], &sc->regs.r10);
3716 __get_user(env->regs[11], &sc->regs.r11);
3717 __get_user(env->regs[12], &sc->regs.r12);
3718 __get_user(env->regs[13], &sc->regs.r13);
3719 __get_user(env->regs[14], &sc->usp);
3720 __get_user(env->regs[15], &sc->regs.acr);
3721 __get_user(env->pregs[PR_MOF], &sc->regs.mof);
3722 __get_user(env->pregs[PR_SRP], &sc->regs.srp);
3723 __get_user(env->pc, &sc->regs.erp);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003724}
3725
Andreas Färber05390242012-02-25 03:37:53 +01003726static abi_ulong get_sigframe(CPUCRISState *env, int framesize)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003727{
edgar_igl9664d922008-03-03 22:23:53 +00003728 abi_ulong sp;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003729 /* Align the stack downwards to 4. */
edgar_igl9664d922008-03-03 22:23:53 +00003730 sp = (env->regs[R_SP] & ~3);
3731 return sp - framesize;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003732}
3733
pbrook624f7972008-05-31 16:11:38 +00003734static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01003735 target_sigset_t *set, CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003736{
3737 struct target_signal_frame *frame;
edgar_igl9664d922008-03-03 22:23:53 +00003738 abi_ulong frame_addr;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003739 int err = 0;
3740 int i;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003741
edgar_igl9664d922008-03-03 22:23:53 +00003742 frame_addr = get_sigframe(env, sizeof *frame);
3743 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
edgar_iglb6d3abd2008-02-28 11:29:27 +00003744 goto badframe;
3745
3746 /*
3747 * The CRIS signal return trampoline. A real linux/CRIS kernel doesn't
3748 * use this trampoline anymore but it sets it up for GDB.
3749 * In QEMU, using the trampoline simplifies things a bit so we use it.
3750 *
3751 * This is movu.w __NR_sigreturn, r9; break 13;
3752 */
Riku Voipio1d8b5122014-04-23 10:26:05 +03003753 __put_user(0x9c5f, frame->retcode+0);
3754 __put_user(TARGET_NR_sigreturn,
3755 frame->retcode + 1);
3756 __put_user(0xe93d, frame->retcode + 2);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003757
3758 /* Save the mask. */
Riku Voipio1d8b5122014-04-23 10:26:05 +03003759 __put_user(set->sig[0], &frame->sc.oldmask);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003760 if (err)
3761 goto badframe;
3762
3763 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
3764 if (__put_user(set->sig[i], &frame->extramask[i - 1]))
3765 goto badframe;
3766 }
3767
3768 setup_sigcontext(&frame->sc, env);
3769
3770 /* Move the stack and setup the arguments for the handler. */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003771 env->regs[R_SP] = frame_addr;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003772 env->regs[10] = sig;
pbrook624f7972008-05-31 16:11:38 +00003773 env->pc = (unsigned long) ka->_sa_handler;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003774 /* Link SRP so the guest returns through the trampoline. */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003775 env->pregs[PR_SRP] = frame_addr + offsetof(typeof(*frame), retcode);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003776
edgar_igl9664d922008-03-03 22:23:53 +00003777 unlock_user_struct(frame, frame_addr, 1);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003778 return;
3779 badframe:
edgar_igl9664d922008-03-03 22:23:53 +00003780 unlock_user_struct(frame, frame_addr, 1);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003781 force_sig(TARGET_SIGSEGV);
3782}
3783
pbrook624f7972008-05-31 16:11:38 +00003784static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05003785 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01003786 target_sigset_t *set, CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003787{
3788 fprintf(stderr, "CRIS setup_rt_frame: not implemented\n");
3789}
3790
Andreas Färber05390242012-02-25 03:37:53 +01003791long do_sigreturn(CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003792{
3793 struct target_signal_frame *frame;
edgar_igl9664d922008-03-03 22:23:53 +00003794 abi_ulong frame_addr;
Anthony Liguoric227f092009-10-01 16:12:16 -05003795 target_sigset_t target_set;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003796 sigset_t set;
3797 int i;
3798
edgar_igl9664d922008-03-03 22:23:53 +00003799 frame_addr = env->regs[R_SP];
edgar_iglb6d3abd2008-02-28 11:29:27 +00003800 /* Make sure the guest isn't playing games. */
edgar_igl9664d922008-03-03 22:23:53 +00003801 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 1))
edgar_iglb6d3abd2008-02-28 11:29:27 +00003802 goto badframe;
3803
3804 /* Restore blocked signals */
3805 if (__get_user(target_set.sig[0], &frame->sc.oldmask))
3806 goto badframe;
3807 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
3808 if (__get_user(target_set.sig[i], &frame->extramask[i - 1]))
3809 goto badframe;
3810 }
3811 target_to_host_sigset_internal(&set, &target_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00003812 do_sigprocmask(SIG_SETMASK, &set, NULL);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003813
3814 restore_sigcontext(&frame->sc, env);
edgar_igl9664d922008-03-03 22:23:53 +00003815 unlock_user_struct(frame, frame_addr, 0);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003816 return env->regs[10];
3817 badframe:
edgar_igl9664d922008-03-03 22:23:53 +00003818 unlock_user_struct(frame, frame_addr, 0);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003819 force_sig(TARGET_SIGSEGV);
3820}
3821
Andreas Färber05390242012-02-25 03:37:53 +01003822long do_rt_sigreturn(CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003823{
3824 fprintf(stderr, "CRIS do_rt_sigreturn: not implemented\n");
3825 return -TARGET_ENOSYS;
3826}
thsc3b5bc82007-12-02 06:31:25 +00003827
Jia Liud9627832012-07-20 15:50:52 +08003828#elif defined(TARGET_OPENRISC)
3829
3830struct target_sigcontext {
3831 struct target_pt_regs regs;
3832 abi_ulong oldmask;
3833 abi_ulong usp;
3834};
3835
3836struct target_ucontext {
3837 abi_ulong tuc_flags;
3838 abi_ulong tuc_link;
3839 target_stack_t tuc_stack;
3840 struct target_sigcontext tuc_mcontext;
3841 target_sigset_t tuc_sigmask; /* mask last for extensibility */
3842};
3843
3844struct target_rt_sigframe {
3845 abi_ulong pinfo;
3846 uint64_t puc;
3847 struct target_siginfo info;
3848 struct target_sigcontext sc;
3849 struct target_ucontext uc;
3850 unsigned char retcode[16]; /* trampoline code */
3851};
3852
3853/* This is the asm-generic/ucontext.h version */
3854#if 0
3855static int restore_sigcontext(CPUOpenRISCState *regs,
3856 struct target_sigcontext *sc)
3857{
3858 unsigned int err = 0;
3859 unsigned long old_usp;
3860
3861 /* Alwys make any pending restarted system call return -EINTR */
3862 current_thread_info()->restart_block.fn = do_no_restart_syscall;
3863
3864 /* restore the regs from &sc->regs (same as sc, since regs is first)
3865 * (sc is already checked for VERIFY_READ since the sigframe was
3866 * checked in sys_sigreturn previously)
3867 */
3868
3869 if (copy_from_user(regs, &sc, sizeof(struct target_pt_regs))) {
3870 goto badframe;
3871 }
3872
3873 /* make sure the U-flag is set so user-mode cannot fool us */
3874
3875 regs->sr &= ~SR_SM;
3876
3877 /* restore the old USP as it was before we stacked the sc etc.
3878 * (we cannot just pop the sigcontext since we aligned the sp and
3879 * stuff after pushing it)
3880 */
3881
Riku Voipio1d8b5122014-04-23 10:26:05 +03003882 __get_user(old_usp, &sc->usp);
Jia Liud9627832012-07-20 15:50:52 +08003883 phx_signal("old_usp 0x%lx", old_usp);
3884
3885 __PHX__ REALLY /* ??? */
3886 wrusp(old_usp);
3887 regs->gpr[1] = old_usp;
3888
3889 /* TODO: the other ports use regs->orig_XX to disable syscall checks
3890 * after this completes, but we don't use that mechanism. maybe we can
3891 * use it now ?
3892 */
3893
3894 return err;
3895
3896badframe:
3897 return 1;
3898}
3899#endif
3900
3901/* Set up a signal frame. */
3902
Riku Voipio41ecc722014-04-23 11:01:00 +03003903static void setup_sigcontext(struct target_sigcontext *sc,
Jia Liud9627832012-07-20 15:50:52 +08003904 CPUOpenRISCState *regs,
3905 unsigned long mask)
3906{
Jia Liud9627832012-07-20 15:50:52 +08003907 unsigned long usp = regs->gpr[1];
3908
3909 /* copy the regs. they are first in sc so we can use sc directly */
3910
Riku Voipio1d8b5122014-04-23 10:26:05 +03003911 /*copy_to_user(&sc, regs, sizeof(struct target_pt_regs));*/
Jia Liud9627832012-07-20 15:50:52 +08003912
3913 /* Set the frametype to CRIS_FRAME_NORMAL for the execution of
3914 the signal handler. The frametype will be restored to its previous
3915 value in restore_sigcontext. */
3916 /*regs->frametype = CRIS_FRAME_NORMAL;*/
3917
3918 /* then some other stuff */
Riku Voipio1d8b5122014-04-23 10:26:05 +03003919 __put_user(mask, &sc->oldmask);
Riku Voipio41ecc722014-04-23 11:01:00 +03003920 __put_user(usp, &sc->usp);
Jia Liud9627832012-07-20 15:50:52 +08003921}
3922
3923static inline unsigned long align_sigframe(unsigned long sp)
3924{
3925 unsigned long i;
3926 i = sp & ~3UL;
3927 return i;
3928}
3929
3930static inline abi_ulong get_sigframe(struct target_sigaction *ka,
3931 CPUOpenRISCState *regs,
3932 size_t frame_size)
3933{
3934 unsigned long sp = regs->gpr[1];
3935 int onsigstack = on_sig_stack(sp);
3936
3937 /* redzone */
3938 /* This is the X/Open sanctioned signal stack switching. */
3939 if ((ka->sa_flags & SA_ONSTACK) != 0 && !onsigstack) {
3940 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
3941 }
3942
3943 sp = align_sigframe(sp - frame_size);
3944
3945 /*
3946 * If we are on the alternate signal stack and would overflow it, don't.
3947 * Return an always-bogus address instead so we will die with SIGSEGV.
3948 */
3949
3950 if (onsigstack && !likely(on_sig_stack(sp))) {
3951 return -1L;
3952 }
3953
3954 return sp;
3955}
3956
3957static void setup_frame(int sig, struct target_sigaction *ka,
3958 target_sigset_t *set, CPUOpenRISCState *env)
3959{
3960 qemu_log("Not implement.\n");
3961}
3962
3963static void setup_rt_frame(int sig, struct target_sigaction *ka,
3964 target_siginfo_t *info,
3965 target_sigset_t *set, CPUOpenRISCState *env)
3966{
3967 int err = 0;
3968 abi_ulong frame_addr;
3969 unsigned long return_ip;
3970 struct target_rt_sigframe *frame;
3971 abi_ulong info_addr, uc_addr;
3972
Jia Liud9627832012-07-20 15:50:52 +08003973 frame_addr = get_sigframe(ka, env, sizeof(*frame));
3974 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
3975 goto give_sigsegv;
3976 }
3977
3978 info_addr = frame_addr + offsetof(struct target_rt_sigframe, info);
Riku Voipio1d8b5122014-04-23 10:26:05 +03003979 __put_user(info_addr, &frame->pinfo);
Jia Liud9627832012-07-20 15:50:52 +08003980 uc_addr = frame_addr + offsetof(struct target_rt_sigframe, uc);
Riku Voipio1d8b5122014-04-23 10:26:05 +03003981 __put_user(uc_addr, &frame->puc);
Jia Liud9627832012-07-20 15:50:52 +08003982
3983 if (ka->sa_flags & SA_SIGINFO) {
Riku Voipiob0fd8d12014-04-23 10:46:13 +03003984 copy_siginfo_to_user(&frame->info, info);
Jia Liud9627832012-07-20 15:50:52 +08003985 }
3986
3987 /*err |= __clear_user(&frame->uc, offsetof(struct ucontext, uc_mcontext));*/
Riku Voipio1d8b5122014-04-23 10:26:05 +03003988 __put_user(0, &frame->uc.tuc_flags);
3989 __put_user(0, &frame->uc.tuc_link);
3990 __put_user(target_sigaltstack_used.ss_sp,
3991 &frame->uc.tuc_stack.ss_sp);
3992 __put_user(sas_ss_flags(env->gpr[1]), &frame->uc.tuc_stack.ss_flags);
3993 __put_user(target_sigaltstack_used.ss_size,
3994 &frame->uc.tuc_stack.ss_size);
Riku Voipio41ecc722014-04-23 11:01:00 +03003995 setup_sigcontext(&frame->sc, env, set->sig[0]);
Jia Liud9627832012-07-20 15:50:52 +08003996
3997 /*err |= copy_to_user(frame->uc.tuc_sigmask, set, sizeof(*set));*/
3998
Jia Liud9627832012-07-20 15:50:52 +08003999 /* trampoline - the desired return ip is the retcode itself */
4000 return_ip = (unsigned long)&frame->retcode;
4001 /* This is l.ori r11,r0,__NR_sigreturn, l.sys 1 */
Riku Voipio1d8b5122014-04-23 10:26:05 +03004002 __put_user(0xa960, (short *)(frame->retcode + 0));
4003 __put_user(TARGET_NR_rt_sigreturn, (short *)(frame->retcode + 2));
4004 __put_user(0x20000001, (unsigned long *)(frame->retcode + 4));
4005 __put_user(0x15000000, (unsigned long *)(frame->retcode + 8));
Jia Liud9627832012-07-20 15:50:52 +08004006
4007 if (err) {
4008 goto give_sigsegv;
4009 }
4010
4011 /* TODO what is the current->exec_domain stuff and invmap ? */
4012
4013 /* Set up registers for signal handler */
4014 env->pc = (unsigned long)ka->_sa_handler; /* what we enter NOW */
4015 env->gpr[9] = (unsigned long)return_ip; /* what we enter LATER */
4016 env->gpr[3] = (unsigned long)sig; /* arg 1: signo */
4017 env->gpr[4] = (unsigned long)&frame->info; /* arg 2: (siginfo_t*) */
4018 env->gpr[5] = (unsigned long)&frame->uc; /* arg 3: ucontext */
4019
4020 /* actually move the usp to reflect the stacked frame */
4021 env->gpr[1] = (unsigned long)frame;
4022
4023 return;
4024
4025give_sigsegv:
4026 unlock_user_struct(frame, frame_addr, 1);
4027 if (sig == TARGET_SIGSEGV) {
4028 ka->_sa_handler = TARGET_SIG_DFL;
4029 }
4030 force_sig(TARGET_SIGSEGV);
4031}
4032
4033long do_sigreturn(CPUOpenRISCState *env)
4034{
4035
4036 qemu_log("do_sigreturn: not implemented\n");
4037 return -TARGET_ENOSYS;
4038}
4039
4040long do_rt_sigreturn(CPUOpenRISCState *env)
4041{
4042 qemu_log("do_rt_sigreturn: not implemented\n");
4043 return -TARGET_ENOSYS;
4044}
4045/* TARGET_OPENRISC */
4046
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004047#elif defined(TARGET_S390X)
4048
4049#define __NUM_GPRS 16
4050#define __NUM_FPRS 16
4051#define __NUM_ACRS 16
4052
4053#define S390_SYSCALL_SIZE 2
4054#define __SIGNAL_FRAMESIZE 160 /* FIXME: 31-bit mode -> 96 */
4055
4056#define _SIGCONTEXT_NSIG 64
4057#define _SIGCONTEXT_NSIG_BPW 64 /* FIXME: 31-bit mode -> 32 */
4058#define _SIGCONTEXT_NSIG_WORDS (_SIGCONTEXT_NSIG / _SIGCONTEXT_NSIG_BPW)
4059#define _SIGMASK_COPY_SIZE (sizeof(unsigned long)*_SIGCONTEXT_NSIG_WORDS)
4060#define PSW_ADDR_AMODE 0x0000000000000000UL /* 0x80000000UL for 31-bit */
4061#define S390_SYSCALL_OPCODE ((uint16_t)0x0a00)
4062
4063typedef struct {
4064 target_psw_t psw;
4065 target_ulong gprs[__NUM_GPRS];
4066 unsigned int acrs[__NUM_ACRS];
4067} target_s390_regs_common;
4068
4069typedef struct {
4070 unsigned int fpc;
4071 double fprs[__NUM_FPRS];
4072} target_s390_fp_regs;
4073
4074typedef struct {
4075 target_s390_regs_common regs;
4076 target_s390_fp_regs fpregs;
4077} target_sigregs;
4078
4079struct target_sigcontext {
4080 target_ulong oldmask[_SIGCONTEXT_NSIG_WORDS];
4081 target_sigregs *sregs;
4082};
4083
4084typedef struct {
4085 uint8_t callee_used_stack[__SIGNAL_FRAMESIZE];
4086 struct target_sigcontext sc;
4087 target_sigregs sregs;
4088 int signo;
4089 uint8_t retcode[S390_SYSCALL_SIZE];
4090} sigframe;
4091
4092struct target_ucontext {
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004093 target_ulong tuc_flags;
4094 struct target_ucontext *tuc_link;
4095 target_stack_t tuc_stack;
4096 target_sigregs tuc_mcontext;
4097 target_sigset_t tuc_sigmask; /* mask last for extensibility */
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004098};
4099
4100typedef struct {
4101 uint8_t callee_used_stack[__SIGNAL_FRAMESIZE];
4102 uint8_t retcode[S390_SYSCALL_SIZE];
4103 struct target_siginfo info;
4104 struct target_ucontext uc;
4105} rt_sigframe;
4106
4107static inline abi_ulong
Andreas Färber05390242012-02-25 03:37:53 +01004108get_sigframe(struct target_sigaction *ka, CPUS390XState *env, size_t frame_size)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004109{
4110 abi_ulong sp;
4111
4112 /* Default to using normal stack */
4113 sp = env->regs[15];
4114
4115 /* This is the X/Open sanctioned signal stack switching. */
4116 if (ka->sa_flags & TARGET_SA_ONSTACK) {
4117 if (!sas_ss_flags(sp)) {
4118 sp = target_sigaltstack_used.ss_sp +
4119 target_sigaltstack_used.ss_size;
4120 }
4121 }
4122
4123 /* This is the legacy signal stack switching. */
4124 else if (/* FIXME !user_mode(regs) */ 0 &&
4125 !(ka->sa_flags & TARGET_SA_RESTORER) &&
4126 ka->sa_restorer) {
4127 sp = (abi_ulong) ka->sa_restorer;
4128 }
4129
4130 return (sp - frame_size) & -8ul;
4131}
4132
Andreas Färber05390242012-02-25 03:37:53 +01004133static void save_sigregs(CPUS390XState *env, target_sigregs *sregs)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004134{
4135 int i;
4136 //save_access_regs(current->thread.acrs); FIXME
4137
4138 /* Copy a 'clean' PSW mask to the user to avoid leaking
4139 information about whether PER is currently on. */
4140 __put_user(env->psw.mask, &sregs->regs.psw.mask);
4141 __put_user(env->psw.addr, &sregs->regs.psw.addr);
4142 for (i = 0; i < 16; i++) {
4143 __put_user(env->regs[i], &sregs->regs.gprs[i]);
4144 }
4145 for (i = 0; i < 16; i++) {
4146 __put_user(env->aregs[i], &sregs->regs.acrs[i]);
4147 }
4148 /*
4149 * We have to store the fp registers to current->thread.fp_regs
4150 * to merge them with the emulated registers.
4151 */
4152 //save_fp_regs(&current->thread.fp_regs); FIXME
4153 for (i = 0; i < 16; i++) {
4154 __put_user(env->fregs[i].ll, &sregs->fpregs.fprs[i]);
4155 }
4156}
4157
4158static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01004159 target_sigset_t *set, CPUS390XState *env)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004160{
4161 sigframe *frame;
4162 abi_ulong frame_addr;
4163
4164 frame_addr = get_sigframe(ka, env, sizeof(*frame));
4165 qemu_log("%s: frame_addr 0x%llx\n", __FUNCTION__,
4166 (unsigned long long)frame_addr);
4167 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
4168 goto give_sigsegv;
4169 }
4170
4171 qemu_log("%s: 1\n", __FUNCTION__);
4172 if (__put_user(set->sig[0], &frame->sc.oldmask[0])) {
4173 goto give_sigsegv;
4174 }
4175
4176 save_sigregs(env, &frame->sregs);
4177
4178 __put_user((abi_ulong)(unsigned long)&frame->sregs,
4179 (abi_ulong *)&frame->sc.sregs);
4180
4181 /* Set up to return from userspace. If provided, use a stub
4182 already in userspace. */
4183 if (ka->sa_flags & TARGET_SA_RESTORER) {
4184 env->regs[14] = (unsigned long)
4185 ka->sa_restorer | PSW_ADDR_AMODE;
4186 } else {
4187 env->regs[14] = (unsigned long)
4188 frame->retcode | PSW_ADDR_AMODE;
4189 if (__put_user(S390_SYSCALL_OPCODE | TARGET_NR_sigreturn,
4190 (uint16_t *)(frame->retcode)))
4191 goto give_sigsegv;
4192 }
4193
4194 /* Set up backchain. */
4195 if (__put_user(env->regs[15], (abi_ulong *) frame)) {
4196 goto give_sigsegv;
4197 }
4198
4199 /* Set up registers for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02004200 env->regs[15] = frame_addr;
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004201 env->psw.addr = (target_ulong) ka->_sa_handler | PSW_ADDR_AMODE;
4202
4203 env->regs[2] = sig; //map_signal(sig);
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02004204 env->regs[3] = frame_addr += offsetof(typeof(*frame), sc);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004205
4206 /* We forgot to include these in the sigcontext.
4207 To avoid breaking binary compatibility, they are passed as args. */
4208 env->regs[4] = 0; // FIXME: no clue... current->thread.trap_no;
4209 env->regs[5] = 0; // FIXME: no clue... current->thread.prot_addr;
4210
4211 /* Place signal number on stack to allow backtrace from handler. */
4212 if (__put_user(env->regs[2], (int *) &frame->signo)) {
4213 goto give_sigsegv;
4214 }
4215 unlock_user_struct(frame, frame_addr, 1);
4216 return;
4217
4218give_sigsegv:
4219 qemu_log("%s: give_sigsegv\n", __FUNCTION__);
4220 unlock_user_struct(frame, frame_addr, 1);
4221 force_sig(TARGET_SIGSEGV);
4222}
4223
4224static void setup_rt_frame(int sig, struct target_sigaction *ka,
4225 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01004226 target_sigset_t *set, CPUS390XState *env)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004227{
4228 int i;
4229 rt_sigframe *frame;
4230 abi_ulong frame_addr;
4231
4232 frame_addr = get_sigframe(ka, env, sizeof *frame);
4233 qemu_log("%s: frame_addr 0x%llx\n", __FUNCTION__,
4234 (unsigned long long)frame_addr);
4235 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
4236 goto give_sigsegv;
4237 }
4238
4239 qemu_log("%s: 1\n", __FUNCTION__);
Riku Voipiob0fd8d12014-04-23 10:46:13 +03004240 copy_siginfo_to_user(&frame->info, info);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004241
4242 /* Create the ucontext. */
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004243 __put_user(0, &frame->uc.tuc_flags);
4244 __put_user((abi_ulong)0, (abi_ulong *)&frame->uc.tuc_link);
4245 __put_user(target_sigaltstack_used.ss_sp, &frame->uc.tuc_stack.ss_sp);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004246 __put_user(sas_ss_flags(get_sp_from_cpustate(env)),
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004247 &frame->uc.tuc_stack.ss_flags);
4248 __put_user(target_sigaltstack_used.ss_size, &frame->uc.tuc_stack.ss_size);
4249 save_sigregs(env, &frame->uc.tuc_mcontext);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004250 for (i = 0; i < TARGET_NSIG_WORDS; i++) {
4251 __put_user((abi_ulong)set->sig[i],
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004252 (abi_ulong *)&frame->uc.tuc_sigmask.sig[i]);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004253 }
4254
4255 /* Set up to return from userspace. If provided, use a stub
4256 already in userspace. */
4257 if (ka->sa_flags & TARGET_SA_RESTORER) {
4258 env->regs[14] = (unsigned long) ka->sa_restorer | PSW_ADDR_AMODE;
4259 } else {
4260 env->regs[14] = (unsigned long) frame->retcode | PSW_ADDR_AMODE;
4261 if (__put_user(S390_SYSCALL_OPCODE | TARGET_NR_rt_sigreturn,
4262 (uint16_t *)(frame->retcode))) {
4263 goto give_sigsegv;
4264 }
4265 }
4266
4267 /* Set up backchain. */
4268 if (__put_user(env->regs[15], (abi_ulong *) frame)) {
4269 goto give_sigsegv;
4270 }
4271
4272 /* Set up registers for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02004273 env->regs[15] = frame_addr;
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004274 env->psw.addr = (target_ulong) ka->_sa_handler | PSW_ADDR_AMODE;
4275
4276 env->regs[2] = sig; //map_signal(sig);
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02004277 env->regs[3] = frame_addr + offsetof(typeof(*frame), info);
4278 env->regs[4] = frame_addr + offsetof(typeof(*frame), uc);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004279 return;
4280
4281give_sigsegv:
4282 qemu_log("%s: give_sigsegv\n", __FUNCTION__);
4283 unlock_user_struct(frame, frame_addr, 1);
4284 force_sig(TARGET_SIGSEGV);
4285}
4286
4287static int
Andreas Färber05390242012-02-25 03:37:53 +01004288restore_sigregs(CPUS390XState *env, target_sigregs *sc)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004289{
4290 int err = 0;
4291 int i;
4292
4293 for (i = 0; i < 16; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03004294 __get_user(env->regs[i], &sc->regs.gprs[i]);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004295 }
4296
Riku Voipio1d8b5122014-04-23 10:26:05 +03004297 __get_user(env->psw.mask, &sc->regs.psw.mask);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004298 qemu_log("%s: sc->regs.psw.addr 0x%llx env->psw.addr 0x%llx\n",
4299 __FUNCTION__, (unsigned long long)sc->regs.psw.addr,
4300 (unsigned long long)env->psw.addr);
Riku Voipio1d8b5122014-04-23 10:26:05 +03004301 __get_user(env->psw.addr, &sc->regs.psw.addr);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004302 /* FIXME: 31-bit -> | PSW_ADDR_AMODE */
4303
4304 for (i = 0; i < 16; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03004305 __get_user(env->aregs[i], &sc->regs.acrs[i]);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004306 }
4307 for (i = 0; i < 16; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03004308 __get_user(env->fregs[i].ll, &sc->fpregs.fprs[i]);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004309 }
4310
4311 return err;
4312}
4313
Andreas Färber05390242012-02-25 03:37:53 +01004314long do_sigreturn(CPUS390XState *env)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004315{
4316 sigframe *frame;
4317 abi_ulong frame_addr = env->regs[15];
4318 qemu_log("%s: frame_addr 0x%llx\n", __FUNCTION__,
4319 (unsigned long long)frame_addr);
4320 target_sigset_t target_set;
4321 sigset_t set;
4322
4323 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
4324 goto badframe;
4325 }
4326 if (__get_user(target_set.sig[0], &frame->sc.oldmask[0])) {
4327 goto badframe;
4328 }
4329
4330 target_to_host_sigset_internal(&set, &target_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00004331 do_sigprocmask(SIG_SETMASK, &set, NULL); /* ~_BLOCKABLE? */
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004332
4333 if (restore_sigregs(env, &frame->sregs)) {
4334 goto badframe;
4335 }
4336
4337 unlock_user_struct(frame, frame_addr, 0);
4338 return env->regs[2];
4339
4340badframe:
4341 unlock_user_struct(frame, frame_addr, 0);
4342 force_sig(TARGET_SIGSEGV);
4343 return 0;
4344}
4345
Andreas Färber05390242012-02-25 03:37:53 +01004346long do_rt_sigreturn(CPUS390XState *env)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004347{
4348 rt_sigframe *frame;
4349 abi_ulong frame_addr = env->regs[15];
4350 qemu_log("%s: frame_addr 0x%llx\n", __FUNCTION__,
4351 (unsigned long long)frame_addr);
4352 sigset_t set;
4353
4354 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
4355 goto badframe;
4356 }
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004357 target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004358
Alex Barcelo1c275922014-03-14 14:36:55 +00004359 do_sigprocmask(SIG_SETMASK, &set, NULL); /* ~_BLOCKABLE? */
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004360
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004361 if (restore_sigregs(env, &frame->uc.tuc_mcontext)) {
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004362 goto badframe;
4363 }
4364
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004365 if (do_sigaltstack(frame_addr + offsetof(rt_sigframe, uc.tuc_stack), 0,
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004366 get_sp_from_cpustate(env)) == -EFAULT) {
4367 goto badframe;
4368 }
4369 unlock_user_struct(frame, frame_addr, 0);
4370 return env->regs[2];
4371
4372badframe:
4373 unlock_user_struct(frame, frame_addr, 0);
4374 force_sig(TARGET_SIGSEGV);
4375 return 0;
4376}
4377
Nathan Froydbcd49332009-05-12 19:13:18 -07004378#elif defined(TARGET_PPC) && !defined(TARGET_PPC64)
4379
4380/* FIXME: Many of the structures are defined for both PPC and PPC64, but
4381 the signal handling is different enough that we haven't implemented
4382 support for PPC64 yet. Hence the restriction above.
4383
4384 There are various #if'd blocks for code for TARGET_PPC64. These
4385 blocks should go away so that we can successfully run 32-bit and
4386 64-bit binaries on a QEMU configured for PPC64. */
4387
4388/* Size of dummy stack frame allocated when calling signal handler.
4389 See arch/powerpc/include/asm/ptrace.h. */
4390#if defined(TARGET_PPC64)
4391#define SIGNAL_FRAMESIZE 128
4392#else
4393#define SIGNAL_FRAMESIZE 64
4394#endif
4395
4396/* See arch/powerpc/include/asm/sigcontext.h. */
4397struct target_sigcontext {
4398 target_ulong _unused[4];
4399 int32_t signal;
4400#if defined(TARGET_PPC64)
4401 int32_t pad0;
4402#endif
4403 target_ulong handler;
4404 target_ulong oldmask;
4405 target_ulong regs; /* struct pt_regs __user * */
4406 /* TODO: PPC64 includes extra bits here. */
4407};
4408
4409/* Indices for target_mcontext.mc_gregs, below.
4410 See arch/powerpc/include/asm/ptrace.h for details. */
4411enum {
4412 TARGET_PT_R0 = 0,
4413 TARGET_PT_R1 = 1,
4414 TARGET_PT_R2 = 2,
4415 TARGET_PT_R3 = 3,
4416 TARGET_PT_R4 = 4,
4417 TARGET_PT_R5 = 5,
4418 TARGET_PT_R6 = 6,
4419 TARGET_PT_R7 = 7,
4420 TARGET_PT_R8 = 8,
4421 TARGET_PT_R9 = 9,
4422 TARGET_PT_R10 = 10,
4423 TARGET_PT_R11 = 11,
4424 TARGET_PT_R12 = 12,
4425 TARGET_PT_R13 = 13,
4426 TARGET_PT_R14 = 14,
4427 TARGET_PT_R15 = 15,
4428 TARGET_PT_R16 = 16,
4429 TARGET_PT_R17 = 17,
4430 TARGET_PT_R18 = 18,
4431 TARGET_PT_R19 = 19,
4432 TARGET_PT_R20 = 20,
4433 TARGET_PT_R21 = 21,
4434 TARGET_PT_R22 = 22,
4435 TARGET_PT_R23 = 23,
4436 TARGET_PT_R24 = 24,
4437 TARGET_PT_R25 = 25,
4438 TARGET_PT_R26 = 26,
4439 TARGET_PT_R27 = 27,
4440 TARGET_PT_R28 = 28,
4441 TARGET_PT_R29 = 29,
4442 TARGET_PT_R30 = 30,
4443 TARGET_PT_R31 = 31,
4444 TARGET_PT_NIP = 32,
4445 TARGET_PT_MSR = 33,
4446 TARGET_PT_ORIG_R3 = 34,
4447 TARGET_PT_CTR = 35,
4448 TARGET_PT_LNK = 36,
4449 TARGET_PT_XER = 37,
4450 TARGET_PT_CCR = 38,
4451 /* Yes, there are two registers with #39. One is 64-bit only. */
4452 TARGET_PT_MQ = 39,
4453 TARGET_PT_SOFTE = 39,
4454 TARGET_PT_TRAP = 40,
4455 TARGET_PT_DAR = 41,
4456 TARGET_PT_DSISR = 42,
4457 TARGET_PT_RESULT = 43,
4458 TARGET_PT_REGS_COUNT = 44
4459};
4460
4461/* See arch/powerpc/include/asm/ucontext.h. Only used for 32-bit PPC;
4462 on 64-bit PPC, sigcontext and mcontext are one and the same. */
4463struct target_mcontext {
4464 target_ulong mc_gregs[48];
4465 /* Includes fpscr. */
4466 uint64_t mc_fregs[33];
4467 target_ulong mc_pad[2];
4468 /* We need to handle Altivec and SPE at the same time, which no
4469 kernel needs to do. Fortunately, the kernel defines this bit to
4470 be Altivec-register-large all the time, rather than trying to
4471 twiddle it based on the specific platform. */
4472 union {
4473 /* SPE vector registers. One extra for SPEFSCR. */
4474 uint32_t spe[33];
4475 /* Altivec vector registers. The packing of VSCR and VRSAVE
4476 varies depending on whether we're PPC64 or not: PPC64 splits
4477 them apart; PPC32 stuffs them together. */
4478#if defined(TARGET_PPC64)
malc3efa9a62009-07-18 13:10:12 +04004479#define QEMU_NVRREG 34
Nathan Froydbcd49332009-05-12 19:13:18 -07004480#else
malc3efa9a62009-07-18 13:10:12 +04004481#define QEMU_NVRREG 33
Nathan Froydbcd49332009-05-12 19:13:18 -07004482#endif
Anthony Liguoric227f092009-10-01 16:12:16 -05004483 ppc_avr_t altivec[QEMU_NVRREG];
malc3efa9a62009-07-18 13:10:12 +04004484#undef QEMU_NVRREG
Nathan Froydbcd49332009-05-12 19:13:18 -07004485 } mc_vregs __attribute__((__aligned__(16)));
4486};
4487
4488struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02004489 target_ulong tuc_flags;
4490 target_ulong tuc_link; /* struct ucontext __user * */
4491 struct target_sigaltstack tuc_stack;
Nathan Froydbcd49332009-05-12 19:13:18 -07004492#if !defined(TARGET_PPC64)
Aurelien Jarno60e99242010-03-29 02:12:51 +02004493 int32_t tuc_pad[7];
4494 target_ulong tuc_regs; /* struct mcontext __user *
Nathan Froydbcd49332009-05-12 19:13:18 -07004495 points to uc_mcontext field */
4496#endif
Aurelien Jarno60e99242010-03-29 02:12:51 +02004497 target_sigset_t tuc_sigmask;
Nathan Froydbcd49332009-05-12 19:13:18 -07004498#if defined(TARGET_PPC64)
Anthony Liguoric227f092009-10-01 16:12:16 -05004499 target_sigset_t unused[15]; /* Allow for uc_sigmask growth */
Aurelien Jarno60e99242010-03-29 02:12:51 +02004500 struct target_sigcontext tuc_mcontext;
Nathan Froydbcd49332009-05-12 19:13:18 -07004501#else
Aurelien Jarno60e99242010-03-29 02:12:51 +02004502 int32_t tuc_maskext[30];
4503 int32_t tuc_pad2[3];
4504 struct target_mcontext tuc_mcontext;
Nathan Froydbcd49332009-05-12 19:13:18 -07004505#endif
4506};
4507
4508/* See arch/powerpc/kernel/signal_32.c. */
4509struct target_sigframe {
4510 struct target_sigcontext sctx;
4511 struct target_mcontext mctx;
4512 int32_t abigap[56];
4513};
4514
4515struct target_rt_sigframe {
4516 struct target_siginfo info;
4517 struct target_ucontext uc;
4518 int32_t abigap[56];
4519};
4520
4521/* We use the mc_pad field for the signal return trampoline. */
4522#define tramp mc_pad
4523
4524/* See arch/powerpc/kernel/signal.c. */
4525static target_ulong get_sigframe(struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01004526 CPUPPCState *env,
Nathan Froydbcd49332009-05-12 19:13:18 -07004527 int frame_size)
4528{
4529 target_ulong oldsp, newsp;
4530
4531 oldsp = env->gpr[1];
4532
4533 if ((ka->sa_flags & TARGET_SA_ONSTACK) &&
Alex Barcelo32a20032012-02-09 23:55:46 +00004534 (sas_ss_flags(oldsp) == 0)) {
Nathan Froydbcd49332009-05-12 19:13:18 -07004535 oldsp = (target_sigaltstack_used.ss_sp
4536 + target_sigaltstack_used.ss_size);
4537 }
4538
4539 newsp = (oldsp - frame_size) & ~0xFUL;
4540
4541 return newsp;
4542}
4543
Andreas Färber05390242012-02-25 03:37:53 +01004544static int save_user_regs(CPUPPCState *env, struct target_mcontext *frame,
Nathan Froydbcd49332009-05-12 19:13:18 -07004545 int sigret)
4546{
4547 target_ulong msr = env->msr;
4548 int i;
4549 target_ulong ccr = 0;
4550
4551 /* In general, the kernel attempts to be intelligent about what it
4552 needs to save for Altivec/FP/SPE registers. We don't care that
4553 much, so we just go ahead and save everything. */
4554
4555 /* Save general registers. */
4556 for (i = 0; i < ARRAY_SIZE(env->gpr); i++) {
4557 if (__put_user(env->gpr[i], &frame->mc_gregs[i])) {
4558 return 1;
4559 }
4560 }
4561 if (__put_user(env->nip, &frame->mc_gregs[TARGET_PT_NIP])
4562 || __put_user(env->ctr, &frame->mc_gregs[TARGET_PT_CTR])
4563 || __put_user(env->lr, &frame->mc_gregs[TARGET_PT_LNK])
4564 || __put_user(env->xer, &frame->mc_gregs[TARGET_PT_XER]))
4565 return 1;
4566
4567 for (i = 0; i < ARRAY_SIZE(env->crf); i++) {
4568 ccr |= env->crf[i] << (32 - ((i + 1) * 4));
4569 }
4570 if (__put_user(ccr, &frame->mc_gregs[TARGET_PT_CCR]))
4571 return 1;
4572
4573 /* Save Altivec registers if necessary. */
4574 if (env->insns_flags & PPC_ALTIVEC) {
4575 for (i = 0; i < ARRAY_SIZE(env->avr); i++) {
Anthony Liguoric227f092009-10-01 16:12:16 -05004576 ppc_avr_t *avr = &env->avr[i];
4577 ppc_avr_t *vreg = &frame->mc_vregs.altivec[i];
Nathan Froydbcd49332009-05-12 19:13:18 -07004578
4579 if (__put_user(avr->u64[0], &vreg->u64[0]) ||
4580 __put_user(avr->u64[1], &vreg->u64[1])) {
4581 return 1;
4582 }
4583 }
4584 /* Set MSR_VR in the saved MSR value to indicate that
4585 frame->mc_vregs contains valid data. */
4586 msr |= MSR_VR;
4587 if (__put_user((uint32_t)env->spr[SPR_VRSAVE],
4588 &frame->mc_vregs.altivec[32].u32[3]))
4589 return 1;
4590 }
4591
4592 /* Save floating point registers. */
4593 if (env->insns_flags & PPC_FLOAT) {
4594 for (i = 0; i < ARRAY_SIZE(env->fpr); i++) {
4595 if (__put_user(env->fpr[i], &frame->mc_fregs[i])) {
4596 return 1;
4597 }
4598 }
4599 if (__put_user((uint64_t) env->fpscr, &frame->mc_fregs[32]))
4600 return 1;
4601 }
4602
4603 /* Save SPE registers. The kernel only saves the high half. */
4604 if (env->insns_flags & PPC_SPE) {
4605#if defined(TARGET_PPC64)
4606 for (i = 0; i < ARRAY_SIZE(env->gpr); i++) {
4607 if (__put_user(env->gpr[i] >> 32, &frame->mc_vregs.spe[i])) {
4608 return 1;
4609 }
4610 }
4611#else
4612 for (i = 0; i < ARRAY_SIZE(env->gprh); i++) {
4613 if (__put_user(env->gprh[i], &frame->mc_vregs.spe[i])) {
4614 return 1;
4615 }
4616 }
4617#endif
4618 /* Set MSR_SPE in the saved MSR value to indicate that
4619 frame->mc_vregs contains valid data. */
4620 msr |= MSR_SPE;
4621 if (__put_user(env->spe_fscr, &frame->mc_vregs.spe[32]))
4622 return 1;
4623 }
4624
4625 /* Store MSR. */
4626 if (__put_user(msr, &frame->mc_gregs[TARGET_PT_MSR]))
4627 return 1;
4628
4629 /* Set up the sigreturn trampoline: li r0,sigret; sc. */
4630 if (sigret) {
4631 if (__put_user(0x38000000UL | sigret, &frame->tramp[0]) ||
4632 __put_user(0x44000002UL, &frame->tramp[1])) {
4633 return 1;
4634 }
4635 }
4636
4637 return 0;
4638}
4639
Andreas Färber05390242012-02-25 03:37:53 +01004640static int restore_user_regs(CPUPPCState *env,
Nathan Froydbcd49332009-05-12 19:13:18 -07004641 struct target_mcontext *frame, int sig)
4642{
4643 target_ulong save_r2 = 0;
4644 target_ulong msr;
4645 target_ulong ccr;
4646
4647 int i;
4648
4649 if (!sig) {
4650 save_r2 = env->gpr[2];
4651 }
4652
4653 /* Restore general registers. */
4654 for (i = 0; i < ARRAY_SIZE(env->gpr); i++) {
4655 if (__get_user(env->gpr[i], &frame->mc_gregs[i])) {
4656 return 1;
4657 }
4658 }
4659 if (__get_user(env->nip, &frame->mc_gregs[TARGET_PT_NIP])
4660 || __get_user(env->ctr, &frame->mc_gregs[TARGET_PT_CTR])
4661 || __get_user(env->lr, &frame->mc_gregs[TARGET_PT_LNK])
4662 || __get_user(env->xer, &frame->mc_gregs[TARGET_PT_XER]))
4663 return 1;
4664 if (__get_user(ccr, &frame->mc_gregs[TARGET_PT_CCR]))
4665 return 1;
4666
4667 for (i = 0; i < ARRAY_SIZE(env->crf); i++) {
4668 env->crf[i] = (ccr >> (32 - ((i + 1) * 4))) & 0xf;
4669 }
4670
4671 if (!sig) {
4672 env->gpr[2] = save_r2;
4673 }
4674 /* Restore MSR. */
4675 if (__get_user(msr, &frame->mc_gregs[TARGET_PT_MSR]))
4676 return 1;
4677
4678 /* If doing signal return, restore the previous little-endian mode. */
4679 if (sig)
4680 env->msr = (env->msr & ~MSR_LE) | (msr & MSR_LE);
4681
4682 /* Restore Altivec registers if necessary. */
4683 if (env->insns_flags & PPC_ALTIVEC) {
4684 for (i = 0; i < ARRAY_SIZE(env->avr); i++) {
Anthony Liguoric227f092009-10-01 16:12:16 -05004685 ppc_avr_t *avr = &env->avr[i];
4686 ppc_avr_t *vreg = &frame->mc_vregs.altivec[i];
Nathan Froydbcd49332009-05-12 19:13:18 -07004687
4688 if (__get_user(avr->u64[0], &vreg->u64[0]) ||
4689 __get_user(avr->u64[1], &vreg->u64[1])) {
4690 return 1;
4691 }
4692 }
4693 /* Set MSR_VEC in the saved MSR value to indicate that
4694 frame->mc_vregs contains valid data. */
4695 if (__get_user(env->spr[SPR_VRSAVE],
4696 (target_ulong *)(&frame->mc_vregs.altivec[32].u32[3])))
4697 return 1;
4698 }
4699
4700 /* Restore floating point registers. */
4701 if (env->insns_flags & PPC_FLOAT) {
4702 uint64_t fpscr;
4703 for (i = 0; i < ARRAY_SIZE(env->fpr); i++) {
4704 if (__get_user(env->fpr[i], &frame->mc_fregs[i])) {
4705 return 1;
4706 }
4707 }
4708 if (__get_user(fpscr, &frame->mc_fregs[32]))
4709 return 1;
4710 env->fpscr = (uint32_t) fpscr;
4711 }
4712
4713 /* Save SPE registers. The kernel only saves the high half. */
4714 if (env->insns_flags & PPC_SPE) {
4715#if defined(TARGET_PPC64)
4716 for (i = 0; i < ARRAY_SIZE(env->gpr); i++) {
4717 uint32_t hi;
4718
4719 if (__get_user(hi, &frame->mc_vregs.spe[i])) {
4720 return 1;
4721 }
4722 env->gpr[i] = ((uint64_t)hi << 32) | ((uint32_t) env->gpr[i]);
4723 }
4724#else
4725 for (i = 0; i < ARRAY_SIZE(env->gprh); i++) {
4726 if (__get_user(env->gprh[i], &frame->mc_vregs.spe[i])) {
4727 return 1;
4728 }
4729 }
4730#endif
4731 if (__get_user(env->spe_fscr, &frame->mc_vregs.spe[32]))
4732 return 1;
4733 }
4734
4735 return 0;
4736}
4737
4738static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01004739 target_sigset_t *set, CPUPPCState *env)
Nathan Froydbcd49332009-05-12 19:13:18 -07004740{
4741 struct target_sigframe *frame;
4742 struct target_sigcontext *sc;
4743 target_ulong frame_addr, newsp;
4744 int err = 0;
4745 int signal;
4746
4747 frame_addr = get_sigframe(ka, env, sizeof(*frame));
4748 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 1))
4749 goto sigsegv;
4750 sc = &frame->sctx;
4751
4752 signal = current_exec_domain_sig(sig);
4753
Riku Voipio1d8b5122014-04-23 10:26:05 +03004754 __put_user(ka->_sa_handler, &sc->handler);
4755 __put_user(set->sig[0], &sc->oldmask);
Nathan Froydbcd49332009-05-12 19:13:18 -07004756#if defined(TARGET_PPC64)
Riku Voipio1d8b5122014-04-23 10:26:05 +03004757 __put_user(set->sig[0] >> 32, &sc->_unused[3]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004758#else
Riku Voipio1d8b5122014-04-23 10:26:05 +03004759 __put_user(set->sig[1], &sc->_unused[3]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004760#endif
Riku Voipio1d8b5122014-04-23 10:26:05 +03004761 __put_user(h2g(&frame->mctx), &sc->regs);
4762 __put_user(sig, &sc->signal);
Nathan Froydbcd49332009-05-12 19:13:18 -07004763
4764 /* Save user regs. */
4765 err |= save_user_regs(env, &frame->mctx, TARGET_NR_sigreturn);
4766
4767 /* The kernel checks for the presence of a VDSO here. We don't
4768 emulate a vdso, so use a sigreturn system call. */
4769 env->lr = (target_ulong) h2g(frame->mctx.tramp);
4770
4771 /* Turn off all fp exceptions. */
4772 env->fpscr = 0;
4773
4774 /* Create a stack frame for the caller of the handler. */
4775 newsp = frame_addr - SIGNAL_FRAMESIZE;
Samuel Seaybeb526b2013-01-02 10:53:46 +00004776 err |= put_user(env->gpr[1], newsp, target_ulong);
Nathan Froydbcd49332009-05-12 19:13:18 -07004777
4778 if (err)
4779 goto sigsegv;
4780
4781 /* Set up registers for signal handler. */
4782 env->gpr[1] = newsp;
4783 env->gpr[3] = signal;
Samuel Seay61993a62013-01-04 14:35:48 +00004784 env->gpr[4] = frame_addr + offsetof(struct target_sigframe, sctx);
Nathan Froydbcd49332009-05-12 19:13:18 -07004785 env->nip = (target_ulong) ka->_sa_handler;
4786 /* Signal handlers are entered in big-endian mode. */
4787 env->msr &= ~MSR_LE;
4788
4789 unlock_user_struct(frame, frame_addr, 1);
4790 return;
4791
4792sigsegv:
4793 unlock_user_struct(frame, frame_addr, 1);
Blue Swirleeacee42012-06-03 16:35:32 +00004794 qemu_log("segfaulting from setup_frame\n");
Riku Voipio66393fb2009-12-04 15:16:32 +02004795 force_sig(TARGET_SIGSEGV);
Nathan Froydbcd49332009-05-12 19:13:18 -07004796}
4797
4798static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05004799 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01004800 target_sigset_t *set, CPUPPCState *env)
Nathan Froydbcd49332009-05-12 19:13:18 -07004801{
4802 struct target_rt_sigframe *rt_sf;
4803 struct target_mcontext *frame;
4804 target_ulong rt_sf_addr, newsp = 0;
4805 int i, err = 0;
4806 int signal;
4807
4808 rt_sf_addr = get_sigframe(ka, env, sizeof(*rt_sf));
4809 if (!lock_user_struct(VERIFY_WRITE, rt_sf, rt_sf_addr, 1))
4810 goto sigsegv;
4811
4812 signal = current_exec_domain_sig(sig);
4813
Riku Voipiob0fd8d12014-04-23 10:46:13 +03004814 copy_siginfo_to_user(&rt_sf->info, info);
Nathan Froydbcd49332009-05-12 19:13:18 -07004815
Riku Voipio1d8b5122014-04-23 10:26:05 +03004816 __put_user(0, &rt_sf->uc.tuc_flags);
4817 __put_user(0, &rt_sf->uc.tuc_link);
4818 __put_user((target_ulong)target_sigaltstack_used.ss_sp,
4819 &rt_sf->uc.tuc_stack.ss_sp);
4820 __put_user(sas_ss_flags(env->gpr[1]),
4821 &rt_sf->uc.tuc_stack.ss_flags);
4822 __put_user(target_sigaltstack_used.ss_size,
4823 &rt_sf->uc.tuc_stack.ss_size);
4824 __put_user(h2g (&rt_sf->uc.tuc_mcontext),
4825 &rt_sf->uc.tuc_regs);
Nathan Froydbcd49332009-05-12 19:13:18 -07004826 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03004827 __put_user(set->sig[i], &rt_sf->uc.tuc_sigmask.sig[i]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004828 }
4829
Aurelien Jarno60e99242010-03-29 02:12:51 +02004830 frame = &rt_sf->uc.tuc_mcontext;
Nathan Froydbcd49332009-05-12 19:13:18 -07004831 err |= save_user_regs(env, frame, TARGET_NR_rt_sigreturn);
4832
4833 /* The kernel checks for the presence of a VDSO here. We don't
4834 emulate a vdso, so use a sigreturn system call. */
4835 env->lr = (target_ulong) h2g(frame->tramp);
4836
4837 /* Turn off all fp exceptions. */
4838 env->fpscr = 0;
4839
4840 /* Create a stack frame for the caller of the handler. */
4841 newsp = rt_sf_addr - (SIGNAL_FRAMESIZE + 16);
Riku Voipio1d8b5122014-04-23 10:26:05 +03004842 __put_user(env->gpr[1], (target_ulong *)(uintptr_t) newsp);
Nathan Froydbcd49332009-05-12 19:13:18 -07004843
4844 if (err)
4845 goto sigsegv;
4846
4847 /* Set up registers for signal handler. */
4848 env->gpr[1] = newsp;
4849 env->gpr[3] = (target_ulong) signal;
4850 env->gpr[4] = (target_ulong) h2g(&rt_sf->info);
4851 env->gpr[5] = (target_ulong) h2g(&rt_sf->uc);
4852 env->gpr[6] = (target_ulong) h2g(rt_sf);
4853 env->nip = (target_ulong) ka->_sa_handler;
4854 /* Signal handlers are entered in big-endian mode. */
4855 env->msr &= ~MSR_LE;
4856
4857 unlock_user_struct(rt_sf, rt_sf_addr, 1);
4858 return;
4859
4860sigsegv:
4861 unlock_user_struct(rt_sf, rt_sf_addr, 1);
Blue Swirleeacee42012-06-03 16:35:32 +00004862 qemu_log("segfaulting from setup_rt_frame\n");
Riku Voipio66393fb2009-12-04 15:16:32 +02004863 force_sig(TARGET_SIGSEGV);
Nathan Froydbcd49332009-05-12 19:13:18 -07004864
4865}
4866
Andreas Färber05390242012-02-25 03:37:53 +01004867long do_sigreturn(CPUPPCState *env)
Nathan Froydbcd49332009-05-12 19:13:18 -07004868{
4869 struct target_sigcontext *sc = NULL;
4870 struct target_mcontext *sr = NULL;
Peter Maydellb04636f2013-07-29 12:00:31 +01004871 target_ulong sr_addr = 0, sc_addr;
Nathan Froydbcd49332009-05-12 19:13:18 -07004872 sigset_t blocked;
Anthony Liguoric227f092009-10-01 16:12:16 -05004873 target_sigset_t set;
Nathan Froydbcd49332009-05-12 19:13:18 -07004874
4875 sc_addr = env->gpr[1] + SIGNAL_FRAMESIZE;
4876 if (!lock_user_struct(VERIFY_READ, sc, sc_addr, 1))
4877 goto sigsegv;
4878
4879#if defined(TARGET_PPC64)
4880 set.sig[0] = sc->oldmask + ((long)(sc->_unused[3]) << 32);
4881#else
4882 if(__get_user(set.sig[0], &sc->oldmask) ||
4883 __get_user(set.sig[1], &sc->_unused[3]))
4884 goto sigsegv;
4885#endif
4886 target_to_host_sigset_internal(&blocked, &set);
Alex Barcelo1c275922014-03-14 14:36:55 +00004887 do_sigprocmask(SIG_SETMASK, &blocked, NULL);
Nathan Froydbcd49332009-05-12 19:13:18 -07004888
4889 if (__get_user(sr_addr, &sc->regs))
4890 goto sigsegv;
4891 if (!lock_user_struct(VERIFY_READ, sr, sr_addr, 1))
4892 goto sigsegv;
4893 if (restore_user_regs(env, sr, 1))
4894 goto sigsegv;
4895
4896 unlock_user_struct(sr, sr_addr, 1);
4897 unlock_user_struct(sc, sc_addr, 1);
4898 return -TARGET_QEMU_ESIGRETURN;
4899
4900sigsegv:
4901 unlock_user_struct(sr, sr_addr, 1);
4902 unlock_user_struct(sc, sc_addr, 1);
Blue Swirleeacee42012-06-03 16:35:32 +00004903 qemu_log("segfaulting from do_sigreturn\n");
Riku Voipio66393fb2009-12-04 15:16:32 +02004904 force_sig(TARGET_SIGSEGV);
Nathan Froydbcd49332009-05-12 19:13:18 -07004905 return 0;
4906}
4907
4908/* See arch/powerpc/kernel/signal_32.c. */
Andreas Färber05390242012-02-25 03:37:53 +01004909static int do_setcontext(struct target_ucontext *ucp, CPUPPCState *env, int sig)
Nathan Froydbcd49332009-05-12 19:13:18 -07004910{
4911 struct target_mcontext *mcp;
4912 target_ulong mcp_addr;
4913 sigset_t blocked;
Anthony Liguoric227f092009-10-01 16:12:16 -05004914 target_sigset_t set;
Nathan Froydbcd49332009-05-12 19:13:18 -07004915
Aurelien Jarno60e99242010-03-29 02:12:51 +02004916 if (copy_from_user(&set, h2g(ucp) + offsetof(struct target_ucontext, tuc_sigmask),
Nathan Froydbcd49332009-05-12 19:13:18 -07004917 sizeof (set)))
4918 return 1;
4919
4920#if defined(TARGET_PPC64)
4921 fprintf (stderr, "do_setcontext: not implemented\n");
4922 return 0;
4923#else
Aurelien Jarno60e99242010-03-29 02:12:51 +02004924 if (__get_user(mcp_addr, &ucp->tuc_regs))
Nathan Froydbcd49332009-05-12 19:13:18 -07004925 return 1;
4926
4927 if (!lock_user_struct(VERIFY_READ, mcp, mcp_addr, 1))
4928 return 1;
4929
4930 target_to_host_sigset_internal(&blocked, &set);
Alex Barcelo1c275922014-03-14 14:36:55 +00004931 do_sigprocmask(SIG_SETMASK, &blocked, NULL);
Nathan Froydbcd49332009-05-12 19:13:18 -07004932 if (restore_user_regs(env, mcp, sig))
4933 goto sigsegv;
4934
4935 unlock_user_struct(mcp, mcp_addr, 1);
4936 return 0;
4937
4938sigsegv:
4939 unlock_user_struct(mcp, mcp_addr, 1);
4940 return 1;
4941#endif
4942}
4943
Andreas Färber05390242012-02-25 03:37:53 +01004944long do_rt_sigreturn(CPUPPCState *env)
Nathan Froydbcd49332009-05-12 19:13:18 -07004945{
4946 struct target_rt_sigframe *rt_sf = NULL;
4947 target_ulong rt_sf_addr;
4948
4949 rt_sf_addr = env->gpr[1] + SIGNAL_FRAMESIZE + 16;
4950 if (!lock_user_struct(VERIFY_READ, rt_sf, rt_sf_addr, 1))
4951 goto sigsegv;
4952
4953 if (do_setcontext(&rt_sf->uc, env, 1))
4954 goto sigsegv;
4955
4956 do_sigaltstack(rt_sf_addr
Aurelien Jarno60e99242010-03-29 02:12:51 +02004957 + offsetof(struct target_rt_sigframe, uc.tuc_stack),
Nathan Froydbcd49332009-05-12 19:13:18 -07004958 0, env->gpr[1]);
4959
4960 unlock_user_struct(rt_sf, rt_sf_addr, 1);
4961 return -TARGET_QEMU_ESIGRETURN;
4962
4963sigsegv:
4964 unlock_user_struct(rt_sf, rt_sf_addr, 1);
Blue Swirleeacee42012-06-03 16:35:32 +00004965 qemu_log("segfaulting from do_rt_sigreturn\n");
Riku Voipio66393fb2009-12-04 15:16:32 +02004966 force_sig(TARGET_SIGSEGV);
Nathan Froydbcd49332009-05-12 19:13:18 -07004967 return 0;
4968}
4969
Laurent Vivier492a8742009-08-03 16:12:17 +02004970#elif defined(TARGET_M68K)
4971
4972struct target_sigcontext {
4973 abi_ulong sc_mask;
4974 abi_ulong sc_usp;
4975 abi_ulong sc_d0;
4976 abi_ulong sc_d1;
4977 abi_ulong sc_a0;
4978 abi_ulong sc_a1;
4979 unsigned short sc_sr;
4980 abi_ulong sc_pc;
4981};
4982
4983struct target_sigframe
4984{
4985 abi_ulong pretcode;
4986 int sig;
4987 int code;
4988 abi_ulong psc;
4989 char retcode[8];
4990 abi_ulong extramask[TARGET_NSIG_WORDS-1];
4991 struct target_sigcontext sc;
4992};
Laurent Vivier71811552009-08-03 16:12:18 +02004993
Anthony Liguoric227f092009-10-01 16:12:16 -05004994typedef int target_greg_t;
Laurent Vivier71811552009-08-03 16:12:18 +02004995#define TARGET_NGREG 18
Anthony Liguoric227f092009-10-01 16:12:16 -05004996typedef target_greg_t target_gregset_t[TARGET_NGREG];
Laurent Vivier71811552009-08-03 16:12:18 +02004997
4998typedef struct target_fpregset {
4999 int f_fpcntl[3];
5000 int f_fpregs[8*3];
Anthony Liguoric227f092009-10-01 16:12:16 -05005001} target_fpregset_t;
Laurent Vivier71811552009-08-03 16:12:18 +02005002
5003struct target_mcontext {
5004 int version;
Anthony Liguoric227f092009-10-01 16:12:16 -05005005 target_gregset_t gregs;
5006 target_fpregset_t fpregs;
Laurent Vivier71811552009-08-03 16:12:18 +02005007};
5008
5009#define TARGET_MCONTEXT_VERSION 2
5010
5011struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02005012 abi_ulong tuc_flags;
5013 abi_ulong tuc_link;
5014 target_stack_t tuc_stack;
5015 struct target_mcontext tuc_mcontext;
5016 abi_long tuc_filler[80];
5017 target_sigset_t tuc_sigmask;
Laurent Vivier71811552009-08-03 16:12:18 +02005018};
5019
5020struct target_rt_sigframe
5021{
5022 abi_ulong pretcode;
5023 int sig;
5024 abi_ulong pinfo;
5025 abi_ulong puc;
5026 char retcode[8];
5027 struct target_siginfo info;
5028 struct target_ucontext uc;
5029};
Laurent Vivier492a8742009-08-03 16:12:17 +02005030
Riku Voipio41ecc722014-04-23 11:01:00 +03005031static void setup_sigcontext(struct target_sigcontext *sc, CPUM68KState *env,
5032 abi_ulong mask)
Laurent Vivier492a8742009-08-03 16:12:17 +02005033{
Riku Voipio1d8b5122014-04-23 10:26:05 +03005034 __put_user(mask, &sc->sc_mask);
5035 __put_user(env->aregs[7], &sc->sc_usp);
5036 __put_user(env->dregs[0], &sc->sc_d0);
5037 __put_user(env->dregs[1], &sc->sc_d1);
5038 __put_user(env->aregs[0], &sc->sc_a0);
5039 __put_user(env->aregs[1], &sc->sc_a1);
5040 __put_user(env->sr, &sc->sc_sr);
5041 __put_user(env->pc, &sc->sc_pc);
Laurent Vivier492a8742009-08-03 16:12:17 +02005042}
5043
Riku Voipio016d2e12014-04-23 11:19:48 +03005044static void
Andreas Färber05390242012-02-25 03:37:53 +01005045restore_sigcontext(CPUM68KState *env, struct target_sigcontext *sc, int *pd0)
Laurent Vivier492a8742009-08-03 16:12:17 +02005046{
Laurent Vivier492a8742009-08-03 16:12:17 +02005047 int temp;
5048
Riku Voipio1d8b5122014-04-23 10:26:05 +03005049 __get_user(env->aregs[7], &sc->sc_usp);
5050 __get_user(env->dregs[1], &sc->sc_d1);
5051 __get_user(env->aregs[0], &sc->sc_a0);
5052 __get_user(env->aregs[1], &sc->sc_a1);
5053 __get_user(env->pc, &sc->sc_pc);
5054 __get_user(temp, &sc->sc_sr);
Laurent Vivier492a8742009-08-03 16:12:17 +02005055 env->sr = (env->sr & 0xff00) | (temp & 0xff);
5056
5057 *pd0 = tswapl(sc->sc_d0);
Laurent Vivier492a8742009-08-03 16:12:17 +02005058}
5059
5060/*
5061 * Determine which stack to use..
5062 */
5063static inline abi_ulong
Andreas Färber05390242012-02-25 03:37:53 +01005064get_sigframe(struct target_sigaction *ka, CPUM68KState *regs,
5065 size_t frame_size)
Laurent Vivier492a8742009-08-03 16:12:17 +02005066{
5067 unsigned long sp;
5068
5069 sp = regs->aregs[7];
5070
5071 /* This is the X/Open sanctioned signal stack switching. */
5072 if ((ka->sa_flags & TARGET_SA_ONSTACK) && (sas_ss_flags (sp) == 0)) {
5073 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
5074 }
5075
5076 return ((sp - frame_size) & -8UL);
5077}
5078
5079static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01005080 target_sigset_t *set, CPUM68KState *env)
Laurent Vivier492a8742009-08-03 16:12:17 +02005081{
5082 struct target_sigframe *frame;
5083 abi_ulong frame_addr;
5084 abi_ulong retcode_addr;
5085 abi_ulong sc_addr;
5086 int err = 0;
5087 int i;
5088
5089 frame_addr = get_sigframe(ka, env, sizeof *frame);
5090 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
5091 goto give_sigsegv;
5092
Riku Voipio1d8b5122014-04-23 10:26:05 +03005093 __put_user(sig, &frame->sig);
Laurent Vivier492a8742009-08-03 16:12:17 +02005094
5095 sc_addr = frame_addr + offsetof(struct target_sigframe, sc);
Riku Voipio1d8b5122014-04-23 10:26:05 +03005096 __put_user(sc_addr, &frame->psc);
Laurent Vivier492a8742009-08-03 16:12:17 +02005097
Riku Voipio41ecc722014-04-23 11:01:00 +03005098 setup_sigcontext(&frame->sc, env, set->sig[0]);
Laurent Vivier492a8742009-08-03 16:12:17 +02005099
5100 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
5101 if (__put_user(set->sig[i], &frame->extramask[i - 1]))
5102 goto give_sigsegv;
5103 }
5104
5105 /* Set up to return from userspace. */
5106
5107 retcode_addr = frame_addr + offsetof(struct target_sigframe, retcode);
Riku Voipio1d8b5122014-04-23 10:26:05 +03005108 __put_user(retcode_addr, &frame->pretcode);
Laurent Vivier492a8742009-08-03 16:12:17 +02005109
5110 /* moveq #,d0; trap #0 */
5111
Riku Voipio1d8b5122014-04-23 10:26:05 +03005112 __put_user(0x70004e40 + (TARGET_NR_sigreturn << 16),
Laurent Vivier492a8742009-08-03 16:12:17 +02005113 (long *)(frame->retcode));
5114
5115 if (err)
5116 goto give_sigsegv;
5117
5118 /* Set up to return from userspace */
5119
5120 env->aregs[7] = frame_addr;
5121 env->pc = ka->_sa_handler;
5122
5123 unlock_user_struct(frame, frame_addr, 1);
5124 return;
5125
5126give_sigsegv:
5127 unlock_user_struct(frame, frame_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02005128 force_sig(TARGET_SIGSEGV);
Laurent Vivier492a8742009-08-03 16:12:17 +02005129}
5130
Laurent Vivier71811552009-08-03 16:12:18 +02005131static inline int target_rt_setup_ucontext(struct target_ucontext *uc,
Andreas Färber05390242012-02-25 03:37:53 +01005132 CPUM68KState *env)
Laurent Vivier71811552009-08-03 16:12:18 +02005133{
Aurelien Jarno60e99242010-03-29 02:12:51 +02005134 target_greg_t *gregs = uc->tuc_mcontext.gregs;
Laurent Vivier71811552009-08-03 16:12:18 +02005135
Riku Voipio1d8b5122014-04-23 10:26:05 +03005136 __put_user(TARGET_MCONTEXT_VERSION, &uc->tuc_mcontext.version);
5137 __put_user(env->dregs[0], &gregs[0]);
5138 __put_user(env->dregs[1], &gregs[1]);
5139 __put_user(env->dregs[2], &gregs[2]);
5140 __put_user(env->dregs[3], &gregs[3]);
5141 __put_user(env->dregs[4], &gregs[4]);
5142 __put_user(env->dregs[5], &gregs[5]);
5143 __put_user(env->dregs[6], &gregs[6]);
5144 __put_user(env->dregs[7], &gregs[7]);
5145 __put_user(env->aregs[0], &gregs[8]);
5146 __put_user(env->aregs[1], &gregs[9]);
5147 __put_user(env->aregs[2], &gregs[10]);
5148 __put_user(env->aregs[3], &gregs[11]);
5149 __put_user(env->aregs[4], &gregs[12]);
5150 __put_user(env->aregs[5], &gregs[13]);
5151 __put_user(env->aregs[6], &gregs[14]);
5152 __put_user(env->aregs[7], &gregs[15]);
5153 __put_user(env->pc, &gregs[16]);
5154 __put_user(env->sr, &gregs[17]);
Laurent Vivier71811552009-08-03 16:12:18 +02005155
Riku Voipio1d8b5122014-04-23 10:26:05 +03005156 return 0;
Laurent Vivier71811552009-08-03 16:12:18 +02005157}
5158
Andreas Färber05390242012-02-25 03:37:53 +01005159static inline int target_rt_restore_ucontext(CPUM68KState *env,
Laurent Vivier71811552009-08-03 16:12:18 +02005160 struct target_ucontext *uc,
5161 int *pd0)
5162{
5163 int temp;
Aurelien Jarno60e99242010-03-29 02:12:51 +02005164 target_greg_t *gregs = uc->tuc_mcontext.gregs;
Laurent Vivier71811552009-08-03 16:12:18 +02005165
Riku Voipio1d8b5122014-04-23 10:26:05 +03005166 __get_user(temp, &uc->tuc_mcontext.version);
Laurent Vivier71811552009-08-03 16:12:18 +02005167 if (temp != TARGET_MCONTEXT_VERSION)
5168 goto badframe;
5169
5170 /* restore passed registers */
Riku Voipio1d8b5122014-04-23 10:26:05 +03005171 __get_user(env->dregs[0], &gregs[0]);
5172 __get_user(env->dregs[1], &gregs[1]);
5173 __get_user(env->dregs[2], &gregs[2]);
5174 __get_user(env->dregs[3], &gregs[3]);
5175 __get_user(env->dregs[4], &gregs[4]);
5176 __get_user(env->dregs[5], &gregs[5]);
5177 __get_user(env->dregs[6], &gregs[6]);
5178 __get_user(env->dregs[7], &gregs[7]);
5179 __get_user(env->aregs[0], &gregs[8]);
5180 __get_user(env->aregs[1], &gregs[9]);
5181 __get_user(env->aregs[2], &gregs[10]);
5182 __get_user(env->aregs[3], &gregs[11]);
5183 __get_user(env->aregs[4], &gregs[12]);
5184 __get_user(env->aregs[5], &gregs[13]);
5185 __get_user(env->aregs[6], &gregs[14]);
5186 __get_user(env->aregs[7], &gregs[15]);
5187 __get_user(env->pc, &gregs[16]);
5188 __get_user(temp, &gregs[17]);
Laurent Vivier71811552009-08-03 16:12:18 +02005189 env->sr = (env->sr & 0xff00) | (temp & 0xff);
5190
5191 *pd0 = env->dregs[0];
Riku Voipio1d8b5122014-04-23 10:26:05 +03005192 return 0;
Laurent Vivier71811552009-08-03 16:12:18 +02005193
5194badframe:
5195 return 1;
5196}
5197
Laurent Vivier492a8742009-08-03 16:12:17 +02005198static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05005199 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01005200 target_sigset_t *set, CPUM68KState *env)
Laurent Vivier492a8742009-08-03 16:12:17 +02005201{
Laurent Vivier71811552009-08-03 16:12:18 +02005202 struct target_rt_sigframe *frame;
5203 abi_ulong frame_addr;
5204 abi_ulong retcode_addr;
5205 abi_ulong info_addr;
5206 abi_ulong uc_addr;
5207 int err = 0;
5208 int i;
5209
5210 frame_addr = get_sigframe(ka, env, sizeof *frame);
5211 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
5212 goto give_sigsegv;
5213
Riku Voipio1d8b5122014-04-23 10:26:05 +03005214 __put_user(sig, &frame->sig);
Laurent Vivier71811552009-08-03 16:12:18 +02005215
5216 info_addr = frame_addr + offsetof(struct target_rt_sigframe, info);
Riku Voipio1d8b5122014-04-23 10:26:05 +03005217 __put_user(info_addr, &frame->pinfo);
Laurent Vivier71811552009-08-03 16:12:18 +02005218
5219 uc_addr = frame_addr + offsetof(struct target_rt_sigframe, uc);
Riku Voipio1d8b5122014-04-23 10:26:05 +03005220 __put_user(uc_addr, &frame->puc);
Laurent Vivier71811552009-08-03 16:12:18 +02005221
Riku Voipiob0fd8d12014-04-23 10:46:13 +03005222 copy_siginfo_to_user(&frame->info, info);
Laurent Vivier71811552009-08-03 16:12:18 +02005223
5224 /* Create the ucontext */
5225
Riku Voipio1d8b5122014-04-23 10:26:05 +03005226 __put_user(0, &frame->uc.tuc_flags);
5227 __put_user(0, &frame->uc.tuc_link);
5228 __put_user(target_sigaltstack_used.ss_sp,
5229 &frame->uc.tuc_stack.ss_sp);
5230 __put_user(sas_ss_flags(env->aregs[7]),
5231 &frame->uc.tuc_stack.ss_flags);
5232 __put_user(target_sigaltstack_used.ss_size,
5233 &frame->uc.tuc_stack.ss_size);
Laurent Vivier71811552009-08-03 16:12:18 +02005234 err |= target_rt_setup_ucontext(&frame->uc, env);
5235
5236 if (err)
5237 goto give_sigsegv;
5238
5239 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
Aurelien Jarno60e99242010-03-29 02:12:51 +02005240 if (__put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]))
Laurent Vivier71811552009-08-03 16:12:18 +02005241 goto give_sigsegv;
5242 }
5243
5244 /* Set up to return from userspace. */
5245
5246 retcode_addr = frame_addr + offsetof(struct target_sigframe, retcode);
Riku Voipio1d8b5122014-04-23 10:26:05 +03005247 __put_user(retcode_addr, &frame->pretcode);
Laurent Vivier71811552009-08-03 16:12:18 +02005248
5249 /* moveq #,d0; notb d0; trap #0 */
5250
Riku Voipio1d8b5122014-04-23 10:26:05 +03005251 __put_user(0x70004600 + ((TARGET_NR_rt_sigreturn ^ 0xff) << 16),
5252 (long *)(frame->retcode + 0));
5253 __put_user(0x4e40, (short *)(frame->retcode + 4));
Laurent Vivier71811552009-08-03 16:12:18 +02005254
5255 if (err)
5256 goto give_sigsegv;
5257
5258 /* Set up to return from userspace */
5259
5260 env->aregs[7] = frame_addr;
5261 env->pc = ka->_sa_handler;
5262
5263 unlock_user_struct(frame, frame_addr, 1);
5264 return;
5265
5266give_sigsegv:
5267 unlock_user_struct(frame, frame_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02005268 force_sig(TARGET_SIGSEGV);
Laurent Vivier492a8742009-08-03 16:12:17 +02005269}
5270
Andreas Färber05390242012-02-25 03:37:53 +01005271long do_sigreturn(CPUM68KState *env)
Laurent Vivier492a8742009-08-03 16:12:17 +02005272{
5273 struct target_sigframe *frame;
5274 abi_ulong frame_addr = env->aregs[7] - 4;
Anthony Liguoric227f092009-10-01 16:12:16 -05005275 target_sigset_t target_set;
Laurent Vivier492a8742009-08-03 16:12:17 +02005276 sigset_t set;
5277 int d0, i;
5278
5279 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
5280 goto badframe;
5281
5282 /* set blocked signals */
5283
5284 if (__get_user(target_set.sig[0], &frame->sc.sc_mask))
5285 goto badframe;
5286
5287 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
5288 if (__get_user(target_set.sig[i], &frame->extramask[i - 1]))
5289 goto badframe;
5290 }
5291
5292 target_to_host_sigset_internal(&set, &target_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00005293 do_sigprocmask(SIG_SETMASK, &set, NULL);
Laurent Vivier492a8742009-08-03 16:12:17 +02005294
5295 /* restore registers */
5296
Riku Voipio016d2e12014-04-23 11:19:48 +03005297 restore_sigcontext(env, &frame->sc, &d0);
Laurent Vivier492a8742009-08-03 16:12:17 +02005298
5299 unlock_user_struct(frame, frame_addr, 0);
5300 return d0;
5301
5302badframe:
5303 unlock_user_struct(frame, frame_addr, 0);
5304 force_sig(TARGET_SIGSEGV);
5305 return 0;
5306}
5307
Andreas Färber05390242012-02-25 03:37:53 +01005308long do_rt_sigreturn(CPUM68KState *env)
Laurent Vivier492a8742009-08-03 16:12:17 +02005309{
Laurent Vivier71811552009-08-03 16:12:18 +02005310 struct target_rt_sigframe *frame;
5311 abi_ulong frame_addr = env->aregs[7] - 4;
Anthony Liguoric227f092009-10-01 16:12:16 -05005312 target_sigset_t target_set;
Laurent Vivier71811552009-08-03 16:12:18 +02005313 sigset_t set;
5314 int d0;
5315
5316 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
5317 goto badframe;
5318
5319 target_to_host_sigset_internal(&set, &target_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00005320 do_sigprocmask(SIG_SETMASK, &set, NULL);
Laurent Vivier71811552009-08-03 16:12:18 +02005321
5322 /* restore registers */
5323
5324 if (target_rt_restore_ucontext(env, &frame->uc, &d0))
5325 goto badframe;
5326
5327 if (do_sigaltstack(frame_addr +
Aurelien Jarno60e99242010-03-29 02:12:51 +02005328 offsetof(struct target_rt_sigframe, uc.tuc_stack),
Laurent Vivier71811552009-08-03 16:12:18 +02005329 0, get_sp_from_cpustate(env)) == -EFAULT)
5330 goto badframe;
5331
5332 unlock_user_struct(frame, frame_addr, 0);
5333 return d0;
5334
5335badframe:
5336 unlock_user_struct(frame, frame_addr, 0);
5337 force_sig(TARGET_SIGSEGV);
5338 return 0;
Laurent Vivier492a8742009-08-03 16:12:17 +02005339}
5340
Richard Henderson6049f4f2009-12-27 18:30:03 -08005341#elif defined(TARGET_ALPHA)
5342
5343struct target_sigcontext {
5344 abi_long sc_onstack;
5345 abi_long sc_mask;
5346 abi_long sc_pc;
5347 abi_long sc_ps;
5348 abi_long sc_regs[32];
5349 abi_long sc_ownedfp;
5350 abi_long sc_fpregs[32];
5351 abi_ulong sc_fpcr;
5352 abi_ulong sc_fp_control;
5353 abi_ulong sc_reserved1;
5354 abi_ulong sc_reserved2;
5355 abi_ulong sc_ssize;
5356 abi_ulong sc_sbase;
5357 abi_ulong sc_traparg_a0;
5358 abi_ulong sc_traparg_a1;
5359 abi_ulong sc_traparg_a2;
5360 abi_ulong sc_fp_trap_pc;
5361 abi_ulong sc_fp_trigger_sum;
5362 abi_ulong sc_fp_trigger_inst;
5363};
5364
5365struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02005366 abi_ulong tuc_flags;
5367 abi_ulong tuc_link;
5368 abi_ulong tuc_osf_sigmask;
5369 target_stack_t tuc_stack;
5370 struct target_sigcontext tuc_mcontext;
5371 target_sigset_t tuc_sigmask;
Richard Henderson6049f4f2009-12-27 18:30:03 -08005372};
5373
5374struct target_sigframe {
5375 struct target_sigcontext sc;
5376 unsigned int retcode[3];
5377};
5378
5379struct target_rt_sigframe {
5380 target_siginfo_t info;
5381 struct target_ucontext uc;
5382 unsigned int retcode[3];
5383};
5384
5385#define INSN_MOV_R30_R16 0x47fe0410
5386#define INSN_LDI_R0 0x201f0000
5387#define INSN_CALLSYS 0x00000083
5388
Riku Voipio41ecc722014-04-23 11:01:00 +03005389static void setup_sigcontext(struct target_sigcontext *sc, CPUAlphaState *env,
Richard Henderson6049f4f2009-12-27 18:30:03 -08005390 abi_ulong frame_addr, target_sigset_t *set)
5391{
Riku Voipio41ecc722014-04-23 11:01:00 +03005392 int i;
Richard Henderson6049f4f2009-12-27 18:30:03 -08005393
Riku Voipio1d8b5122014-04-23 10:26:05 +03005394 __put_user(on_sig_stack(frame_addr), &sc->sc_onstack);
5395 __put_user(set->sig[0], &sc->sc_mask);
5396 __put_user(env->pc, &sc->sc_pc);
5397 __put_user(8, &sc->sc_ps);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005398
5399 for (i = 0; i < 31; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03005400 __put_user(env->ir[i], &sc->sc_regs[i]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005401 }
Riku Voipio1d8b5122014-04-23 10:26:05 +03005402 __put_user(0, &sc->sc_regs[31]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005403
5404 for (i = 0; i < 31; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03005405 __put_user(env->fir[i], &sc->sc_fpregs[i]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005406 }
Riku Voipio1d8b5122014-04-23 10:26:05 +03005407 __put_user(0, &sc->sc_fpregs[31]);
5408 __put_user(cpu_alpha_load_fpcr(env), &sc->sc_fpcr);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005409
Riku Voipio1d8b5122014-04-23 10:26:05 +03005410 __put_user(0, &sc->sc_traparg_a0); /* FIXME */
5411 __put_user(0, &sc->sc_traparg_a1); /* FIXME */
5412 __put_user(0, &sc->sc_traparg_a2); /* FIXME */
Richard Henderson6049f4f2009-12-27 18:30:03 -08005413}
5414
Riku Voipio016d2e12014-04-23 11:19:48 +03005415static void restore_sigcontext(CPUAlphaState *env,
Andreas Färber05390242012-02-25 03:37:53 +01005416 struct target_sigcontext *sc)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005417{
5418 uint64_t fpcr;
Riku Voipio016d2e12014-04-23 11:19:48 +03005419 int i;
Richard Henderson6049f4f2009-12-27 18:30:03 -08005420
Riku Voipio1d8b5122014-04-23 10:26:05 +03005421 __get_user(env->pc, &sc->sc_pc);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005422
5423 for (i = 0; i < 31; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03005424 __get_user(env->ir[i], &sc->sc_regs[i]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005425 }
5426 for (i = 0; i < 31; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03005427 __get_user(env->fir[i], &sc->sc_fpregs[i]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005428 }
5429
Riku Voipio1d8b5122014-04-23 10:26:05 +03005430 __get_user(fpcr, &sc->sc_fpcr);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005431 cpu_alpha_store_fpcr(env, fpcr);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005432}
5433
5434static inline abi_ulong get_sigframe(struct target_sigaction *sa,
Andreas Färber05390242012-02-25 03:37:53 +01005435 CPUAlphaState *env,
5436 unsigned long framesize)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005437{
5438 abi_ulong sp = env->ir[IR_SP];
5439
5440 /* This is the X/Open sanctioned signal stack switching. */
5441 if ((sa->sa_flags & TARGET_SA_ONSTACK) != 0 && !sas_ss_flags(sp)) {
5442 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
5443 }
5444 return (sp - framesize) & -32;
5445}
5446
5447static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01005448 target_sigset_t *set, CPUAlphaState *env)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005449{
5450 abi_ulong frame_addr, r26;
5451 struct target_sigframe *frame;
5452 int err = 0;
5453
5454 frame_addr = get_sigframe(ka, env, sizeof(*frame));
5455 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
5456 goto give_sigsegv;
5457 }
5458
Riku Voipio41ecc722014-04-23 11:01:00 +03005459 setup_sigcontext(&frame->sc, env, frame_addr, set);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005460
5461 if (ka->sa_restorer) {
5462 r26 = ka->sa_restorer;
5463 } else {
Riku Voipio1d8b5122014-04-23 10:26:05 +03005464 __put_user(INSN_MOV_R30_R16, &frame->retcode[0]);
5465 __put_user(INSN_LDI_R0 + TARGET_NR_sigreturn,
5466 &frame->retcode[1]);
5467 __put_user(INSN_CALLSYS, &frame->retcode[2]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005468 /* imb() */
5469 r26 = frame_addr;
5470 }
5471
5472 unlock_user_struct(frame, frame_addr, 1);
5473
5474 if (err) {
5475 give_sigsegv:
5476 if (sig == TARGET_SIGSEGV) {
5477 ka->_sa_handler = TARGET_SIG_DFL;
5478 }
5479 force_sig(TARGET_SIGSEGV);
5480 }
5481
5482 env->ir[IR_RA] = r26;
5483 env->ir[IR_PV] = env->pc = ka->_sa_handler;
5484 env->ir[IR_A0] = sig;
5485 env->ir[IR_A1] = 0;
5486 env->ir[IR_A2] = frame_addr + offsetof(struct target_sigframe, sc);
5487 env->ir[IR_SP] = frame_addr;
5488}
5489
5490static void setup_rt_frame(int sig, struct target_sigaction *ka,
5491 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01005492 target_sigset_t *set, CPUAlphaState *env)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005493{
5494 abi_ulong frame_addr, r26;
5495 struct target_rt_sigframe *frame;
5496 int i, err = 0;
5497
5498 frame_addr = get_sigframe(ka, env, sizeof(*frame));
5499 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
5500 goto give_sigsegv;
5501 }
5502
Riku Voipiob0fd8d12014-04-23 10:46:13 +03005503 copy_siginfo_to_user(&frame->info, info);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005504
Riku Voipio1d8b5122014-04-23 10:26:05 +03005505 __put_user(0, &frame->uc.tuc_flags);
5506 __put_user(0, &frame->uc.tuc_link);
5507 __put_user(set->sig[0], &frame->uc.tuc_osf_sigmask);
5508 __put_user(target_sigaltstack_used.ss_sp,
5509 &frame->uc.tuc_stack.ss_sp);
5510 __put_user(sas_ss_flags(env->ir[IR_SP]),
5511 &frame->uc.tuc_stack.ss_flags);
5512 __put_user(target_sigaltstack_used.ss_size,
5513 &frame->uc.tuc_stack.ss_size);
Riku Voipio41ecc722014-04-23 11:01:00 +03005514 setup_sigcontext(&frame->uc.tuc_mcontext, env, frame_addr, set);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005515 for (i = 0; i < TARGET_NSIG_WORDS; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03005516 __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005517 }
5518
5519 if (ka->sa_restorer) {
5520 r26 = ka->sa_restorer;
5521 } else {
Riku Voipio1d8b5122014-04-23 10:26:05 +03005522 __put_user(INSN_MOV_R30_R16, &frame->retcode[0]);
5523 __put_user(INSN_LDI_R0 + TARGET_NR_rt_sigreturn,
5524 &frame->retcode[1]);
5525 __put_user(INSN_CALLSYS, &frame->retcode[2]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005526 /* imb(); */
5527 r26 = frame_addr;
5528 }
5529
5530 if (err) {
5531 give_sigsegv:
5532 if (sig == TARGET_SIGSEGV) {
5533 ka->_sa_handler = TARGET_SIG_DFL;
5534 }
5535 force_sig(TARGET_SIGSEGV);
5536 }
5537
5538 env->ir[IR_RA] = r26;
5539 env->ir[IR_PV] = env->pc = ka->_sa_handler;
5540 env->ir[IR_A0] = sig;
5541 env->ir[IR_A1] = frame_addr + offsetof(struct target_rt_sigframe, info);
5542 env->ir[IR_A2] = frame_addr + offsetof(struct target_rt_sigframe, uc);
5543 env->ir[IR_SP] = frame_addr;
5544}
5545
Andreas Färber05390242012-02-25 03:37:53 +01005546long do_sigreturn(CPUAlphaState *env)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005547{
5548 struct target_sigcontext *sc;
5549 abi_ulong sc_addr = env->ir[IR_A0];
5550 target_sigset_t target_set;
5551 sigset_t set;
5552
5553 if (!lock_user_struct(VERIFY_READ, sc, sc_addr, 1)) {
5554 goto badframe;
5555 }
5556
5557 target_sigemptyset(&target_set);
5558 if (__get_user(target_set.sig[0], &sc->sc_mask)) {
5559 goto badframe;
5560 }
5561
5562 target_to_host_sigset_internal(&set, &target_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00005563 do_sigprocmask(SIG_SETMASK, &set, NULL);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005564
Riku Voipio016d2e12014-04-23 11:19:48 +03005565 restore_sigcontext(env, sc);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005566 unlock_user_struct(sc, sc_addr, 0);
5567 return env->ir[IR_V0];
5568
5569 badframe:
5570 unlock_user_struct(sc, sc_addr, 0);
5571 force_sig(TARGET_SIGSEGV);
5572}
5573
Andreas Färber05390242012-02-25 03:37:53 +01005574long do_rt_sigreturn(CPUAlphaState *env)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005575{
5576 abi_ulong frame_addr = env->ir[IR_A0];
5577 struct target_rt_sigframe *frame;
5578 sigset_t set;
5579
5580 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
5581 goto badframe;
5582 }
Aurelien Jarno60e99242010-03-29 02:12:51 +02005583 target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
Alex Barcelo1c275922014-03-14 14:36:55 +00005584 do_sigprocmask(SIG_SETMASK, &set, NULL);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005585
Riku Voipio016d2e12014-04-23 11:19:48 +03005586 restore_sigcontext(env, &frame->uc.tuc_mcontext);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005587 if (do_sigaltstack(frame_addr + offsetof(struct target_rt_sigframe,
Aurelien Jarno60e99242010-03-29 02:12:51 +02005588 uc.tuc_stack),
Richard Henderson6049f4f2009-12-27 18:30:03 -08005589 0, env->ir[IR_SP]) == -EFAULT) {
5590 goto badframe;
5591 }
5592
5593 unlock_user_struct(frame, frame_addr, 0);
5594 return env->ir[IR_V0];
5595
5596
5597 badframe:
5598 unlock_user_struct(frame, frame_addr, 0);
5599 force_sig(TARGET_SIGSEGV);
5600}
5601
bellardb346ff42003-06-15 20:05:50 +00005602#else
5603
pbrook624f7972008-05-31 16:11:38 +00005604static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber9349b4f2012-03-14 01:38:32 +01005605 target_sigset_t *set, CPUArchState *env)
bellardb346ff42003-06-15 20:05:50 +00005606{
5607 fprintf(stderr, "setup_frame: not implemented\n");
5608}
5609
pbrook624f7972008-05-31 16:11:38 +00005610static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05005611 target_siginfo_t *info,
Andreas Färber9349b4f2012-03-14 01:38:32 +01005612 target_sigset_t *set, CPUArchState *env)
bellardb346ff42003-06-15 20:05:50 +00005613{
5614 fprintf(stderr, "setup_rt_frame: not implemented\n");
5615}
5616
Andreas Färber9349b4f2012-03-14 01:38:32 +01005617long do_sigreturn(CPUArchState *env)
bellardb346ff42003-06-15 20:05:50 +00005618{
5619 fprintf(stderr, "do_sigreturn: not implemented\n");
bellardf8b0aa22007-11-11 23:03:42 +00005620 return -TARGET_ENOSYS;
bellardb346ff42003-06-15 20:05:50 +00005621}
5622
Andreas Färber9349b4f2012-03-14 01:38:32 +01005623long do_rt_sigreturn(CPUArchState *env)
bellardb346ff42003-06-15 20:05:50 +00005624{
5625 fprintf(stderr, "do_rt_sigreturn: not implemented\n");
bellardf8b0aa22007-11-11 23:03:42 +00005626 return -TARGET_ENOSYS;
bellardb346ff42003-06-15 20:05:50 +00005627}
5628
bellard66fb9762003-03-23 01:06:05 +00005629#endif
5630
Andreas Färber9349b4f2012-03-14 01:38:32 +01005631void process_pending_signals(CPUArchState *cpu_env)
bellard66fb9762003-03-23 01:06:05 +00005632{
Andreas Färberdb6b81d2013-06-27 19:49:31 +02005633 CPUState *cpu = ENV_GET_CPU(cpu_env);
bellard66fb9762003-03-23 01:06:05 +00005634 int sig;
blueswir1992f48a2007-10-14 16:27:31 +00005635 abi_ulong handler;
bellard9de5e442003-03-23 16:49:39 +00005636 sigset_t set, old_set;
Anthony Liguoric227f092009-10-01 16:12:16 -05005637 target_sigset_t target_old_set;
pbrook624f7972008-05-31 16:11:38 +00005638 struct emulated_sigtable *k;
5639 struct target_sigaction *sa;
bellard66fb9762003-03-23 01:06:05 +00005640 struct sigqueue *q;
Andreas Färber0429a972013-08-26 18:14:44 +02005641 TaskState *ts = cpu->opaque;
ths3b46e622007-09-17 08:09:54 +00005642
pbrook624f7972008-05-31 16:11:38 +00005643 if (!ts->signal_pending)
bellard31e31b82003-02-18 22:55:36 +00005644 return;
5645
pbrook624f7972008-05-31 16:11:38 +00005646 /* FIXME: This is not threadsafe. */
5647 k = ts->sigtab;
bellard66fb9762003-03-23 01:06:05 +00005648 for(sig = 1; sig <= TARGET_NSIG; sig++) {
5649 if (k->pending)
bellard31e31b82003-02-18 22:55:36 +00005650 goto handle_signal;
bellard66fb9762003-03-23 01:06:05 +00005651 k++;
bellard31e31b82003-02-18 22:55:36 +00005652 }
5653 /* if no signal is pending, just return */
pbrook624f7972008-05-31 16:11:38 +00005654 ts->signal_pending = 0;
bellard31e31b82003-02-18 22:55:36 +00005655 return;
bellard66fb9762003-03-23 01:06:05 +00005656
bellard31e31b82003-02-18 22:55:36 +00005657 handle_signal:
bellard66fb9762003-03-23 01:06:05 +00005658#ifdef DEBUG_SIGNAL
bellardbc8a22c2003-03-30 21:02:40 +00005659 fprintf(stderr, "qemu: process signal %d\n", sig);
bellard66fb9762003-03-23 01:06:05 +00005660#endif
5661 /* dequeue signal */
5662 q = k->first;
5663 k->first = q->next;
5664 if (!k->first)
5665 k->pending = 0;
ths3b46e622007-09-17 08:09:54 +00005666
Andreas Färberdb6b81d2013-06-27 19:49:31 +02005667 sig = gdb_handlesig(cpu, sig);
bellard1fddef42005-04-17 19:16:13 +00005668 if (!sig) {
aurel32ca587a82008-12-18 22:44:13 +00005669 sa = NULL;
5670 handler = TARGET_SIG_IGN;
5671 } else {
5672 sa = &sigact_table[sig - 1];
5673 handler = sa->_sa_handler;
bellard1fddef42005-04-17 19:16:13 +00005674 }
bellard66fb9762003-03-23 01:06:05 +00005675
Peter Maydella7ec0f92014-03-14 14:36:56 +00005676 if (ts->sigsegv_blocked && sig == TARGET_SIGSEGV) {
5677 /* Guest has blocked SIGSEGV but we got one anyway. Assume this
5678 * is a forced SIGSEGV (ie one the kernel handles via force_sig_info
5679 * because it got a real MMU fault), and treat as if default handler.
5680 */
5681 handler = TARGET_SIG_DFL;
5682 }
5683
bellard66fb9762003-03-23 01:06:05 +00005684 if (handler == TARGET_SIG_DFL) {
aurel32ca587a82008-12-18 22:44:13 +00005685 /* default handler : ignore some signal. The other are job control or fatal */
5686 if (sig == TARGET_SIGTSTP || sig == TARGET_SIGTTIN || sig == TARGET_SIGTTOU) {
5687 kill(getpid(),SIGSTOP);
5688 } else if (sig != TARGET_SIGCHLD &&
5689 sig != TARGET_SIGURG &&
5690 sig != TARGET_SIGWINCH &&
5691 sig != TARGET_SIGCONT) {
bellard66fb9762003-03-23 01:06:05 +00005692 force_sig(sig);
5693 }
5694 } else if (handler == TARGET_SIG_IGN) {
5695 /* ignore sig */
5696 } else if (handler == TARGET_SIG_ERR) {
5697 force_sig(sig);
5698 } else {
bellard9de5e442003-03-23 16:49:39 +00005699 /* compute the blocked signals during the handler execution */
pbrook624f7972008-05-31 16:11:38 +00005700 target_to_host_sigset(&set, &sa->sa_mask);
bellard9de5e442003-03-23 16:49:39 +00005701 /* SA_NODEFER indicates that the current signal should not be
5702 blocked during the handler */
pbrook624f7972008-05-31 16:11:38 +00005703 if (!(sa->sa_flags & TARGET_SA_NODEFER))
bellard9de5e442003-03-23 16:49:39 +00005704 sigaddset(&set, target_to_host_signal(sig));
ths3b46e622007-09-17 08:09:54 +00005705
bellard9de5e442003-03-23 16:49:39 +00005706 /* block signals in the handler using Linux */
Alex Barcelo1c275922014-03-14 14:36:55 +00005707 do_sigprocmask(SIG_BLOCK, &set, &old_set);
bellard9de5e442003-03-23 16:49:39 +00005708 /* save the previous blocked signal state to restore it at the
5709 end of the signal execution (see do_sigreturn) */
bellard92319442004-06-19 16:58:13 +00005710 host_to_target_sigset_internal(&target_old_set, &old_set);
bellard9de5e442003-03-23 16:49:39 +00005711
bellardbc8a22c2003-03-30 21:02:40 +00005712 /* if the CPU is in VM86 mode, we restore the 32 bit values */
j_mayer84409dd2007-04-06 08:56:50 +00005713#if defined(TARGET_I386) && !defined(TARGET_X86_64)
bellardbc8a22c2003-03-30 21:02:40 +00005714 {
5715 CPUX86State *env = cpu_env;
5716 if (env->eflags & VM_MASK)
5717 save_v86_state(env);
5718 }
5719#endif
bellard9de5e442003-03-23 16:49:39 +00005720 /* prepare the stack frame of the virtual CPU */
Richard Hendersonff970902013-02-10 10:30:42 -08005721#if defined(TARGET_ABI_MIPSN32) || defined(TARGET_ABI_MIPSN64)
5722 /* These targets do not have traditional signals. */
5723 setup_rt_frame(sig, sa, &q->info, &target_old_set, cpu_env);
5724#else
pbrook624f7972008-05-31 16:11:38 +00005725 if (sa->sa_flags & TARGET_SA_SIGINFO)
5726 setup_rt_frame(sig, sa, &q->info, &target_old_set, cpu_env);
bellard66fb9762003-03-23 01:06:05 +00005727 else
pbrook624f7972008-05-31 16:11:38 +00005728 setup_frame(sig, sa, &target_old_set, cpu_env);
Richard Hendersonff970902013-02-10 10:30:42 -08005729#endif
pbrook624f7972008-05-31 16:11:38 +00005730 if (sa->sa_flags & TARGET_SA_RESETHAND)
5731 sa->_sa_handler = TARGET_SIG_DFL;
bellard31e31b82003-02-18 22:55:36 +00005732 }
bellard66fb9762003-03-23 01:06:05 +00005733 if (q != &k->info)
pbrook624f7972008-05-31 16:11:38 +00005734 free_sigqueue(cpu_env, q);
bellard31e31b82003-02-18 22:55:36 +00005735}