blob: 9e6a4952a745396543bd7e0d0d42aa3a72123316 [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{
207 return sigprocmask(how, set, oldset);
208}
209
bellard9de5e442003-03-23 16:49:39 +0000210/* siginfo conversion */
211
Anthony Liguoric227f092009-10-01 16:12:16 -0500212static inline void host_to_target_siginfo_noswap(target_siginfo_t *tinfo,
bellard9de5e442003-03-23 16:49:39 +0000213 const siginfo_t *info)
bellard66fb9762003-03-23 01:06:05 +0000214{
Richard Hendersona05c6402012-09-15 11:34:20 -0700215 int sig = host_to_target_signal(info->si_signo);
bellard9de5e442003-03-23 16:49:39 +0000216 tinfo->si_signo = sig;
217 tinfo->si_errno = 0;
pbrookafd7cd92008-05-31 12:14:21 +0000218 tinfo->si_code = info->si_code;
Richard Hendersona05c6402012-09-15 11:34:20 -0700219
220 if (sig == TARGET_SIGILL || sig == TARGET_SIGFPE || sig == TARGET_SIGSEGV
221 || sig == TARGET_SIGBUS || sig == TARGET_SIGTRAP) {
222 /* Should never come here, but who knows. The information for
223 the target is irrelevant. */
bellard9de5e442003-03-23 16:49:39 +0000224 tinfo->_sifields._sigfault._addr = 0;
Richard Hendersona05c6402012-09-15 11:34:20 -0700225 } else if (sig == TARGET_SIGIO) {
226 tinfo->_sifields._sigpoll._band = info->si_band;
ths7f7f7c82007-07-12 11:02:46 +0000227 tinfo->_sifields._sigpoll._fd = info->si_fd;
Richard Hendersona05c6402012-09-15 11:34:20 -0700228 } else if (sig == TARGET_SIGCHLD) {
229 tinfo->_sifields._sigchld._pid = info->si_pid;
230 tinfo->_sifields._sigchld._uid = info->si_uid;
231 tinfo->_sifields._sigchld._status
232 = host_to_target_waitstatus(info->si_status);
233 tinfo->_sifields._sigchld._utime = info->si_utime;
234 tinfo->_sifields._sigchld._stime = info->si_stime;
bellard9de5e442003-03-23 16:49:39 +0000235 } else if (sig >= TARGET_SIGRTMIN) {
236 tinfo->_sifields._rt._pid = info->si_pid;
237 tinfo->_sifields._rt._uid = info->si_uid;
238 /* XXX: potential problem if 64 bit */
Richard Hendersona05c6402012-09-15 11:34:20 -0700239 tinfo->_sifields._rt._sigval.sival_ptr
240 = (abi_ulong)(unsigned long)info->si_value.sival_ptr;
bellard9de5e442003-03-23 16:49:39 +0000241 }
bellard66fb9762003-03-23 01:06:05 +0000242}
243
Anthony Liguoric227f092009-10-01 16:12:16 -0500244static void tswap_siginfo(target_siginfo_t *tinfo,
245 const target_siginfo_t *info)
bellard9de5e442003-03-23 16:49:39 +0000246{
Richard Hendersona05c6402012-09-15 11:34:20 -0700247 int sig = info->si_signo;
bellard9de5e442003-03-23 16:49:39 +0000248 tinfo->si_signo = tswap32(sig);
249 tinfo->si_errno = tswap32(info->si_errno);
250 tinfo->si_code = tswap32(info->si_code);
Richard Hendersona05c6402012-09-15 11:34:20 -0700251
252 if (sig == TARGET_SIGILL || sig == TARGET_SIGFPE || sig == TARGET_SIGSEGV
253 || sig == TARGET_SIGBUS || sig == TARGET_SIGTRAP) {
254 tinfo->_sifields._sigfault._addr
255 = tswapal(info->_sifields._sigfault._addr);
256 } else if (sig == TARGET_SIGIO) {
257 tinfo->_sifields._sigpoll._band
258 = tswap32(info->_sifields._sigpoll._band);
259 tinfo->_sifields._sigpoll._fd = tswap32(info->_sifields._sigpoll._fd);
260 } else if (sig == TARGET_SIGCHLD) {
261 tinfo->_sifields._sigchld._pid
262 = tswap32(info->_sifields._sigchld._pid);
263 tinfo->_sifields._sigchld._uid
264 = tswap32(info->_sifields._sigchld._uid);
265 tinfo->_sifields._sigchld._status
266 = tswap32(info->_sifields._sigchld._status);
267 tinfo->_sifields._sigchld._utime
268 = tswapal(info->_sifields._sigchld._utime);
269 tinfo->_sifields._sigchld._stime
270 = tswapal(info->_sifields._sigchld._stime);
bellard9de5e442003-03-23 16:49:39 +0000271 } else if (sig >= TARGET_SIGRTMIN) {
272 tinfo->_sifields._rt._pid = tswap32(info->_sifields._rt._pid);
273 tinfo->_sifields._rt._uid = tswap32(info->_sifields._rt._uid);
Richard Hendersona05c6402012-09-15 11:34:20 -0700274 tinfo->_sifields._rt._sigval.sival_ptr
275 = tswapal(info->_sifields._rt._sigval.sival_ptr);
bellard9de5e442003-03-23 16:49:39 +0000276 }
277}
278
279
Anthony Liguoric227f092009-10-01 16:12:16 -0500280void host_to_target_siginfo(target_siginfo_t *tinfo, const siginfo_t *info)
bellard9de5e442003-03-23 16:49:39 +0000281{
282 host_to_target_siginfo_noswap(tinfo, info);
283 tswap_siginfo(tinfo, tinfo);
284}
285
286/* XXX: we support only POSIX RT signals are used. */
thsaa1f17c2007-07-11 22:48:58 +0000287/* XXX: find a solution for 64 bit (additional malloced data is needed) */
Anthony Liguoric227f092009-10-01 16:12:16 -0500288void target_to_host_siginfo(siginfo_t *info, const target_siginfo_t *tinfo)
bellard66fb9762003-03-23 01:06:05 +0000289{
290 info->si_signo = tswap32(tinfo->si_signo);
291 info->si_errno = tswap32(tinfo->si_errno);
292 info->si_code = tswap32(tinfo->si_code);
bellard9de5e442003-03-23 16:49:39 +0000293 info->si_pid = tswap32(tinfo->_sifields._rt._pid);
294 info->si_uid = tswap32(tinfo->_sifields._rt._uid);
ths5fafdf22007-09-16 21:08:06 +0000295 info->si_value.sival_ptr =
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200296 (void *)(long)tswapal(tinfo->_sifields._rt._sigval.sival_ptr);
bellard66fb9762003-03-23 01:06:05 +0000297}
298
aurel32ca587a82008-12-18 22:44:13 +0000299static int fatal_signal (int sig)
300{
301 switch (sig) {
302 case TARGET_SIGCHLD:
303 case TARGET_SIGURG:
304 case TARGET_SIGWINCH:
305 /* Ignored by default. */
306 return 0;
307 case TARGET_SIGCONT:
308 case TARGET_SIGSTOP:
309 case TARGET_SIGTSTP:
310 case TARGET_SIGTTIN:
311 case TARGET_SIGTTOU:
312 /* Job control signals. */
313 return 0;
314 default:
315 return 1;
316 }
317}
318
Mika Westerbergedf8e2a2009-04-07 09:57:11 +0300319/* returns 1 if given signal should dump core if not handled */
320static int core_dump_signal(int sig)
321{
322 switch (sig) {
323 case TARGET_SIGABRT:
324 case TARGET_SIGFPE:
325 case TARGET_SIGILL:
326 case TARGET_SIGQUIT:
327 case TARGET_SIGSEGV:
328 case TARGET_SIGTRAP:
329 case TARGET_SIGBUS:
330 return (1);
331 default:
332 return (0);
333 }
334}
335
bellard31e31b82003-02-18 22:55:36 +0000336void signal_init(void)
337{
338 struct sigaction act;
pbrook624f7972008-05-31 16:11:38 +0000339 struct sigaction oact;
bellard9e5f5282003-07-13 17:33:54 +0000340 int i, j;
pbrook624f7972008-05-31 16:11:38 +0000341 int host_sig;
bellard31e31b82003-02-18 22:55:36 +0000342
bellard9e5f5282003-07-13 17:33:54 +0000343 /* generate signal conversion tables */
Arnaud Patard3ca05582009-03-30 01:18:20 +0200344 for(i = 1; i < _NSIG; i++) {
bellard9e5f5282003-07-13 17:33:54 +0000345 if (host_to_target_signal_table[i] == 0)
346 host_to_target_signal_table[i] = i;
347 }
Arnaud Patard3ca05582009-03-30 01:18:20 +0200348 for(i = 1; i < _NSIG; i++) {
bellard9e5f5282003-07-13 17:33:54 +0000349 j = host_to_target_signal_table[i];
350 target_to_host_signal_table[j] = i;
351 }
ths3b46e622007-09-17 08:09:54 +0000352
bellard9de5e442003-03-23 16:49:39 +0000353 /* set all host signal handlers. ALL signals are blocked during
354 the handlers to serialize them. */
pbrook624f7972008-05-31 16:11:38 +0000355 memset(sigact_table, 0, sizeof(sigact_table));
356
bellard9de5e442003-03-23 16:49:39 +0000357 sigfillset(&act.sa_mask);
bellard31e31b82003-02-18 22:55:36 +0000358 act.sa_flags = SA_SIGINFO;
359 act.sa_sigaction = host_signal_handler;
pbrook624f7972008-05-31 16:11:38 +0000360 for(i = 1; i <= TARGET_NSIG; i++) {
361 host_sig = target_to_host_signal(i);
362 sigaction(host_sig, NULL, &oact);
363 if (oact.sa_sigaction == (void *)SIG_IGN) {
364 sigact_table[i - 1]._sa_handler = TARGET_SIG_IGN;
365 } else if (oact.sa_sigaction == (void *)SIG_DFL) {
366 sigact_table[i - 1]._sa_handler = TARGET_SIG_DFL;
367 }
368 /* If there's already a handler installed then something has
369 gone horribly wrong, so don't even try to handle that case. */
aurel32ca587a82008-12-18 22:44:13 +0000370 /* Install some handlers for our own use. We need at least
371 SIGSEGV and SIGBUS, to detect exceptions. We can not just
372 trap all signals because it affects syscall interrupt
373 behavior. But do trap all default-fatal signals. */
374 if (fatal_signal (i))
pbrook624f7972008-05-31 16:11:38 +0000375 sigaction(host_sig, &act, NULL);
bellard31e31b82003-02-18 22:55:36 +0000376 }
bellard31e31b82003-02-18 22:55:36 +0000377}
378
bellard66fb9762003-03-23 01:06:05 +0000379/* signal queue handling */
380
Andreas Färber9349b4f2012-03-14 01:38:32 +0100381static inline struct sigqueue *alloc_sigqueue(CPUArchState *env)
bellard66fb9762003-03-23 01:06:05 +0000382{
Andreas Färber0429a972013-08-26 18:14:44 +0200383 CPUState *cpu = ENV_GET_CPU(env);
384 TaskState *ts = cpu->opaque;
pbrook624f7972008-05-31 16:11:38 +0000385 struct sigqueue *q = ts->first_free;
bellard66fb9762003-03-23 01:06:05 +0000386 if (!q)
387 return NULL;
pbrook624f7972008-05-31 16:11:38 +0000388 ts->first_free = q->next;
bellard66fb9762003-03-23 01:06:05 +0000389 return q;
390}
391
Andreas Färber9349b4f2012-03-14 01:38:32 +0100392static inline void free_sigqueue(CPUArchState *env, struct sigqueue *q)
bellard66fb9762003-03-23 01:06:05 +0000393{
Andreas Färber0429a972013-08-26 18:14:44 +0200394 CPUState *cpu = ENV_GET_CPU(env);
395 TaskState *ts = cpu->opaque;
396
pbrook624f7972008-05-31 16:11:38 +0000397 q->next = ts->first_free;
398 ts->first_free = q;
bellard66fb9762003-03-23 01:06:05 +0000399}
400
bellard9de5e442003-03-23 16:49:39 +0000401/* abort execution with signal */
Riku Voipio66393fb2009-12-04 15:16:32 +0200402static void QEMU_NORETURN force_sig(int target_sig)
bellard66fb9762003-03-23 01:06:05 +0000403{
Andreas Färber0429a972013-08-26 18:14:44 +0200404 CPUState *cpu = thread_cpu;
405 CPUArchState *env = cpu->env_ptr;
406 TaskState *ts = (TaskState *)cpu->opaque;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +0300407 int host_sig, core_dumped = 0;
aurel32603e4fd2009-04-15 16:18:38 +0000408 struct sigaction act;
Riku Voipio66393fb2009-12-04 15:16:32 +0200409 host_sig = target_to_host_signal(target_sig);
Andreas Färbera2247f82013-06-09 19:47:04 +0200410 gdb_signalled(env, target_sig);
aurel32603e4fd2009-04-15 16:18:38 +0000411
Mika Westerbergedf8e2a2009-04-07 09:57:11 +0300412 /* dump core if supported by target binary format */
Riku Voipio66393fb2009-12-04 15:16:32 +0200413 if (core_dump_signal(target_sig) && (ts->bprm->core_dump != NULL)) {
Mika Westerbergedf8e2a2009-04-07 09:57:11 +0300414 stop_all_tasks();
415 core_dumped =
Andreas Färbera2247f82013-06-09 19:47:04 +0200416 ((*ts->bprm->core_dump)(target_sig, env) == 0);
Mika Westerbergedf8e2a2009-04-07 09:57:11 +0300417 }
418 if (core_dumped) {
419 /* we already dumped the core of target process, we don't want
420 * a coredump of qemu itself */
421 struct rlimit nodump;
422 getrlimit(RLIMIT_CORE, &nodump);
423 nodump.rlim_cur=0;
424 setrlimit(RLIMIT_CORE, &nodump);
425 (void) fprintf(stderr, "qemu: uncaught target signal %d (%s) - %s\n",
Riku Voipio66393fb2009-12-04 15:16:32 +0200426 target_sig, strsignal(host_sig), "core dumped" );
Mika Westerbergedf8e2a2009-04-07 09:57:11 +0300427 }
428
Stefan Weil0c587512011-04-28 17:20:32 +0200429 /* The proper exit code for dying from an uncaught signal is
aurel32603e4fd2009-04-15 16:18:38 +0000430 * -<signal>. The kernel doesn't allow exit() or _exit() to pass
431 * a negative value. To get the proper exit code we need to
432 * actually die from an uncaught signal. Here the default signal
433 * handler is installed, we send ourself a signal and we wait for
434 * it to arrive. */
435 sigfillset(&act.sa_mask);
436 act.sa_handler = SIG_DFL;
Peter Maydell3a5d30b2014-02-17 18:55:32 +0000437 act.sa_flags = 0;
aurel32603e4fd2009-04-15 16:18:38 +0000438 sigaction(host_sig, &act, NULL);
439
440 /* For some reason raise(host_sig) doesn't send the signal when
441 * statically linked on x86-64. */
442 kill(getpid(), host_sig);
443
444 /* Make sure the signal isn't masked (just reuse the mask inside
445 of act) */
446 sigdelset(&act.sa_mask, host_sig);
447 sigsuspend(&act.sa_mask);
448
449 /* unreachable */
Blue Swirla6c6f762010-03-13 14:18:50 +0000450 abort();
bellard66fb9762003-03-23 01:06:05 +0000451}
452
bellard9de5e442003-03-23 16:49:39 +0000453/* queue a signal so that it will be send to the virtual CPU as soon
454 as possible */
Andreas Färber9349b4f2012-03-14 01:38:32 +0100455int queue_signal(CPUArchState *env, int sig, target_siginfo_t *info)
bellard31e31b82003-02-18 22:55:36 +0000456{
Andreas Färber0429a972013-08-26 18:14:44 +0200457 CPUState *cpu = ENV_GET_CPU(env);
458 TaskState *ts = cpu->opaque;
pbrook624f7972008-05-31 16:11:38 +0000459 struct emulated_sigtable *k;
bellard9de5e442003-03-23 16:49:39 +0000460 struct sigqueue *q, **pq;
blueswir1992f48a2007-10-14 16:27:31 +0000461 abi_ulong handler;
aurel32ca587a82008-12-18 22:44:13 +0000462 int queue;
bellard66fb9762003-03-23 01:06:05 +0000463
bellard9de5e442003-03-23 16:49:39 +0000464#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000465 fprintf(stderr, "queue_signal: sig=%d\n",
bellard9de5e442003-03-23 16:49:39 +0000466 sig);
bellard66fb9762003-03-23 01:06:05 +0000467#endif
pbrook624f7972008-05-31 16:11:38 +0000468 k = &ts->sigtab[sig - 1];
aurel32ca587a82008-12-18 22:44:13 +0000469 queue = gdb_queuesig ();
pbrook624f7972008-05-31 16:11:38 +0000470 handler = sigact_table[sig - 1]._sa_handler;
aurel32ca587a82008-12-18 22:44:13 +0000471 if (!queue && handler == TARGET_SIG_DFL) {
ths60b19692008-11-27 15:47:15 +0000472 if (sig == TARGET_SIGTSTP || sig == TARGET_SIGTTIN || sig == TARGET_SIGTTOU) {
473 kill(getpid(),SIGSTOP);
474 return 0;
475 } else
bellard66fb9762003-03-23 01:06:05 +0000476 /* default handler : ignore some signal. The other are fatal */
ths5fafdf22007-09-16 21:08:06 +0000477 if (sig != TARGET_SIGCHLD &&
478 sig != TARGET_SIGURG &&
ths60b19692008-11-27 15:47:15 +0000479 sig != TARGET_SIGWINCH &&
480 sig != TARGET_SIGCONT) {
bellard66fb9762003-03-23 01:06:05 +0000481 force_sig(sig);
bellard9de5e442003-03-23 16:49:39 +0000482 } else {
483 return 0; /* indicate ignored */
bellard66fb9762003-03-23 01:06:05 +0000484 }
aurel32ca587a82008-12-18 22:44:13 +0000485 } else if (!queue && handler == TARGET_SIG_IGN) {
bellard66fb9762003-03-23 01:06:05 +0000486 /* ignore signal */
bellard9de5e442003-03-23 16:49:39 +0000487 return 0;
aurel32ca587a82008-12-18 22:44:13 +0000488 } else if (!queue && handler == TARGET_SIG_ERR) {
bellard66fb9762003-03-23 01:06:05 +0000489 force_sig(sig);
490 } else {
bellard9de5e442003-03-23 16:49:39 +0000491 pq = &k->first;
492 if (sig < TARGET_SIGRTMIN) {
493 /* if non real time signal, we queue exactly one signal */
494 if (!k->pending)
495 q = &k->info;
496 else
497 return 0;
498 } else {
499 if (!k->pending) {
500 /* first signal */
501 q = &k->info;
502 } else {
pbrook624f7972008-05-31 16:11:38 +0000503 q = alloc_sigqueue(env);
bellard9de5e442003-03-23 16:49:39 +0000504 if (!q)
505 return -EAGAIN;
506 while (*pq != NULL)
507 pq = &(*pq)->next;
508 }
509 }
510 *pq = q;
511 q->info = *info;
512 q->next = NULL;
513 k->pending = 1;
514 /* signal that a new signal is pending */
pbrook624f7972008-05-31 16:11:38 +0000515 ts->signal_pending = 1;
bellard9de5e442003-03-23 16:49:39 +0000516 return 1; /* indicates that the signal was queued */
517 }
518}
519
ths5fafdf22007-09-16 21:08:06 +0000520static void host_signal_handler(int host_signum, siginfo_t *info,
bellard9de5e442003-03-23 16:49:39 +0000521 void *puc)
522{
Andreas Färbera2247f82013-06-09 19:47:04 +0200523 CPUArchState *env = thread_cpu->env_ptr;
bellard9de5e442003-03-23 16:49:39 +0000524 int sig;
Anthony Liguoric227f092009-10-01 16:12:16 -0500525 target_siginfo_t tinfo;
bellard9de5e442003-03-23 16:49:39 +0000526
527 /* the CPU emulator uses some host signals to detect exceptions,
aurel32eaa449b2009-01-03 13:14:52 +0000528 we forward to it some signals */
aurel32ca587a82008-12-18 22:44:13 +0000529 if ((host_signum == SIGSEGV || host_signum == SIGBUS)
aurel32eaa449b2009-01-03 13:14:52 +0000530 && info->si_code > 0) {
bellardb346ff42003-06-15 20:05:50 +0000531 if (cpu_signal_handler(host_signum, info, puc))
bellard9de5e442003-03-23 16:49:39 +0000532 return;
533 }
534
535 /* get target signal number */
536 sig = host_to_target_signal(host_signum);
537 if (sig < 1 || sig > TARGET_NSIG)
538 return;
539#if defined(DEBUG_SIGNAL)
bellardbc8a22c2003-03-30 21:02:40 +0000540 fprintf(stderr, "qemu: got signal %d\n", sig);
bellard9de5e442003-03-23 16:49:39 +0000541#endif
542 host_to_target_siginfo_noswap(&tinfo, info);
Andreas Färbera2247f82013-06-09 19:47:04 +0200543 if (queue_signal(env, sig, &tinfo) == 1) {
bellard9de5e442003-03-23 16:49:39 +0000544 /* interrupt the virtual CPU as soon as possible */
Andreas Färbera2247f82013-06-09 19:47:04 +0200545 cpu_exit(thread_cpu);
bellard66fb9762003-03-23 01:06:05 +0000546 }
bellard31e31b82003-02-18 22:55:36 +0000547}
548
ths0da46a62007-10-20 20:23:07 +0000549/* do_sigaltstack() returns target values and errnos. */
bellard579a97f2007-11-11 14:26:47 +0000550/* compare linux/kernel/signal.c:do_sigaltstack() */
551abi_long do_sigaltstack(abi_ulong uss_addr, abi_ulong uoss_addr, abi_ulong sp)
thsa04e1342007-09-27 13:57:58 +0000552{
553 int ret;
554 struct target_sigaltstack oss;
555
556 /* XXX: test errors */
bellard579a97f2007-11-11 14:26:47 +0000557 if(uoss_addr)
thsa04e1342007-09-27 13:57:58 +0000558 {
559 __put_user(target_sigaltstack_used.ss_sp, &oss.ss_sp);
560 __put_user(target_sigaltstack_used.ss_size, &oss.ss_size);
561 __put_user(sas_ss_flags(sp), &oss.ss_flags);
562 }
563
bellard579a97f2007-11-11 14:26:47 +0000564 if(uss_addr)
thsa04e1342007-09-27 13:57:58 +0000565 {
bellard579a97f2007-11-11 14:26:47 +0000566 struct target_sigaltstack *uss;
567 struct target_sigaltstack ss;
thsa04e1342007-09-27 13:57:58 +0000568
ths0da46a62007-10-20 20:23:07 +0000569 ret = -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +0000570 if (!lock_user_struct(VERIFY_READ, uss, uss_addr, 1)
thsa04e1342007-09-27 13:57:58 +0000571 || __get_user(ss.ss_sp, &uss->ss_sp)
572 || __get_user(ss.ss_size, &uss->ss_size)
573 || __get_user(ss.ss_flags, &uss->ss_flags))
574 goto out;
bellard579a97f2007-11-11 14:26:47 +0000575 unlock_user_struct(uss, uss_addr, 0);
thsa04e1342007-09-27 13:57:58 +0000576
ths0da46a62007-10-20 20:23:07 +0000577 ret = -TARGET_EPERM;
thsa04e1342007-09-27 13:57:58 +0000578 if (on_sig_stack(sp))
579 goto out;
580
ths0da46a62007-10-20 20:23:07 +0000581 ret = -TARGET_EINVAL;
thsa04e1342007-09-27 13:57:58 +0000582 if (ss.ss_flags != TARGET_SS_DISABLE
583 && ss.ss_flags != TARGET_SS_ONSTACK
584 && ss.ss_flags != 0)
585 goto out;
586
587 if (ss.ss_flags == TARGET_SS_DISABLE) {
588 ss.ss_size = 0;
589 ss.ss_sp = 0;
590 } else {
ths0da46a62007-10-20 20:23:07 +0000591 ret = -TARGET_ENOMEM;
thsa04e1342007-09-27 13:57:58 +0000592 if (ss.ss_size < MINSIGSTKSZ)
593 goto out;
594 }
595
596 target_sigaltstack_used.ss_sp = ss.ss_sp;
597 target_sigaltstack_used.ss_size = ss.ss_size;
598 }
599
bellard579a97f2007-11-11 14:26:47 +0000600 if (uoss_addr) {
ths0da46a62007-10-20 20:23:07 +0000601 ret = -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +0000602 if (copy_to_user(uoss_addr, &oss, sizeof(oss)))
thsa04e1342007-09-27 13:57:58 +0000603 goto out;
thsa04e1342007-09-27 13:57:58 +0000604 }
605
606 ret = 0;
607out:
608 return ret;
609}
610
ths0da46a62007-10-20 20:23:07 +0000611/* do_sigaction() return host values and errnos */
bellard66fb9762003-03-23 01:06:05 +0000612int do_sigaction(int sig, const struct target_sigaction *act,
613 struct target_sigaction *oact)
bellard31e31b82003-02-18 22:55:36 +0000614{
pbrook624f7972008-05-31 16:11:38 +0000615 struct target_sigaction *k;
bellard773b93e2004-01-04 17:15:59 +0000616 struct sigaction act1;
617 int host_sig;
ths0da46a62007-10-20 20:23:07 +0000618 int ret = 0;
bellard31e31b82003-02-18 22:55:36 +0000619
ths2a913eb2008-11-27 15:46:25 +0000620 if (sig < 1 || sig > TARGET_NSIG || sig == TARGET_SIGKILL || sig == TARGET_SIGSTOP)
bellard66fb9762003-03-23 01:06:05 +0000621 return -EINVAL;
622 k = &sigact_table[sig - 1];
bellard773b93e2004-01-04 17:15:59 +0000623#if defined(DEBUG_SIGNAL)
Blue Swirl0bf9e312009-07-20 17:19:25 +0000624 fprintf(stderr, "sigaction sig=%d act=0x%p, oact=0x%p\n",
625 sig, act, oact);
bellard66fb9762003-03-23 01:06:05 +0000626#endif
627 if (oact) {
Richard Hendersond2565872013-01-04 16:39:32 -0800628 __put_user(k->_sa_handler, &oact->_sa_handler);
629 __put_user(k->sa_flags, &oact->sa_flags);
ths388bb212007-05-13 13:58:00 +0000630#if !defined(TARGET_MIPS)
Richard Hendersond2565872013-01-04 16:39:32 -0800631 __put_user(k->sa_restorer, &oact->sa_restorer);
ths388bb212007-05-13 13:58:00 +0000632#endif
Richard Hendersond2565872013-01-04 16:39:32 -0800633 /* Not swapped. */
pbrook624f7972008-05-31 16:11:38 +0000634 oact->sa_mask = k->sa_mask;
bellard66fb9762003-03-23 01:06:05 +0000635 }
636 if (act) {
pbrook624f7972008-05-31 16:11:38 +0000637 /* FIXME: This is not threadsafe. */
Richard Hendersond2565872013-01-04 16:39:32 -0800638 __get_user(k->_sa_handler, &act->_sa_handler);
639 __get_user(k->sa_flags, &act->sa_flags);
ths388bb212007-05-13 13:58:00 +0000640#if !defined(TARGET_MIPS)
Richard Hendersond2565872013-01-04 16:39:32 -0800641 __get_user(k->sa_restorer, &act->sa_restorer);
ths388bb212007-05-13 13:58:00 +0000642#endif
Richard Hendersond2565872013-01-04 16:39:32 -0800643 /* To be swapped in target_to_host_sigset. */
pbrook624f7972008-05-31 16:11:38 +0000644 k->sa_mask = act->sa_mask;
bellard773b93e2004-01-04 17:15:59 +0000645
646 /* we update the host linux signal state */
647 host_sig = target_to_host_signal(sig);
648 if (host_sig != SIGSEGV && host_sig != SIGBUS) {
649 sigfillset(&act1.sa_mask);
650 act1.sa_flags = SA_SIGINFO;
pbrook624f7972008-05-31 16:11:38 +0000651 if (k->sa_flags & TARGET_SA_RESTART)
bellard773b93e2004-01-04 17:15:59 +0000652 act1.sa_flags |= SA_RESTART;
653 /* NOTE: it is important to update the host kernel signal
654 ignore state to avoid getting unexpected interrupted
655 syscalls */
pbrook624f7972008-05-31 16:11:38 +0000656 if (k->_sa_handler == TARGET_SIG_IGN) {
bellard773b93e2004-01-04 17:15:59 +0000657 act1.sa_sigaction = (void *)SIG_IGN;
pbrook624f7972008-05-31 16:11:38 +0000658 } else if (k->_sa_handler == TARGET_SIG_DFL) {
aurel32ca587a82008-12-18 22:44:13 +0000659 if (fatal_signal (sig))
660 act1.sa_sigaction = host_signal_handler;
661 else
662 act1.sa_sigaction = (void *)SIG_DFL;
bellard773b93e2004-01-04 17:15:59 +0000663 } else {
664 act1.sa_sigaction = host_signal_handler;
665 }
ths0da46a62007-10-20 20:23:07 +0000666 ret = sigaction(host_sig, &act1, NULL);
bellard773b93e2004-01-04 17:15:59 +0000667 }
bellard66fb9762003-03-23 01:06:05 +0000668 }
ths0da46a62007-10-20 20:23:07 +0000669 return ret;
bellard66fb9762003-03-23 01:06:05 +0000670}
bellard31e31b82003-02-18 22:55:36 +0000671
Anthony Liguoric227f092009-10-01 16:12:16 -0500672static inline int copy_siginfo_to_user(target_siginfo_t *tinfo,
673 const target_siginfo_t *info)
bellard43fff232003-07-09 19:31:39 +0000674{
675 tswap_siginfo(tinfo, info);
676 return 0;
677}
678
thsc3b5bc82007-12-02 06:31:25 +0000679static inline int current_exec_domain_sig(int sig)
680{
681 return /* current->exec_domain && current->exec_domain->signal_invmap
682 && sig < 32 ? current->exec_domain->signal_invmap[sig] : */ sig;
683}
684
bellard459a4012007-11-11 19:45:10 +0000685#if defined(TARGET_I386) && TARGET_ABI_BITS == 32
bellard66fb9762003-03-23 01:06:05 +0000686
687/* from the Linux kernel */
688
689struct target_fpreg {
690 uint16_t significand[4];
691 uint16_t exponent;
692};
693
694struct target_fpxreg {
695 uint16_t significand[4];
696 uint16_t exponent;
697 uint16_t padding[3];
698};
699
700struct target_xmmreg {
blueswir1992f48a2007-10-14 16:27:31 +0000701 abi_ulong element[4];
bellard66fb9762003-03-23 01:06:05 +0000702};
703
704struct target_fpstate {
705 /* Regular FPU environment */
blueswir1992f48a2007-10-14 16:27:31 +0000706 abi_ulong cw;
707 abi_ulong sw;
708 abi_ulong tag;
709 abi_ulong ipoff;
710 abi_ulong cssel;
711 abi_ulong dataoff;
712 abi_ulong datasel;
bellard66fb9762003-03-23 01:06:05 +0000713 struct target_fpreg _st[8];
714 uint16_t status;
715 uint16_t magic; /* 0xffff = regular FPU data only */
716
717 /* FXSR FPU environment */
blueswir1992f48a2007-10-14 16:27:31 +0000718 abi_ulong _fxsr_env[6]; /* FXSR FPU env is ignored */
719 abi_ulong mxcsr;
720 abi_ulong reserved;
bellard66fb9762003-03-23 01:06:05 +0000721 struct target_fpxreg _fxsr_st[8]; /* FXSR FPU reg data is ignored */
722 struct target_xmmreg _xmm[8];
blueswir1992f48a2007-10-14 16:27:31 +0000723 abi_ulong padding[56];
bellard66fb9762003-03-23 01:06:05 +0000724};
725
726#define X86_FXSR_MAGIC 0x0000
727
728struct target_sigcontext {
729 uint16_t gs, __gsh;
730 uint16_t fs, __fsh;
731 uint16_t es, __esh;
732 uint16_t ds, __dsh;
blueswir1992f48a2007-10-14 16:27:31 +0000733 abi_ulong edi;
734 abi_ulong esi;
735 abi_ulong ebp;
736 abi_ulong esp;
737 abi_ulong ebx;
738 abi_ulong edx;
739 abi_ulong ecx;
740 abi_ulong eax;
741 abi_ulong trapno;
742 abi_ulong err;
743 abi_ulong eip;
bellard66fb9762003-03-23 01:06:05 +0000744 uint16_t cs, __csh;
blueswir1992f48a2007-10-14 16:27:31 +0000745 abi_ulong eflags;
746 abi_ulong esp_at_signal;
bellard66fb9762003-03-23 01:06:05 +0000747 uint16_t ss, __ssh;
blueswir1992f48a2007-10-14 16:27:31 +0000748 abi_ulong fpstate; /* pointer */
749 abi_ulong oldmask;
750 abi_ulong cr2;
bellard66fb9762003-03-23 01:06:05 +0000751};
752
bellard66fb9762003-03-23 01:06:05 +0000753struct target_ucontext {
blueswir1992f48a2007-10-14 16:27:31 +0000754 abi_ulong tuc_flags;
755 abi_ulong tuc_link;
Anthony Liguoric227f092009-10-01 16:12:16 -0500756 target_stack_t tuc_stack;
bellardb8076a72005-04-07 22:20:31 +0000757 struct target_sigcontext tuc_mcontext;
Anthony Liguoric227f092009-10-01 16:12:16 -0500758 target_sigset_t tuc_sigmask; /* mask last for extensibility */
bellard66fb9762003-03-23 01:06:05 +0000759};
760
761struct sigframe
762{
blueswir1992f48a2007-10-14 16:27:31 +0000763 abi_ulong pretcode;
bellard66fb9762003-03-23 01:06:05 +0000764 int sig;
765 struct target_sigcontext sc;
766 struct target_fpstate fpstate;
blueswir1992f48a2007-10-14 16:27:31 +0000767 abi_ulong extramask[TARGET_NSIG_WORDS-1];
bellard66fb9762003-03-23 01:06:05 +0000768 char retcode[8];
769};
770
771struct rt_sigframe
772{
blueswir1992f48a2007-10-14 16:27:31 +0000773 abi_ulong pretcode;
bellard66fb9762003-03-23 01:06:05 +0000774 int sig;
blueswir1992f48a2007-10-14 16:27:31 +0000775 abi_ulong pinfo;
776 abi_ulong puc;
bellard66fb9762003-03-23 01:06:05 +0000777 struct target_siginfo info;
778 struct target_ucontext uc;
779 struct target_fpstate fpstate;
780 char retcode[8];
781};
782
783/*
784 * Set up a signal frame.
785 */
786
bellard66fb9762003-03-23 01:06:05 +0000787/* XXX: save x87 state */
788static int
789setup_sigcontext(struct target_sigcontext *sc, struct target_fpstate *fpstate,
bellard28be6232007-11-11 22:23:38 +0000790 CPUX86State *env, abi_ulong mask, abi_ulong fpstate_addr)
bellard66fb9762003-03-23 01:06:05 +0000791{
Andreas Färber27103422013-08-26 08:31:06 +0200792 CPUState *cs = CPU(x86_env_get_cpu(env));
793 int err = 0;
794 uint16_t magic;
bellard66fb9762003-03-23 01:06:05 +0000795
bellard579a97f2007-11-11 14:26:47 +0000796 /* already locked in setup_frame() */
bellarda52c7572003-06-21 13:14:12 +0000797 err |= __put_user(env->segs[R_GS].selector, (unsigned int *)&sc->gs);
798 err |= __put_user(env->segs[R_FS].selector, (unsigned int *)&sc->fs);
799 err |= __put_user(env->segs[R_ES].selector, (unsigned int *)&sc->es);
800 err |= __put_user(env->segs[R_DS].selector, (unsigned int *)&sc->ds);
bellard66fb9762003-03-23 01:06:05 +0000801 err |= __put_user(env->regs[R_EDI], &sc->edi);
802 err |= __put_user(env->regs[R_ESI], &sc->esi);
803 err |= __put_user(env->regs[R_EBP], &sc->ebp);
804 err |= __put_user(env->regs[R_ESP], &sc->esp);
805 err |= __put_user(env->regs[R_EBX], &sc->ebx);
806 err |= __put_user(env->regs[R_EDX], &sc->edx);
807 err |= __put_user(env->regs[R_ECX], &sc->ecx);
808 err |= __put_user(env->regs[R_EAX], &sc->eax);
Andreas Färber27103422013-08-26 08:31:06 +0200809 err |= __put_user(cs->exception_index, &sc->trapno);
bellard66099dd2003-05-08 15:34:02 +0000810 err |= __put_user(env->error_code, &sc->err);
bellard66fb9762003-03-23 01:06:05 +0000811 err |= __put_user(env->eip, &sc->eip);
bellarda52c7572003-06-21 13:14:12 +0000812 err |= __put_user(env->segs[R_CS].selector, (unsigned int *)&sc->cs);
bellard66fb9762003-03-23 01:06:05 +0000813 err |= __put_user(env->eflags, &sc->eflags);
814 err |= __put_user(env->regs[R_ESP], &sc->esp_at_signal);
bellarda52c7572003-06-21 13:14:12 +0000815 err |= __put_user(env->segs[R_SS].selector, (unsigned int *)&sc->ss);
bellarded2dcdf2003-05-29 20:06:27 +0000816
bellard28be6232007-11-11 22:23:38 +0000817 cpu_x86_fsave(env, fpstate_addr, 1);
bellarded2dcdf2003-05-29 20:06:27 +0000818 fpstate->status = fpstate->sw;
bellard775b58d2007-11-11 16:22:17 +0000819 magic = 0xffff;
820 err |= __put_user(magic, &fpstate->magic);
bellard28be6232007-11-11 22:23:38 +0000821 err |= __put_user(fpstate_addr, &sc->fpstate);
bellarded2dcdf2003-05-29 20:06:27 +0000822
bellard66fb9762003-03-23 01:06:05 +0000823 /* non-iBCS2 extensions.. */
824 err |= __put_user(mask, &sc->oldmask);
bellarda52c7572003-06-21 13:14:12 +0000825 err |= __put_user(env->cr[2], &sc->cr2);
bellard66fb9762003-03-23 01:06:05 +0000826 return err;
827}
828
829/*
830 * Determine which stack to use..
831 */
832
bellard579a97f2007-11-11 14:26:47 +0000833static inline abi_ulong
pbrook624f7972008-05-31 16:11:38 +0000834get_sigframe(struct target_sigaction *ka, CPUX86State *env, size_t frame_size)
bellard66fb9762003-03-23 01:06:05 +0000835{
836 unsigned long esp;
837
838 /* Default to using normal stack */
839 esp = env->regs[R_ESP];
bellard66fb9762003-03-23 01:06:05 +0000840 /* This is the X/Open sanctioned signal stack switching. */
pbrook624f7972008-05-31 16:11:38 +0000841 if (ka->sa_flags & TARGET_SA_ONSTACK) {
thsa04e1342007-09-27 13:57:58 +0000842 if (sas_ss_flags(esp) == 0)
843 esp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
844 }
bellard66fb9762003-03-23 01:06:05 +0000845
846 /* This is the legacy signal stack switching. */
ths5fafdf22007-09-16 21:08:06 +0000847 else
bellarda52c7572003-06-21 13:14:12 +0000848 if ((env->segs[R_SS].selector & 0xffff) != __USER_DS &&
pbrook624f7972008-05-31 16:11:38 +0000849 !(ka->sa_flags & TARGET_SA_RESTORER) &&
850 ka->sa_restorer) {
851 esp = (unsigned long) ka->sa_restorer;
bellarda52c7572003-06-21 13:14:12 +0000852 }
bellard579a97f2007-11-11 14:26:47 +0000853 return (esp - frame_size) & -8ul;
bellard66fb9762003-03-23 01:06:05 +0000854}
855
bellard579a97f2007-11-11 14:26:47 +0000856/* compare linux/arch/i386/kernel/signal.c:setup_frame() */
pbrook624f7972008-05-31 16:11:38 +0000857static void setup_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -0500858 target_sigset_t *set, CPUX86State *env)
bellard66fb9762003-03-23 01:06:05 +0000859{
bellard579a97f2007-11-11 14:26:47 +0000860 abi_ulong frame_addr;
bellard66fb9762003-03-23 01:06:05 +0000861 struct sigframe *frame;
bellard92319442004-06-19 16:58:13 +0000862 int i, err = 0;
bellard66fb9762003-03-23 01:06:05 +0000863
bellard579a97f2007-11-11 14:26:47 +0000864 frame_addr = get_sigframe(ka, env, sizeof(*frame));
bellard66fb9762003-03-23 01:06:05 +0000865
bellard579a97f2007-11-11 14:26:47 +0000866 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
bellard66fb9762003-03-23 01:06:05 +0000867 goto give_sigsegv;
bellard579a97f2007-11-11 14:26:47 +0000868
thsc3b5bc82007-12-02 06:31:25 +0000869 err |= __put_user(current_exec_domain_sig(sig),
bellard66fb9762003-03-23 01:06:05 +0000870 &frame->sig);
871 if (err)
872 goto give_sigsegv;
873
bellard28be6232007-11-11 22:23:38 +0000874 setup_sigcontext(&frame->sc, &frame->fpstate, env, set->sig[0],
875 frame_addr + offsetof(struct sigframe, fpstate));
bellard66fb9762003-03-23 01:06:05 +0000876 if (err)
877 goto give_sigsegv;
878
bellard92319442004-06-19 16:58:13 +0000879 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
880 if (__put_user(set->sig[i], &frame->extramask[i - 1]))
881 goto give_sigsegv;
882 }
bellard66fb9762003-03-23 01:06:05 +0000883
884 /* Set up to return from userspace. If provided, use a stub
885 already in userspace. */
pbrook624f7972008-05-31 16:11:38 +0000886 if (ka->sa_flags & TARGET_SA_RESTORER) {
887 err |= __put_user(ka->sa_restorer, &frame->pretcode);
bellard66fb9762003-03-23 01:06:05 +0000888 } else {
bellard775b58d2007-11-11 16:22:17 +0000889 uint16_t val16;
bellard28be6232007-11-11 22:23:38 +0000890 abi_ulong retcode_addr;
891 retcode_addr = frame_addr + offsetof(struct sigframe, retcode);
892 err |= __put_user(retcode_addr, &frame->pretcode);
bellard66fb9762003-03-23 01:06:05 +0000893 /* This is popl %eax ; movl $,%eax ; int $0x80 */
bellard775b58d2007-11-11 16:22:17 +0000894 val16 = 0xb858;
895 err |= __put_user(val16, (uint16_t *)(frame->retcode+0));
bellard66fb9762003-03-23 01:06:05 +0000896 err |= __put_user(TARGET_NR_sigreturn, (int *)(frame->retcode+2));
bellard775b58d2007-11-11 16:22:17 +0000897 val16 = 0x80cd;
898 err |= __put_user(val16, (uint16_t *)(frame->retcode+6));
bellard66fb9762003-03-23 01:06:05 +0000899 }
900
901 if (err)
902 goto give_sigsegv;
903
904 /* Set up registers for signal handler */
bellard28be6232007-11-11 22:23:38 +0000905 env->regs[R_ESP] = frame_addr;
pbrook624f7972008-05-31 16:11:38 +0000906 env->eip = ka->_sa_handler;
bellard66fb9762003-03-23 01:06:05 +0000907
908 cpu_x86_load_seg(env, R_DS, __USER_DS);
909 cpu_x86_load_seg(env, R_ES, __USER_DS);
910 cpu_x86_load_seg(env, R_SS, __USER_DS);
911 cpu_x86_load_seg(env, R_CS, __USER_CS);
912 env->eflags &= ~TF_MASK;
913
bellard579a97f2007-11-11 14:26:47 +0000914 unlock_user_struct(frame, frame_addr, 1);
915
bellard66fb9762003-03-23 01:06:05 +0000916 return;
917
918give_sigsegv:
bellard579a97f2007-11-11 14:26:47 +0000919 unlock_user_struct(frame, frame_addr, 1);
bellard66fb9762003-03-23 01:06:05 +0000920 if (sig == TARGET_SIGSEGV)
pbrook624f7972008-05-31 16:11:38 +0000921 ka->_sa_handler = TARGET_SIG_DFL;
bellard66fb9762003-03-23 01:06:05 +0000922 force_sig(TARGET_SIGSEGV /* , current */);
923}
924
bellard579a97f2007-11-11 14:26:47 +0000925/* compare linux/arch/i386/kernel/signal.c:setup_rt_frame() */
pbrook624f7972008-05-31 16:11:38 +0000926static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -0500927 target_siginfo_t *info,
928 target_sigset_t *set, CPUX86State *env)
bellard66fb9762003-03-23 01:06:05 +0000929{
bellard28be6232007-11-11 22:23:38 +0000930 abi_ulong frame_addr, addr;
bellard66fb9762003-03-23 01:06:05 +0000931 struct rt_sigframe *frame;
bellard92319442004-06-19 16:58:13 +0000932 int i, err = 0;
bellard66fb9762003-03-23 01:06:05 +0000933
bellard579a97f2007-11-11 14:26:47 +0000934 frame_addr = get_sigframe(ka, env, sizeof(*frame));
bellard66fb9762003-03-23 01:06:05 +0000935
bellard579a97f2007-11-11 14:26:47 +0000936 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
bellard66fb9762003-03-23 01:06:05 +0000937 goto give_sigsegv;
bellard66fb9762003-03-23 01:06:05 +0000938
thsc3b5bc82007-12-02 06:31:25 +0000939 err |= __put_user(current_exec_domain_sig(sig),
bellard66fb9762003-03-23 01:06:05 +0000940 &frame->sig);
bellard28be6232007-11-11 22:23:38 +0000941 addr = frame_addr + offsetof(struct rt_sigframe, info);
942 err |= __put_user(addr, &frame->pinfo);
943 addr = frame_addr + offsetof(struct rt_sigframe, uc);
944 err |= __put_user(addr, &frame->puc);
bellard66fb9762003-03-23 01:06:05 +0000945 err |= copy_siginfo_to_user(&frame->info, info);
946 if (err)
947 goto give_sigsegv;
948
949 /* Create the ucontext. */
bellardb8076a72005-04-07 22:20:31 +0000950 err |= __put_user(0, &frame->uc.tuc_flags);
951 err |= __put_user(0, &frame->uc.tuc_link);
thsa04e1342007-09-27 13:57:58 +0000952 err |= __put_user(target_sigaltstack_used.ss_sp,
bellardb8076a72005-04-07 22:20:31 +0000953 &frame->uc.tuc_stack.ss_sp);
thsa04e1342007-09-27 13:57:58 +0000954 err |= __put_user(sas_ss_flags(get_sp_from_cpustate(env)),
bellardb8076a72005-04-07 22:20:31 +0000955 &frame->uc.tuc_stack.ss_flags);
thsa04e1342007-09-27 13:57:58 +0000956 err |= __put_user(target_sigaltstack_used.ss_size,
bellardb8076a72005-04-07 22:20:31 +0000957 &frame->uc.tuc_stack.ss_size);
958 err |= setup_sigcontext(&frame->uc.tuc_mcontext, &frame->fpstate,
bellard28be6232007-11-11 22:23:38 +0000959 env, set->sig[0],
960 frame_addr + offsetof(struct rt_sigframe, fpstate));
bellard92319442004-06-19 16:58:13 +0000961 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
bellardb8076a72005-04-07 22:20:31 +0000962 if (__put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]))
bellard92319442004-06-19 16:58:13 +0000963 goto give_sigsegv;
964 }
bellard66fb9762003-03-23 01:06:05 +0000965
966 /* Set up to return from userspace. If provided, use a stub
967 already in userspace. */
pbrook624f7972008-05-31 16:11:38 +0000968 if (ka->sa_flags & TARGET_SA_RESTORER) {
969 err |= __put_user(ka->sa_restorer, &frame->pretcode);
bellard66fb9762003-03-23 01:06:05 +0000970 } else {
bellard775b58d2007-11-11 16:22:17 +0000971 uint16_t val16;
bellard28be6232007-11-11 22:23:38 +0000972 addr = frame_addr + offsetof(struct rt_sigframe, retcode);
973 err |= __put_user(addr, &frame->pretcode);
bellard66fb9762003-03-23 01:06:05 +0000974 /* This is movl $,%eax ; int $0x80 */
bellard775b58d2007-11-11 16:22:17 +0000975 err |= __put_user(0xb8, (char *)(frame->retcode+0));
bellard66fb9762003-03-23 01:06:05 +0000976 err |= __put_user(TARGET_NR_rt_sigreturn, (int *)(frame->retcode+1));
bellard775b58d2007-11-11 16:22:17 +0000977 val16 = 0x80cd;
978 err |= __put_user(val16, (uint16_t *)(frame->retcode+5));
bellard66fb9762003-03-23 01:06:05 +0000979 }
980
981 if (err)
982 goto give_sigsegv;
983
984 /* Set up registers for signal handler */
bellard28be6232007-11-11 22:23:38 +0000985 env->regs[R_ESP] = frame_addr;
pbrook624f7972008-05-31 16:11:38 +0000986 env->eip = ka->_sa_handler;
bellard66fb9762003-03-23 01:06:05 +0000987
988 cpu_x86_load_seg(env, R_DS, __USER_DS);
989 cpu_x86_load_seg(env, R_ES, __USER_DS);
990 cpu_x86_load_seg(env, R_SS, __USER_DS);
991 cpu_x86_load_seg(env, R_CS, __USER_CS);
992 env->eflags &= ~TF_MASK;
993
bellard579a97f2007-11-11 14:26:47 +0000994 unlock_user_struct(frame, frame_addr, 1);
995
bellard66fb9762003-03-23 01:06:05 +0000996 return;
997
998give_sigsegv:
bellard579a97f2007-11-11 14:26:47 +0000999 unlock_user_struct(frame, frame_addr, 1);
bellard66fb9762003-03-23 01:06:05 +00001000 if (sig == TARGET_SIGSEGV)
pbrook624f7972008-05-31 16:11:38 +00001001 ka->_sa_handler = TARGET_SIG_DFL;
bellard66fb9762003-03-23 01:06:05 +00001002 force_sig(TARGET_SIGSEGV /* , current */);
1003}
1004
1005static int
1006restore_sigcontext(CPUX86State *env, struct target_sigcontext *sc, int *peax)
1007{
1008 unsigned int err = 0;
bellard28be6232007-11-11 22:23:38 +00001009 abi_ulong fpstate_addr;
1010 unsigned int tmpflags;
bellard66fb9762003-03-23 01:06:05 +00001011
bellard28be6232007-11-11 22:23:38 +00001012 cpu_x86_load_seg(env, R_GS, tswap16(sc->gs));
1013 cpu_x86_load_seg(env, R_FS, tswap16(sc->fs));
1014 cpu_x86_load_seg(env, R_ES, tswap16(sc->es));
1015 cpu_x86_load_seg(env, R_DS, tswap16(sc->ds));
bellard66fb9762003-03-23 01:06:05 +00001016
bellard28be6232007-11-11 22:23:38 +00001017 env->regs[R_EDI] = tswapl(sc->edi);
1018 env->regs[R_ESI] = tswapl(sc->esi);
1019 env->regs[R_EBP] = tswapl(sc->ebp);
1020 env->regs[R_ESP] = tswapl(sc->esp);
1021 env->regs[R_EBX] = tswapl(sc->ebx);
1022 env->regs[R_EDX] = tswapl(sc->edx);
1023 env->regs[R_ECX] = tswapl(sc->ecx);
1024 env->eip = tswapl(sc->eip);
bellard66fb9762003-03-23 01:06:05 +00001025
Mike McCormack9a826d72011-06-01 15:14:37 +09001026 cpu_x86_load_seg(env, R_CS, lduw_p(&sc->cs) | 3);
1027 cpu_x86_load_seg(env, R_SS, lduw_p(&sc->ss) | 3);
ths5fafdf22007-09-16 21:08:06 +00001028
bellard28be6232007-11-11 22:23:38 +00001029 tmpflags = tswapl(sc->eflags);
1030 env->eflags = (env->eflags & ~0x40DD5) | (tmpflags & 0x40DD5);
1031 // regs->orig_eax = -1; /* disable syscall checks */
1032
1033 fpstate_addr = tswapl(sc->fpstate);
1034 if (fpstate_addr != 0) {
1035 if (!access_ok(VERIFY_READ, fpstate_addr,
1036 sizeof(struct target_fpstate)))
1037 goto badframe;
1038 cpu_x86_frstor(env, fpstate_addr, 1);
bellard66fb9762003-03-23 01:06:05 +00001039 }
1040
bellard28be6232007-11-11 22:23:38 +00001041 *peax = tswapl(sc->eax);
bellard66fb9762003-03-23 01:06:05 +00001042 return err;
bellard66fb9762003-03-23 01:06:05 +00001043badframe:
1044 return 1;
bellard66fb9762003-03-23 01:06:05 +00001045}
1046
1047long do_sigreturn(CPUX86State *env)
1048{
bellard579a97f2007-11-11 14:26:47 +00001049 struct sigframe *frame;
1050 abi_ulong frame_addr = env->regs[R_ESP] - 8;
Anthony Liguoric227f092009-10-01 16:12:16 -05001051 target_sigset_t target_set;
bellard66fb9762003-03-23 01:06:05 +00001052 sigset_t set;
1053 int eax, i;
1054
bellard447db212003-05-10 15:10:36 +00001055#if defined(DEBUG_SIGNAL)
1056 fprintf(stderr, "do_sigreturn\n");
1057#endif
bellard579a97f2007-11-11 14:26:47 +00001058 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
1059 goto badframe;
bellard66fb9762003-03-23 01:06:05 +00001060 /* set blocked signals */
bellard92319442004-06-19 16:58:13 +00001061 if (__get_user(target_set.sig[0], &frame->sc.oldmask))
1062 goto badframe;
1063 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
1064 if (__get_user(target_set.sig[i], &frame->extramask[i - 1]))
1065 goto badframe;
1066 }
bellard66fb9762003-03-23 01:06:05 +00001067
bellard92319442004-06-19 16:58:13 +00001068 target_to_host_sigset_internal(&set, &target_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00001069 do_sigprocmask(SIG_SETMASK, &set, NULL);
ths3b46e622007-09-17 08:09:54 +00001070
bellard66fb9762003-03-23 01:06:05 +00001071 /* restore registers */
1072 if (restore_sigcontext(env, &frame->sc, &eax))
1073 goto badframe;
bellard579a97f2007-11-11 14:26:47 +00001074 unlock_user_struct(frame, frame_addr, 0);
bellard66fb9762003-03-23 01:06:05 +00001075 return eax;
1076
1077badframe:
bellard579a97f2007-11-11 14:26:47 +00001078 unlock_user_struct(frame, frame_addr, 0);
bellard66fb9762003-03-23 01:06:05 +00001079 force_sig(TARGET_SIGSEGV);
1080 return 0;
1081}
1082
1083long do_rt_sigreturn(CPUX86State *env)
1084{
bellard28be6232007-11-11 22:23:38 +00001085 abi_ulong frame_addr;
1086 struct rt_sigframe *frame;
bellard66fb9762003-03-23 01:06:05 +00001087 sigset_t set;
bellard66fb9762003-03-23 01:06:05 +00001088 int eax;
1089
bellard28be6232007-11-11 22:23:38 +00001090 frame_addr = env->regs[R_ESP] - 4;
1091 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
1092 goto badframe;
bellardb8076a72005-04-07 22:20:31 +00001093 target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
Alex Barcelo1c275922014-03-14 14:36:55 +00001094 do_sigprocmask(SIG_SETMASK, &set, NULL);
ths5fafdf22007-09-16 21:08:06 +00001095
bellardb8076a72005-04-07 22:20:31 +00001096 if (restore_sigcontext(env, &frame->uc.tuc_mcontext, &eax))
bellard66fb9762003-03-23 01:06:05 +00001097 goto badframe;
1098
bellard28be6232007-11-11 22:23:38 +00001099 if (do_sigaltstack(frame_addr + offsetof(struct rt_sigframe, uc.tuc_stack), 0,
1100 get_sp_from_cpustate(env)) == -EFAULT)
bellard66fb9762003-03-23 01:06:05 +00001101 goto badframe;
thsa04e1342007-09-27 13:57:58 +00001102
bellard28be6232007-11-11 22:23:38 +00001103 unlock_user_struct(frame, frame_addr, 0);
bellard66fb9762003-03-23 01:06:05 +00001104 return eax;
1105
1106badframe:
bellard28be6232007-11-11 22:23:38 +00001107 unlock_user_struct(frame, frame_addr, 0);
1108 force_sig(TARGET_SIGSEGV);
bellard66fb9762003-03-23 01:06:05 +00001109 return 0;
1110}
1111
Andreas Schwab1744aea2013-09-03 20:12:16 +01001112#elif defined(TARGET_AARCH64)
1113
1114struct target_sigcontext {
1115 uint64_t fault_address;
1116 /* AArch64 registers */
1117 uint64_t regs[31];
1118 uint64_t sp;
1119 uint64_t pc;
1120 uint64_t pstate;
1121 /* 4K reserved for FP/SIMD state and future expansion */
1122 char __reserved[4096] __attribute__((__aligned__(16)));
1123};
1124
1125struct target_ucontext {
1126 abi_ulong tuc_flags;
1127 abi_ulong tuc_link;
1128 target_stack_t tuc_stack;
1129 target_sigset_t tuc_sigmask;
1130 /* glibc uses a 1024-bit sigset_t */
1131 char __unused[1024 / 8 - sizeof(target_sigset_t)];
1132 /* last for future expansion */
1133 struct target_sigcontext tuc_mcontext;
1134};
1135
1136/*
1137 * Header to be used at the beginning of structures extending the user
1138 * context. Such structures must be placed after the rt_sigframe on the stack
1139 * and be 16-byte aligned. The last structure must be a dummy one with the
1140 * magic and size set to 0.
1141 */
1142struct target_aarch64_ctx {
1143 uint32_t magic;
1144 uint32_t size;
1145};
1146
1147#define TARGET_FPSIMD_MAGIC 0x46508001
1148
1149struct target_fpsimd_context {
1150 struct target_aarch64_ctx head;
1151 uint32_t fpsr;
1152 uint32_t fpcr;
1153 uint64_t vregs[32 * 2]; /* really uint128_t vregs[32] */
1154};
1155
1156/*
1157 * Auxiliary context saved in the sigcontext.__reserved array. Not exported to
1158 * user space as it will change with the addition of new context. User space
1159 * should check the magic/size information.
1160 */
1161struct target_aux_context {
1162 struct target_fpsimd_context fpsimd;
1163 /* additional context to be added before "end" */
1164 struct target_aarch64_ctx end;
1165};
1166
1167struct target_rt_sigframe {
1168 struct target_siginfo info;
1169 struct target_ucontext uc;
1170 uint64_t fp;
1171 uint64_t lr;
1172 uint32_t tramp[2];
1173};
1174
1175static int target_setup_sigframe(struct target_rt_sigframe *sf,
1176 CPUARMState *env, target_sigset_t *set)
1177{
1178 int i;
1179 struct target_aux_context *aux =
1180 (struct target_aux_context *)sf->uc.tuc_mcontext.__reserved;
1181
1182 /* set up the stack frame for unwinding */
1183 __put_user(env->xregs[29], &sf->fp);
1184 __put_user(env->xregs[30], &sf->lr);
1185
1186 for (i = 0; i < 31; i++) {
1187 __put_user(env->xregs[i], &sf->uc.tuc_mcontext.regs[i]);
1188 }
1189 __put_user(env->xregs[31], &sf->uc.tuc_mcontext.sp);
1190 __put_user(env->pc, &sf->uc.tuc_mcontext.pc);
Peter Maydelld3563122013-12-17 19:42:30 +00001191 __put_user(pstate_read(env), &sf->uc.tuc_mcontext.pstate);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001192
1193 __put_user(/*current->thread.fault_address*/ 0,
1194 &sf->uc.tuc_mcontext.fault_address);
1195
1196 for (i = 0; i < TARGET_NSIG_WORDS; i++) {
1197 __put_user(set->sig[i], &sf->uc.tuc_sigmask.sig[i]);
1198 }
1199
1200 for (i = 0; i < 32; i++) {
1201#ifdef TARGET_WORDS_BIGENDIAN
1202 __put_user(env->vfp.regs[i * 2], &aux->fpsimd.vregs[i * 2 + 1]);
1203 __put_user(env->vfp.regs[i * 2 + 1], &aux->fpsimd.vregs[i * 2]);
1204#else
1205 __put_user(env->vfp.regs[i * 2], &aux->fpsimd.vregs[i * 2]);
1206 __put_user(env->vfp.regs[i * 2 + 1], &aux->fpsimd.vregs[i * 2 + 1]);
1207#endif
1208 }
Will Newtone0ee1382014-01-04 22:15:48 +00001209 __put_user(vfp_get_fpsr(env), &aux->fpsimd.fpsr);
1210 __put_user(vfp_get_fpcr(env), &aux->fpsimd.fpcr);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001211 __put_user(TARGET_FPSIMD_MAGIC, &aux->fpsimd.head.magic);
1212 __put_user(sizeof(struct target_fpsimd_context),
1213 &aux->fpsimd.head.size);
1214
1215 /* set the "end" magic */
1216 __put_user(0, &aux->end.magic);
1217 __put_user(0, &aux->end.size);
1218
1219 return 0;
1220}
1221
1222static int target_restore_sigframe(CPUARMState *env,
1223 struct target_rt_sigframe *sf)
1224{
1225 sigset_t set;
1226 int i;
1227 struct target_aux_context *aux =
1228 (struct target_aux_context *)sf->uc.tuc_mcontext.__reserved;
Will Newtone0ee1382014-01-04 22:15:48 +00001229 uint32_t magic, size, fpsr, fpcr;
Peter Maydelld3563122013-12-17 19:42:30 +00001230 uint64_t pstate;
Andreas Schwab1744aea2013-09-03 20:12:16 +01001231
1232 target_to_host_sigset(&set, &sf->uc.tuc_sigmask);
Alex Barcelo1c275922014-03-14 14:36:55 +00001233 do_sigprocmask(SIG_SETMASK, &set, NULL);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001234
1235 for (i = 0; i < 31; i++) {
1236 __get_user(env->xregs[i], &sf->uc.tuc_mcontext.regs[i]);
1237 }
1238
1239 __get_user(env->xregs[31], &sf->uc.tuc_mcontext.sp);
1240 __get_user(env->pc, &sf->uc.tuc_mcontext.pc);
Peter Maydelld3563122013-12-17 19:42:30 +00001241 __get_user(pstate, &sf->uc.tuc_mcontext.pstate);
1242 pstate_write(env, pstate);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001243
1244 __get_user(magic, &aux->fpsimd.head.magic);
1245 __get_user(size, &aux->fpsimd.head.size);
1246
1247 if (magic != TARGET_FPSIMD_MAGIC
1248 || size != sizeof(struct target_fpsimd_context)) {
1249 return 1;
1250 }
1251
Peter Maydell4cf23482014-03-02 19:36:38 +00001252 for (i = 0; i < 32; i++) {
1253#ifdef TARGET_WORDS_BIGENDIAN
1254 __get_user(env->vfp.regs[i * 2], &aux->fpsimd.vregs[i * 2 + 1]);
1255 __get_user(env->vfp.regs[i * 2 + 1], &aux->fpsimd.vregs[i * 2]);
1256#else
1257 __get_user(env->vfp.regs[i * 2], &aux->fpsimd.vregs[i * 2]);
1258 __get_user(env->vfp.regs[i * 2 + 1], &aux->fpsimd.vregs[i * 2 + 1]);
1259#endif
Andreas Schwab1744aea2013-09-03 20:12:16 +01001260 }
Will Newtone0ee1382014-01-04 22:15:48 +00001261 __get_user(fpsr, &aux->fpsimd.fpsr);
1262 vfp_set_fpsr(env, fpsr);
1263 __get_user(fpcr, &aux->fpsimd.fpcr);
1264 vfp_set_fpcr(env, fpcr);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001265
1266 return 0;
1267}
1268
1269static abi_ulong get_sigframe(struct target_sigaction *ka, CPUARMState *env)
1270{
1271 abi_ulong sp;
1272
1273 sp = env->xregs[31];
1274
1275 /*
1276 * This is the X/Open sanctioned signal stack switching.
1277 */
1278 if ((ka->sa_flags & SA_ONSTACK) && !sas_ss_flags(sp)) {
1279 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
1280 }
1281
1282 sp = (sp - sizeof(struct target_rt_sigframe)) & ~15;
1283
1284 return sp;
1285}
1286
1287static void target_setup_frame(int usig, struct target_sigaction *ka,
1288 target_siginfo_t *info, target_sigset_t *set,
1289 CPUARMState *env)
1290{
1291 struct target_rt_sigframe *frame;
Michael Matz8a3ae912014-03-02 19:36:39 +00001292 abi_ulong frame_addr, return_addr;
Andreas Schwab1744aea2013-09-03 20:12:16 +01001293
1294 frame_addr = get_sigframe(ka, env);
1295 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
1296 goto give_sigsegv;
1297 }
1298
1299 __put_user(0, &frame->uc.tuc_flags);
1300 __put_user(0, &frame->uc.tuc_link);
1301
1302 __put_user(target_sigaltstack_used.ss_sp,
1303 &frame->uc.tuc_stack.ss_sp);
1304 __put_user(sas_ss_flags(env->xregs[31]),
1305 &frame->uc.tuc_stack.ss_flags);
1306 __put_user(target_sigaltstack_used.ss_size,
1307 &frame->uc.tuc_stack.ss_size);
1308 target_setup_sigframe(frame, env, set);
Michael Matz8a3ae912014-03-02 19:36:39 +00001309 if (ka->sa_flags & TARGET_SA_RESTORER) {
1310 return_addr = ka->sa_restorer;
1311 } else {
1312 /* mov x8,#__NR_rt_sigreturn; svc #0 */
1313 __put_user(0xd2801168, &frame->tramp[0]);
1314 __put_user(0xd4000001, &frame->tramp[1]);
1315 return_addr = frame_addr + offsetof(struct target_rt_sigframe, tramp);
1316 }
Andreas Schwab1744aea2013-09-03 20:12:16 +01001317 env->xregs[0] = usig;
1318 env->xregs[31] = frame_addr;
1319 env->xregs[29] = env->xregs[31] + offsetof(struct target_rt_sigframe, fp);
1320 env->pc = ka->_sa_handler;
Michael Matz8a3ae912014-03-02 19:36:39 +00001321 env->xregs[30] = return_addr;
Andreas Schwab1744aea2013-09-03 20:12:16 +01001322 if (info) {
1323 if (copy_siginfo_to_user(&frame->info, info)) {
1324 goto give_sigsegv;
1325 }
1326 env->xregs[1] = frame_addr + offsetof(struct target_rt_sigframe, info);
1327 env->xregs[2] = frame_addr + offsetof(struct target_rt_sigframe, uc);
1328 }
1329
1330 unlock_user_struct(frame, frame_addr, 1);
1331 return;
1332
1333 give_sigsegv:
1334 unlock_user_struct(frame, frame_addr, 1);
1335 force_sig(TARGET_SIGSEGV);
1336}
1337
1338static void setup_rt_frame(int sig, struct target_sigaction *ka,
1339 target_siginfo_t *info, target_sigset_t *set,
1340 CPUARMState *env)
1341{
1342 target_setup_frame(sig, ka, info, set, env);
1343}
1344
1345static void setup_frame(int sig, struct target_sigaction *ka,
1346 target_sigset_t *set, CPUARMState *env)
1347{
1348 target_setup_frame(sig, ka, 0, set, env);
1349}
1350
1351long do_rt_sigreturn(CPUARMState *env)
1352{
Peter Maydell7f72cd22014-03-12 13:06:00 +00001353 struct target_rt_sigframe *frame = NULL;
Andreas Schwab1744aea2013-09-03 20:12:16 +01001354 abi_ulong frame_addr = env->xregs[31];
1355
1356 if (frame_addr & 15) {
1357 goto badframe;
1358 }
1359
1360 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
1361 goto badframe;
1362 }
1363
1364 if (target_restore_sigframe(env, frame)) {
1365 goto badframe;
1366 }
1367
1368 if (do_sigaltstack(frame_addr +
1369 offsetof(struct target_rt_sigframe, uc.tuc_stack),
1370 0, get_sp_from_cpustate(env)) == -EFAULT) {
1371 goto badframe;
1372 }
1373
1374 unlock_user_struct(frame, frame_addr, 0);
1375 return env->xregs[0];
1376
1377 badframe:
1378 unlock_user_struct(frame, frame_addr, 0);
1379 force_sig(TARGET_SIGSEGV);
1380 return 0;
1381}
1382
1383long do_sigreturn(CPUARMState *env)
1384{
1385 return do_rt_sigreturn(env);
1386}
1387
bellard43fff232003-07-09 19:31:39 +00001388#elif defined(TARGET_ARM)
1389
1390struct target_sigcontext {
blueswir1992f48a2007-10-14 16:27:31 +00001391 abi_ulong trap_no;
1392 abi_ulong error_code;
1393 abi_ulong oldmask;
1394 abi_ulong arm_r0;
1395 abi_ulong arm_r1;
1396 abi_ulong arm_r2;
1397 abi_ulong arm_r3;
1398 abi_ulong arm_r4;
1399 abi_ulong arm_r5;
1400 abi_ulong arm_r6;
1401 abi_ulong arm_r7;
1402 abi_ulong arm_r8;
1403 abi_ulong arm_r9;
1404 abi_ulong arm_r10;
1405 abi_ulong arm_fp;
1406 abi_ulong arm_ip;
1407 abi_ulong arm_sp;
1408 abi_ulong arm_lr;
1409 abi_ulong arm_pc;
1410 abi_ulong arm_cpsr;
1411 abi_ulong fault_address;
bellard43fff232003-07-09 19:31:39 +00001412};
1413
pbrooka745ec62008-05-06 15:36:17 +00001414struct target_ucontext_v1 {
blueswir1992f48a2007-10-14 16:27:31 +00001415 abi_ulong tuc_flags;
1416 abi_ulong tuc_link;
Anthony Liguoric227f092009-10-01 16:12:16 -05001417 target_stack_t tuc_stack;
bellardb8076a72005-04-07 22:20:31 +00001418 struct target_sigcontext tuc_mcontext;
Anthony Liguoric227f092009-10-01 16:12:16 -05001419 target_sigset_t tuc_sigmask; /* mask last for extensibility */
bellard43fff232003-07-09 19:31:39 +00001420};
1421
pbrooka745ec62008-05-06 15:36:17 +00001422struct target_ucontext_v2 {
1423 abi_ulong tuc_flags;
1424 abi_ulong tuc_link;
Anthony Liguoric227f092009-10-01 16:12:16 -05001425 target_stack_t tuc_stack;
pbrooka745ec62008-05-06 15:36:17 +00001426 struct target_sigcontext tuc_mcontext;
Anthony Liguoric227f092009-10-01 16:12:16 -05001427 target_sigset_t tuc_sigmask; /* mask last for extensibility */
Peter Maydell5f0b7c82010-11-24 15:20:03 +00001428 char __unused[128 - sizeof(target_sigset_t)];
pbrooka745ec62008-05-06 15:36:17 +00001429 abi_ulong tuc_regspace[128] __attribute__((__aligned__(8)));
1430};
1431
Peter Maydell0d871bd2010-11-24 15:20:05 +00001432struct target_user_vfp {
1433 uint64_t fpregs[32];
1434 abi_ulong fpscr;
1435};
1436
1437struct target_user_vfp_exc {
1438 abi_ulong fpexc;
1439 abi_ulong fpinst;
1440 abi_ulong fpinst2;
1441};
1442
1443struct target_vfp_sigframe {
1444 abi_ulong magic;
1445 abi_ulong size;
1446 struct target_user_vfp ufp;
1447 struct target_user_vfp_exc ufp_exc;
1448} __attribute__((__aligned__(8)));
1449
Peter Maydell08e11252010-11-24 15:20:07 +00001450struct target_iwmmxt_sigframe {
1451 abi_ulong magic;
1452 abi_ulong size;
1453 uint64_t regs[16];
1454 /* Note that not all the coprocessor control registers are stored here */
1455 uint32_t wcssf;
1456 uint32_t wcasf;
1457 uint32_t wcgr0;
1458 uint32_t wcgr1;
1459 uint32_t wcgr2;
1460 uint32_t wcgr3;
1461} __attribute__((__aligned__(8)));
1462
Peter Maydell0d871bd2010-11-24 15:20:05 +00001463#define TARGET_VFP_MAGIC 0x56465001
Peter Maydell08e11252010-11-24 15:20:07 +00001464#define TARGET_IWMMXT_MAGIC 0x12ef842a
Peter Maydell0d871bd2010-11-24 15:20:05 +00001465
pbrooka8c33202008-05-07 23:22:46 +00001466struct sigframe_v1
bellard43fff232003-07-09 19:31:39 +00001467{
1468 struct target_sigcontext sc;
blueswir1992f48a2007-10-14 16:27:31 +00001469 abi_ulong extramask[TARGET_NSIG_WORDS-1];
1470 abi_ulong retcode;
bellard43fff232003-07-09 19:31:39 +00001471};
1472
pbrooka8c33202008-05-07 23:22:46 +00001473struct sigframe_v2
1474{
1475 struct target_ucontext_v2 uc;
1476 abi_ulong retcode;
1477};
1478
pbrooka745ec62008-05-06 15:36:17 +00001479struct rt_sigframe_v1
bellard43fff232003-07-09 19:31:39 +00001480{
bellardf8b0aa22007-11-11 23:03:42 +00001481 abi_ulong pinfo;
1482 abi_ulong puc;
bellard43fff232003-07-09 19:31:39 +00001483 struct target_siginfo info;
pbrooka745ec62008-05-06 15:36:17 +00001484 struct target_ucontext_v1 uc;
1485 abi_ulong retcode;
1486};
1487
1488struct rt_sigframe_v2
1489{
1490 struct target_siginfo info;
1491 struct target_ucontext_v2 uc;
blueswir1992f48a2007-10-14 16:27:31 +00001492 abi_ulong retcode;
bellard43fff232003-07-09 19:31:39 +00001493};
1494
1495#define TARGET_CONFIG_CPU_32 1
1496
1497/*
1498 * For ARM syscalls, we encode the syscall number into the instruction.
1499 */
1500#define SWI_SYS_SIGRETURN (0xef000000|(TARGET_NR_sigreturn + ARM_SYSCALL_BASE))
1501#define SWI_SYS_RT_SIGRETURN (0xef000000|(TARGET_NR_rt_sigreturn + ARM_SYSCALL_BASE))
1502
1503/*
1504 * For Thumb syscalls, we pass the syscall number via r7. We therefore
1505 * need two 16-bit instructions.
1506 */
1507#define SWI_THUMB_SIGRETURN (0xdf00 << 16 | 0x2700 | (TARGET_NR_sigreturn))
1508#define SWI_THUMB_RT_SIGRETURN (0xdf00 << 16 | 0x2700 | (TARGET_NR_rt_sigreturn))
1509
blueswir1992f48a2007-10-14 16:27:31 +00001510static const abi_ulong retcodes[4] = {
bellard43fff232003-07-09 19:31:39 +00001511 SWI_SYS_SIGRETURN, SWI_THUMB_SIGRETURN,
1512 SWI_SYS_RT_SIGRETURN, SWI_THUMB_RT_SIGRETURN
1513};
1514
1515
bellard43fff232003-07-09 19:31:39 +00001516#define __get_user_error(x,p,e) __get_user(x, p)
1517
Andreas Färber05390242012-02-25 03:37:53 +01001518static inline int valid_user_regs(CPUARMState *regs)
bellard43fff232003-07-09 19:31:39 +00001519{
1520 return 1;
1521}
1522
pbrooka8c33202008-05-07 23:22:46 +00001523static void
bellard43fff232003-07-09 19:31:39 +00001524setup_sigcontext(struct target_sigcontext *sc, /*struct _fpstate *fpstate,*/
Andreas Färber05390242012-02-25 03:37:53 +01001525 CPUARMState *env, abi_ulong mask)
bellard43fff232003-07-09 19:31:39 +00001526{
pbrooka8c33202008-05-07 23:22:46 +00001527 __put_user(env->regs[0], &sc->arm_r0);
1528 __put_user(env->regs[1], &sc->arm_r1);
1529 __put_user(env->regs[2], &sc->arm_r2);
1530 __put_user(env->regs[3], &sc->arm_r3);
1531 __put_user(env->regs[4], &sc->arm_r4);
1532 __put_user(env->regs[5], &sc->arm_r5);
1533 __put_user(env->regs[6], &sc->arm_r6);
1534 __put_user(env->regs[7], &sc->arm_r7);
1535 __put_user(env->regs[8], &sc->arm_r8);
1536 __put_user(env->regs[9], &sc->arm_r9);
1537 __put_user(env->regs[10], &sc->arm_r10);
1538 __put_user(env->regs[11], &sc->arm_fp);
1539 __put_user(env->regs[12], &sc->arm_ip);
1540 __put_user(env->regs[13], &sc->arm_sp);
1541 __put_user(env->regs[14], &sc->arm_lr);
1542 __put_user(env->regs[15], &sc->arm_pc);
bellard43fff232003-07-09 19:31:39 +00001543#ifdef TARGET_CONFIG_CPU_32
pbrooka8c33202008-05-07 23:22:46 +00001544 __put_user(cpsr_read(env), &sc->arm_cpsr);
bellard43fff232003-07-09 19:31:39 +00001545#endif
1546
pbrooka8c33202008-05-07 23:22:46 +00001547 __put_user(/* current->thread.trap_no */ 0, &sc->trap_no);
1548 __put_user(/* current->thread.error_code */ 0, &sc->error_code);
1549 __put_user(/* current->thread.address */ 0, &sc->fault_address);
1550 __put_user(mask, &sc->oldmask);
bellard43fff232003-07-09 19:31:39 +00001551}
1552
bellard579a97f2007-11-11 14:26:47 +00001553static inline abi_ulong
Andreas Färber05390242012-02-25 03:37:53 +01001554get_sigframe(struct target_sigaction *ka, CPUARMState *regs, int framesize)
bellard43fff232003-07-09 19:31:39 +00001555{
1556 unsigned long sp = regs->regs[13];
1557
bellard43fff232003-07-09 19:31:39 +00001558 /*
1559 * This is the X/Open sanctioned signal stack switching.
1560 */
pbrook624f7972008-05-31 16:11:38 +00001561 if ((ka->sa_flags & TARGET_SA_ONSTACK) && !sas_ss_flags(sp))
thsa04e1342007-09-27 13:57:58 +00001562 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
bellard43fff232003-07-09 19:31:39 +00001563 /*
1564 * ATPCS B01 mandates 8-byte alignment
1565 */
bellard579a97f2007-11-11 14:26:47 +00001566 return (sp - framesize) & ~7;
bellard43fff232003-07-09 19:31:39 +00001567}
1568
1569static int
Andreas Färber05390242012-02-25 03:37:53 +01001570setup_return(CPUARMState *env, struct target_sigaction *ka,
bellardf8b0aa22007-11-11 23:03:42 +00001571 abi_ulong *rc, abi_ulong frame_addr, int usig, abi_ulong rc_addr)
bellard43fff232003-07-09 19:31:39 +00001572{
pbrook624f7972008-05-31 16:11:38 +00001573 abi_ulong handler = ka->_sa_handler;
blueswir1992f48a2007-10-14 16:27:31 +00001574 abi_ulong retcode;
pbrook75b680e2008-03-21 16:07:30 +00001575 int thumb = handler & 1;
Peter Maydell964413d2011-01-14 20:39:19 +01001576 uint32_t cpsr = cpsr_read(env);
1577
1578 cpsr &= ~CPSR_IT;
1579 if (thumb) {
1580 cpsr |= CPSR_T;
1581 } else {
1582 cpsr &= ~CPSR_T;
1583 }
bellard43fff232003-07-09 19:31:39 +00001584
pbrook624f7972008-05-31 16:11:38 +00001585 if (ka->sa_flags & TARGET_SA_RESTORER) {
1586 retcode = ka->sa_restorer;
bellard43fff232003-07-09 19:31:39 +00001587 } else {
1588 unsigned int idx = thumb;
1589
pbrook624f7972008-05-31 16:11:38 +00001590 if (ka->sa_flags & TARGET_SA_SIGINFO)
bellard43fff232003-07-09 19:31:39 +00001591 idx += 2;
1592
1593 if (__put_user(retcodes[idx], rc))
1594 return 1;
Stefan Weilca8a2772011-10-03 22:43:19 +02001595
bellardf8b0aa22007-11-11 23:03:42 +00001596 retcode = rc_addr + thumb;
bellard43fff232003-07-09 19:31:39 +00001597 }
1598
1599 env->regs[0] = usig;
bellardf8b0aa22007-11-11 23:03:42 +00001600 env->regs[13] = frame_addr;
bellard43fff232003-07-09 19:31:39 +00001601 env->regs[14] = retcode;
1602 env->regs[15] = handler & (thumb ? ~1 : ~3);
Peter Maydell964413d2011-01-14 20:39:19 +01001603 cpsr_write(env, cpsr, 0xffffffff);
bellard43fff232003-07-09 19:31:39 +00001604
1605 return 0;
1606}
1607
Andreas Färber05390242012-02-25 03:37:53 +01001608static abi_ulong *setup_sigframe_v2_vfp(abi_ulong *regspace, CPUARMState *env)
Peter Maydell0d871bd2010-11-24 15:20:05 +00001609{
1610 int i;
1611 struct target_vfp_sigframe *vfpframe;
1612 vfpframe = (struct target_vfp_sigframe *)regspace;
1613 __put_user(TARGET_VFP_MAGIC, &vfpframe->magic);
1614 __put_user(sizeof(*vfpframe), &vfpframe->size);
1615 for (i = 0; i < 32; i++) {
Peter Maydell005e1a02011-02-10 13:59:35 +00001616 __put_user(float64_val(env->vfp.regs[i]), &vfpframe->ufp.fpregs[i]);
Peter Maydell0d871bd2010-11-24 15:20:05 +00001617 }
1618 __put_user(vfp_get_fpscr(env), &vfpframe->ufp.fpscr);
1619 __put_user(env->vfp.xregs[ARM_VFP_FPEXC], &vfpframe->ufp_exc.fpexc);
1620 __put_user(env->vfp.xregs[ARM_VFP_FPINST], &vfpframe->ufp_exc.fpinst);
1621 __put_user(env->vfp.xregs[ARM_VFP_FPINST2], &vfpframe->ufp_exc.fpinst2);
1622 return (abi_ulong*)(vfpframe+1);
1623}
1624
Andreas Färber05390242012-02-25 03:37:53 +01001625static abi_ulong *setup_sigframe_v2_iwmmxt(abi_ulong *regspace,
1626 CPUARMState *env)
Peter Maydell08e11252010-11-24 15:20:07 +00001627{
1628 int i;
1629 struct target_iwmmxt_sigframe *iwmmxtframe;
1630 iwmmxtframe = (struct target_iwmmxt_sigframe *)regspace;
1631 __put_user(TARGET_IWMMXT_MAGIC, &iwmmxtframe->magic);
1632 __put_user(sizeof(*iwmmxtframe), &iwmmxtframe->size);
1633 for (i = 0; i < 16; i++) {
1634 __put_user(env->iwmmxt.regs[i], &iwmmxtframe->regs[i]);
1635 }
1636 __put_user(env->vfp.xregs[ARM_IWMMXT_wCSSF], &iwmmxtframe->wcssf);
1637 __put_user(env->vfp.xregs[ARM_IWMMXT_wCASF], &iwmmxtframe->wcssf);
1638 __put_user(env->vfp.xregs[ARM_IWMMXT_wCGR0], &iwmmxtframe->wcgr0);
1639 __put_user(env->vfp.xregs[ARM_IWMMXT_wCGR1], &iwmmxtframe->wcgr1);
1640 __put_user(env->vfp.xregs[ARM_IWMMXT_wCGR2], &iwmmxtframe->wcgr2);
1641 __put_user(env->vfp.xregs[ARM_IWMMXT_wCGR3], &iwmmxtframe->wcgr3);
1642 return (abi_ulong*)(iwmmxtframe+1);
1643}
1644
pbrooka8c33202008-05-07 23:22:46 +00001645static void setup_sigframe_v2(struct target_ucontext_v2 *uc,
Andreas Färber05390242012-02-25 03:37:53 +01001646 target_sigset_t *set, CPUARMState *env)
bellard43fff232003-07-09 19:31:39 +00001647{
pbrooka8c33202008-05-07 23:22:46 +00001648 struct target_sigaltstack stack;
1649 int i;
Peter Maydell0d871bd2010-11-24 15:20:05 +00001650 abi_ulong *regspace;
pbrooka8c33202008-05-07 23:22:46 +00001651
1652 /* Clear all the bits of the ucontext we don't use. */
1653 memset(uc, 0, offsetof(struct target_ucontext_v2, tuc_mcontext));
1654
1655 memset(&stack, 0, sizeof(stack));
1656 __put_user(target_sigaltstack_used.ss_sp, &stack.ss_sp);
1657 __put_user(target_sigaltstack_used.ss_size, &stack.ss_size);
1658 __put_user(sas_ss_flags(get_sp_from_cpustate(env)), &stack.ss_flags);
1659 memcpy(&uc->tuc_stack, &stack, sizeof(stack));
1660
1661 setup_sigcontext(&uc->tuc_mcontext, env, set->sig[0]);
Peter Maydell0d871bd2010-11-24 15:20:05 +00001662 /* Save coprocessor signal frame. */
1663 regspace = uc->tuc_regspace;
1664 if (arm_feature(env, ARM_FEATURE_VFP)) {
1665 regspace = setup_sigframe_v2_vfp(regspace, env);
1666 }
Peter Maydell08e11252010-11-24 15:20:07 +00001667 if (arm_feature(env, ARM_FEATURE_IWMMXT)) {
1668 regspace = setup_sigframe_v2_iwmmxt(regspace, env);
1669 }
1670
Peter Maydell0d871bd2010-11-24 15:20:05 +00001671 /* Write terminating magic word */
1672 __put_user(0, regspace);
1673
pbrooka8c33202008-05-07 23:22:46 +00001674 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
1675 __put_user(set->sig[i], &uc->tuc_sigmask.sig[i]);
1676 }
1677}
1678
1679/* compare linux/arch/arm/kernel/signal.c:setup_frame() */
pbrook624f7972008-05-31 16:11:38 +00001680static void setup_frame_v1(int usig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01001681 target_sigset_t *set, CPUARMState *regs)
pbrooka8c33202008-05-07 23:22:46 +00001682{
1683 struct sigframe_v1 *frame;
bellard579a97f2007-11-11 14:26:47 +00001684 abi_ulong frame_addr = get_sigframe(ka, regs, sizeof(*frame));
pbrooka8c33202008-05-07 23:22:46 +00001685 int i;
bellard43fff232003-07-09 19:31:39 +00001686
bellard579a97f2007-11-11 14:26:47 +00001687 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
1688 return;
1689
pbrooka8c33202008-05-07 23:22:46 +00001690 setup_sigcontext(&frame->sc, regs, set->sig[0]);
bellard43fff232003-07-09 19:31:39 +00001691
bellard92319442004-06-19 16:58:13 +00001692 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
1693 if (__put_user(set->sig[i], &frame->extramask[i - 1]))
bellard579a97f2007-11-11 14:26:47 +00001694 goto end;
bellard43fff232003-07-09 19:31:39 +00001695 }
1696
pbrooka8c33202008-05-07 23:22:46 +00001697 setup_return(regs, ka, &frame->retcode, frame_addr, usig,
1698 frame_addr + offsetof(struct sigframe_v1, retcode));
bellard579a97f2007-11-11 14:26:47 +00001699
1700end:
1701 unlock_user_struct(frame, frame_addr, 1);
pbrooka8c33202008-05-07 23:22:46 +00001702}
1703
pbrook624f7972008-05-31 16:11:38 +00001704static void setup_frame_v2(int usig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01001705 target_sigset_t *set, CPUARMState *regs)
pbrooka8c33202008-05-07 23:22:46 +00001706{
1707 struct sigframe_v2 *frame;
1708 abi_ulong frame_addr = get_sigframe(ka, regs, sizeof(*frame));
1709
1710 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
1711 return;
1712
1713 setup_sigframe_v2(&frame->uc, set, regs);
1714
1715 setup_return(regs, ka, &frame->retcode, frame_addr, usig,
1716 frame_addr + offsetof(struct sigframe_v2, retcode));
1717
1718 unlock_user_struct(frame, frame_addr, 1);
1719}
1720
pbrook624f7972008-05-31 16:11:38 +00001721static void setup_frame(int usig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01001722 target_sigset_t *set, CPUARMState *regs)
pbrooka8c33202008-05-07 23:22:46 +00001723{
1724 if (get_osversion() >= 0x020612) {
1725 setup_frame_v2(usig, ka, set, regs);
1726 } else {
1727 setup_frame_v1(usig, ka, set, regs);
1728 }
bellard43fff232003-07-09 19:31:39 +00001729}
1730
bellard579a97f2007-11-11 14:26:47 +00001731/* compare linux/arch/arm/kernel/signal.c:setup_rt_frame() */
pbrook624f7972008-05-31 16:11:38 +00001732static void setup_rt_frame_v1(int usig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05001733 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01001734 target_sigset_t *set, CPUARMState *env)
bellard43fff232003-07-09 19:31:39 +00001735{
pbrooka745ec62008-05-06 15:36:17 +00001736 struct rt_sigframe_v1 *frame;
bellard579a97f2007-11-11 14:26:47 +00001737 abi_ulong frame_addr = get_sigframe(ka, env, sizeof(*frame));
thsa04e1342007-09-27 13:57:58 +00001738 struct target_sigaltstack stack;
pbrooka8c33202008-05-07 23:22:46 +00001739 int i;
bellardf8b0aa22007-11-11 23:03:42 +00001740 abi_ulong info_addr, uc_addr;
bellard43fff232003-07-09 19:31:39 +00001741
bellard579a97f2007-11-11 14:26:47 +00001742 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
bellardedf779f2004-02-22 13:40:13 +00001743 return /* 1 */;
1744
pbrooka745ec62008-05-06 15:36:17 +00001745 info_addr = frame_addr + offsetof(struct rt_sigframe_v1, info);
pbrooka8c33202008-05-07 23:22:46 +00001746 __put_user(info_addr, &frame->pinfo);
pbrooka745ec62008-05-06 15:36:17 +00001747 uc_addr = frame_addr + offsetof(struct rt_sigframe_v1, uc);
pbrooka8c33202008-05-07 23:22:46 +00001748 __put_user(uc_addr, &frame->puc);
1749 copy_siginfo_to_user(&frame->info, info);
bellard43fff232003-07-09 19:31:39 +00001750
1751 /* Clear all the bits of the ucontext we don't use. */
pbrooka745ec62008-05-06 15:36:17 +00001752 memset(&frame->uc, 0, offsetof(struct target_ucontext_v1, tuc_mcontext));
bellard43fff232003-07-09 19:31:39 +00001753
thsa04e1342007-09-27 13:57:58 +00001754 memset(&stack, 0, sizeof(stack));
1755 __put_user(target_sigaltstack_used.ss_sp, &stack.ss_sp);
1756 __put_user(target_sigaltstack_used.ss_size, &stack.ss_size);
1757 __put_user(sas_ss_flags(get_sp_from_cpustate(env)), &stack.ss_flags);
bellard775b58d2007-11-11 16:22:17 +00001758 memcpy(&frame->uc.tuc_stack, &stack, sizeof(stack));
thsa04e1342007-09-27 13:57:58 +00001759
pbrooka8c33202008-05-07 23:22:46 +00001760 setup_sigcontext(&frame->uc.tuc_mcontext, env, set->sig[0]);
bellard92319442004-06-19 16:58:13 +00001761 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
bellardb8076a72005-04-07 22:20:31 +00001762 if (__put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]))
bellard579a97f2007-11-11 14:26:47 +00001763 goto end;
bellard92319442004-06-19 16:58:13 +00001764 }
bellard43fff232003-07-09 19:31:39 +00001765
pbrooka8c33202008-05-07 23:22:46 +00001766 setup_return(env, ka, &frame->retcode, frame_addr, usig,
1767 frame_addr + offsetof(struct rt_sigframe_v1, retcode));
pbrooka745ec62008-05-06 15:36:17 +00001768
pbrooka8c33202008-05-07 23:22:46 +00001769 env->regs[1] = info_addr;
1770 env->regs[2] = uc_addr;
pbrooka745ec62008-05-06 15:36:17 +00001771
1772end:
1773 unlock_user_struct(frame, frame_addr, 1);
pbrooka745ec62008-05-06 15:36:17 +00001774}
1775
pbrook624f7972008-05-31 16:11:38 +00001776static void setup_rt_frame_v2(int usig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05001777 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01001778 target_sigset_t *set, CPUARMState *env)
pbrooka745ec62008-05-06 15:36:17 +00001779{
1780 struct rt_sigframe_v2 *frame;
1781 abi_ulong frame_addr = get_sigframe(ka, env, sizeof(*frame));
pbrooka745ec62008-05-06 15:36:17 +00001782 abi_ulong info_addr, uc_addr;
1783
1784 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
1785 return /* 1 */;
1786
1787 info_addr = frame_addr + offsetof(struct rt_sigframe_v2, info);
1788 uc_addr = frame_addr + offsetof(struct rt_sigframe_v2, uc);
pbrooka8c33202008-05-07 23:22:46 +00001789 copy_siginfo_to_user(&frame->info, info);
pbrooka745ec62008-05-06 15:36:17 +00001790
pbrooka8c33202008-05-07 23:22:46 +00001791 setup_sigframe_v2(&frame->uc, set, env);
pbrooka745ec62008-05-06 15:36:17 +00001792
pbrooka8c33202008-05-07 23:22:46 +00001793 setup_return(env, ka, &frame->retcode, frame_addr, usig,
1794 frame_addr + offsetof(struct rt_sigframe_v2, retcode));
pbrooka745ec62008-05-06 15:36:17 +00001795
pbrooka8c33202008-05-07 23:22:46 +00001796 env->regs[1] = info_addr;
1797 env->regs[2] = uc_addr;
pbrooka745ec62008-05-06 15:36:17 +00001798
bellard579a97f2007-11-11 14:26:47 +00001799 unlock_user_struct(frame, frame_addr, 1);
bellard43fff232003-07-09 19:31:39 +00001800}
1801
pbrook624f7972008-05-31 16:11:38 +00001802static void setup_rt_frame(int usig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05001803 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01001804 target_sigset_t *set, CPUARMState *env)
pbrooka745ec62008-05-06 15:36:17 +00001805{
1806 if (get_osversion() >= 0x020612) {
1807 setup_rt_frame_v2(usig, ka, info, set, env);
1808 } else {
1809 setup_rt_frame_v1(usig, ka, info, set, env);
1810 }
1811}
1812
bellard43fff232003-07-09 19:31:39 +00001813static int
Andreas Färber05390242012-02-25 03:37:53 +01001814restore_sigcontext(CPUARMState *env, struct target_sigcontext *sc)
bellard43fff232003-07-09 19:31:39 +00001815{
1816 int err = 0;
bellardb5ff1b32005-11-26 10:38:39 +00001817 uint32_t cpsr;
bellard43fff232003-07-09 19:31:39 +00001818
1819 __get_user_error(env->regs[0], &sc->arm_r0, err);
1820 __get_user_error(env->regs[1], &sc->arm_r1, err);
1821 __get_user_error(env->regs[2], &sc->arm_r2, err);
1822 __get_user_error(env->regs[3], &sc->arm_r3, err);
1823 __get_user_error(env->regs[4], &sc->arm_r4, err);
1824 __get_user_error(env->regs[5], &sc->arm_r5, err);
1825 __get_user_error(env->regs[6], &sc->arm_r6, err);
1826 __get_user_error(env->regs[7], &sc->arm_r7, err);
1827 __get_user_error(env->regs[8], &sc->arm_r8, err);
1828 __get_user_error(env->regs[9], &sc->arm_r9, err);
1829 __get_user_error(env->regs[10], &sc->arm_r10, err);
1830 __get_user_error(env->regs[11], &sc->arm_fp, err);
1831 __get_user_error(env->regs[12], &sc->arm_ip, err);
1832 __get_user_error(env->regs[13], &sc->arm_sp, err);
1833 __get_user_error(env->regs[14], &sc->arm_lr, err);
1834 __get_user_error(env->regs[15], &sc->arm_pc, err);
1835#ifdef TARGET_CONFIG_CPU_32
bellardb5ff1b32005-11-26 10:38:39 +00001836 __get_user_error(cpsr, &sc->arm_cpsr, err);
pbrook75b680e2008-03-21 16:07:30 +00001837 cpsr_write(env, cpsr, CPSR_USER | CPSR_EXEC);
bellard43fff232003-07-09 19:31:39 +00001838#endif
1839
1840 err |= !valid_user_regs(env);
1841
1842 return err;
1843}
1844
Andreas Färber05390242012-02-25 03:37:53 +01001845static long do_sigreturn_v1(CPUARMState *env)
bellard43fff232003-07-09 19:31:39 +00001846{
bellardf8b0aa22007-11-11 23:03:42 +00001847 abi_ulong frame_addr;
Peter Maydell978fae92013-07-29 12:00:32 +01001848 struct sigframe_v1 *frame = NULL;
Anthony Liguoric227f092009-10-01 16:12:16 -05001849 target_sigset_t set;
bellard43fff232003-07-09 19:31:39 +00001850 sigset_t host_set;
bellard92319442004-06-19 16:58:13 +00001851 int i;
bellard43fff232003-07-09 19:31:39 +00001852
1853 /*
1854 * Since we stacked the signal on a 64-bit boundary,
1855 * then 'sp' should be word aligned here. If it's
1856 * not, then the user is trying to mess with us.
1857 */
bellardf8b0aa22007-11-11 23:03:42 +00001858 frame_addr = env->regs[13];
Peter Maydell978fae92013-07-29 12:00:32 +01001859 if (frame_addr & 7) {
1860 goto badframe;
1861 }
1862
bellardf8b0aa22007-11-11 23:03:42 +00001863 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
1864 goto badframe;
bellard43fff232003-07-09 19:31:39 +00001865
bellard92319442004-06-19 16:58:13 +00001866 if (__get_user(set.sig[0], &frame->sc.oldmask))
1867 goto badframe;
1868 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
1869 if (__get_user(set.sig[i], &frame->extramask[i - 1]))
1870 goto badframe;
1871 }
bellard43fff232003-07-09 19:31:39 +00001872
bellard92319442004-06-19 16:58:13 +00001873 target_to_host_sigset_internal(&host_set, &set);
Alex Barcelo1c275922014-03-14 14:36:55 +00001874 do_sigprocmask(SIG_SETMASK, &host_set, NULL);
bellard43fff232003-07-09 19:31:39 +00001875
1876 if (restore_sigcontext(env, &frame->sc))
1877 goto badframe;
1878
1879#if 0
1880 /* Send SIGTRAP if we're single-stepping */
1881 if (ptrace_cancel_bpt(current))
1882 send_sig(SIGTRAP, current, 1);
1883#endif
bellardf8b0aa22007-11-11 23:03:42 +00001884 unlock_user_struct(frame, frame_addr, 0);
1885 return env->regs[0];
bellard43fff232003-07-09 19:31:39 +00001886
1887badframe:
bellardf8b0aa22007-11-11 23:03:42 +00001888 unlock_user_struct(frame, frame_addr, 0);
Riku Voipio66393fb2009-12-04 15:16:32 +02001889 force_sig(TARGET_SIGSEGV /* , current */);
bellard43fff232003-07-09 19:31:39 +00001890 return 0;
1891}
1892
Andreas Färber05390242012-02-25 03:37:53 +01001893static abi_ulong *restore_sigframe_v2_vfp(CPUARMState *env, abi_ulong *regspace)
Peter Maydell5f9099d2010-11-24 15:20:06 +00001894{
1895 int i;
1896 abi_ulong magic, sz;
1897 uint32_t fpscr, fpexc;
1898 struct target_vfp_sigframe *vfpframe;
1899 vfpframe = (struct target_vfp_sigframe *)regspace;
1900
1901 __get_user(magic, &vfpframe->magic);
1902 __get_user(sz, &vfpframe->size);
1903 if (magic != TARGET_VFP_MAGIC || sz != sizeof(*vfpframe)) {
1904 return 0;
1905 }
1906 for (i = 0; i < 32; i++) {
Peter Maydell005e1a02011-02-10 13:59:35 +00001907 __get_user(float64_val(env->vfp.regs[i]), &vfpframe->ufp.fpregs[i]);
Peter Maydell5f9099d2010-11-24 15:20:06 +00001908 }
1909 __get_user(fpscr, &vfpframe->ufp.fpscr);
1910 vfp_set_fpscr(env, fpscr);
1911 __get_user(fpexc, &vfpframe->ufp_exc.fpexc);
1912 /* Sanitise FPEXC: ensure VFP is enabled, FPINST2 is invalid
1913 * and the exception flag is cleared
1914 */
1915 fpexc |= (1 << 30);
1916 fpexc &= ~((1 << 31) | (1 << 28));
1917 env->vfp.xregs[ARM_VFP_FPEXC] = fpexc;
1918 __get_user(env->vfp.xregs[ARM_VFP_FPINST], &vfpframe->ufp_exc.fpinst);
1919 __get_user(env->vfp.xregs[ARM_VFP_FPINST2], &vfpframe->ufp_exc.fpinst2);
1920 return (abi_ulong*)(vfpframe + 1);
1921}
1922
Andreas Färber05390242012-02-25 03:37:53 +01001923static abi_ulong *restore_sigframe_v2_iwmmxt(CPUARMState *env,
1924 abi_ulong *regspace)
Peter Maydella59d69d2010-11-24 15:20:08 +00001925{
1926 int i;
1927 abi_ulong magic, sz;
1928 struct target_iwmmxt_sigframe *iwmmxtframe;
1929 iwmmxtframe = (struct target_iwmmxt_sigframe *)regspace;
1930
1931 __get_user(magic, &iwmmxtframe->magic);
1932 __get_user(sz, &iwmmxtframe->size);
1933 if (magic != TARGET_IWMMXT_MAGIC || sz != sizeof(*iwmmxtframe)) {
1934 return 0;
1935 }
1936 for (i = 0; i < 16; i++) {
1937 __get_user(env->iwmmxt.regs[i], &iwmmxtframe->regs[i]);
1938 }
1939 __get_user(env->vfp.xregs[ARM_IWMMXT_wCSSF], &iwmmxtframe->wcssf);
1940 __get_user(env->vfp.xregs[ARM_IWMMXT_wCASF], &iwmmxtframe->wcssf);
1941 __get_user(env->vfp.xregs[ARM_IWMMXT_wCGR0], &iwmmxtframe->wcgr0);
1942 __get_user(env->vfp.xregs[ARM_IWMMXT_wCGR1], &iwmmxtframe->wcgr1);
1943 __get_user(env->vfp.xregs[ARM_IWMMXT_wCGR2], &iwmmxtframe->wcgr2);
1944 __get_user(env->vfp.xregs[ARM_IWMMXT_wCGR3], &iwmmxtframe->wcgr3);
1945 return (abi_ulong*)(iwmmxtframe + 1);
1946}
1947
Andreas Färber05390242012-02-25 03:37:53 +01001948static int do_sigframe_return_v2(CPUARMState *env, target_ulong frame_addr,
pbrooka8c33202008-05-07 23:22:46 +00001949 struct target_ucontext_v2 *uc)
1950{
1951 sigset_t host_set;
Peter Maydell5f9099d2010-11-24 15:20:06 +00001952 abi_ulong *regspace;
pbrooka8c33202008-05-07 23:22:46 +00001953
1954 target_to_host_sigset(&host_set, &uc->tuc_sigmask);
Alex Barcelo1c275922014-03-14 14:36:55 +00001955 do_sigprocmask(SIG_SETMASK, &host_set, NULL);
pbrooka8c33202008-05-07 23:22:46 +00001956
1957 if (restore_sigcontext(env, &uc->tuc_mcontext))
1958 return 1;
1959
Peter Maydell5f9099d2010-11-24 15:20:06 +00001960 /* Restore coprocessor signal frame */
1961 regspace = uc->tuc_regspace;
1962 if (arm_feature(env, ARM_FEATURE_VFP)) {
1963 regspace = restore_sigframe_v2_vfp(env, regspace);
1964 if (!regspace) {
1965 return 1;
1966 }
1967 }
Peter Maydella59d69d2010-11-24 15:20:08 +00001968 if (arm_feature(env, ARM_FEATURE_IWMMXT)) {
1969 regspace = restore_sigframe_v2_iwmmxt(env, regspace);
1970 if (!regspace) {
1971 return 1;
1972 }
1973 }
Peter Maydell5f9099d2010-11-24 15:20:06 +00001974
pbrooka8c33202008-05-07 23:22:46 +00001975 if (do_sigaltstack(frame_addr + offsetof(struct target_ucontext_v2, tuc_stack), 0, get_sp_from_cpustate(env)) == -EFAULT)
1976 return 1;
1977
1978#if 0
1979 /* Send SIGTRAP if we're single-stepping */
1980 if (ptrace_cancel_bpt(current))
1981 send_sig(SIGTRAP, current, 1);
1982#endif
1983
1984 return 0;
1985}
1986
Andreas Färber05390242012-02-25 03:37:53 +01001987static long do_sigreturn_v2(CPUARMState *env)
pbrooka8c33202008-05-07 23:22:46 +00001988{
1989 abi_ulong frame_addr;
Peter Maydell978fae92013-07-29 12:00:32 +01001990 struct sigframe_v2 *frame = NULL;
pbrooka8c33202008-05-07 23:22:46 +00001991
1992 /*
1993 * Since we stacked the signal on a 64-bit boundary,
1994 * then 'sp' should be word aligned here. If it's
1995 * not, then the user is trying to mess with us.
1996 */
pbrooka8c33202008-05-07 23:22:46 +00001997 frame_addr = env->regs[13];
Peter Maydell978fae92013-07-29 12:00:32 +01001998 if (frame_addr & 7) {
1999 goto badframe;
2000 }
2001
pbrooka8c33202008-05-07 23:22:46 +00002002 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
2003 goto badframe;
2004
2005 if (do_sigframe_return_v2(env, frame_addr, &frame->uc))
2006 goto badframe;
2007
2008 unlock_user_struct(frame, frame_addr, 0);
2009 return env->regs[0];
2010
2011badframe:
2012 unlock_user_struct(frame, frame_addr, 0);
Riku Voipio66393fb2009-12-04 15:16:32 +02002013 force_sig(TARGET_SIGSEGV /* , current */);
pbrooka8c33202008-05-07 23:22:46 +00002014 return 0;
2015}
2016
Andreas Färber05390242012-02-25 03:37:53 +01002017long do_sigreturn(CPUARMState *env)
pbrooka8c33202008-05-07 23:22:46 +00002018{
2019 if (get_osversion() >= 0x020612) {
2020 return do_sigreturn_v2(env);
2021 } else {
2022 return do_sigreturn_v1(env);
2023 }
2024}
2025
Andreas Färber05390242012-02-25 03:37:53 +01002026static long do_rt_sigreturn_v1(CPUARMState *env)
bellard43fff232003-07-09 19:31:39 +00002027{
bellardf8b0aa22007-11-11 23:03:42 +00002028 abi_ulong frame_addr;
Peter Maydell978fae92013-07-29 12:00:32 +01002029 struct rt_sigframe_v1 *frame = NULL;
bellard43fff232003-07-09 19:31:39 +00002030 sigset_t host_set;
2031
2032 /*
2033 * Since we stacked the signal on a 64-bit boundary,
2034 * then 'sp' should be word aligned here. If it's
2035 * not, then the user is trying to mess with us.
2036 */
bellardf8b0aa22007-11-11 23:03:42 +00002037 frame_addr = env->regs[13];
Peter Maydell978fae92013-07-29 12:00:32 +01002038 if (frame_addr & 7) {
2039 goto badframe;
2040 }
2041
bellardf8b0aa22007-11-11 23:03:42 +00002042 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
2043 goto badframe;
bellard43fff232003-07-09 19:31:39 +00002044
bellardb8076a72005-04-07 22:20:31 +00002045 target_to_host_sigset(&host_set, &frame->uc.tuc_sigmask);
Alex Barcelo1c275922014-03-14 14:36:55 +00002046 do_sigprocmask(SIG_SETMASK, &host_set, NULL);
bellard43fff232003-07-09 19:31:39 +00002047
bellardb8076a72005-04-07 22:20:31 +00002048 if (restore_sigcontext(env, &frame->uc.tuc_mcontext))
bellard43fff232003-07-09 19:31:39 +00002049 goto badframe;
2050
pbrooka745ec62008-05-06 15:36:17 +00002051 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 +00002052 goto badframe;
2053
bellard43fff232003-07-09 19:31:39 +00002054#if 0
2055 /* Send SIGTRAP if we're single-stepping */
2056 if (ptrace_cancel_bpt(current))
2057 send_sig(SIGTRAP, current, 1);
2058#endif
bellardf8b0aa22007-11-11 23:03:42 +00002059 unlock_user_struct(frame, frame_addr, 0);
bellard43fff232003-07-09 19:31:39 +00002060 return env->regs[0];
2061
2062badframe:
bellardf8b0aa22007-11-11 23:03:42 +00002063 unlock_user_struct(frame, frame_addr, 0);
Riku Voipio66393fb2009-12-04 15:16:32 +02002064 force_sig(TARGET_SIGSEGV /* , current */);
bellard43fff232003-07-09 19:31:39 +00002065 return 0;
2066}
2067
Andreas Färber05390242012-02-25 03:37:53 +01002068static long do_rt_sigreturn_v2(CPUARMState *env)
pbrooka745ec62008-05-06 15:36:17 +00002069{
2070 abi_ulong frame_addr;
Peter Maydell978fae92013-07-29 12:00:32 +01002071 struct rt_sigframe_v2 *frame = NULL;
pbrooka745ec62008-05-06 15:36:17 +00002072
2073 /*
2074 * Since we stacked the signal on a 64-bit boundary,
2075 * then 'sp' should be word aligned here. If it's
2076 * not, then the user is trying to mess with us.
2077 */
pbrooka745ec62008-05-06 15:36:17 +00002078 frame_addr = env->regs[13];
Peter Maydell978fae92013-07-29 12:00:32 +01002079 if (frame_addr & 7) {
2080 goto badframe;
2081 }
2082
pbrooka745ec62008-05-06 15:36:17 +00002083 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
2084 goto badframe;
2085
pbrooka8c33202008-05-07 23:22:46 +00002086 if (do_sigframe_return_v2(env, frame_addr, &frame->uc))
2087 goto badframe;
pbrooka745ec62008-05-06 15:36:17 +00002088
pbrooka745ec62008-05-06 15:36:17 +00002089 unlock_user_struct(frame, frame_addr, 0);
2090 return env->regs[0];
2091
2092badframe:
2093 unlock_user_struct(frame, frame_addr, 0);
Riku Voipio66393fb2009-12-04 15:16:32 +02002094 force_sig(TARGET_SIGSEGV /* , current */);
pbrooka745ec62008-05-06 15:36:17 +00002095 return 0;
2096}
2097
Andreas Färber05390242012-02-25 03:37:53 +01002098long do_rt_sigreturn(CPUARMState *env)
pbrooka745ec62008-05-06 15:36:17 +00002099{
2100 if (get_osversion() >= 0x020612) {
2101 return do_rt_sigreturn_v2(env);
2102 } else {
2103 return do_rt_sigreturn_v1(env);
2104 }
2105}
2106
bellard6d5e2162004-09-30 22:04:13 +00002107#elif defined(TARGET_SPARC)
bellard80a9d032005-01-03 23:31:27 +00002108
bellard6d5e2162004-09-30 22:04:13 +00002109#define __SUNOS_MAXWIN 31
2110
2111/* This is what SunOS does, so shall I. */
2112struct target_sigcontext {
blueswir1992f48a2007-10-14 16:27:31 +00002113 abi_ulong sigc_onstack; /* state to restore */
bellard6d5e2162004-09-30 22:04:13 +00002114
blueswir1992f48a2007-10-14 16:27:31 +00002115 abi_ulong sigc_mask; /* sigmask to restore */
2116 abi_ulong sigc_sp; /* stack pointer */
2117 abi_ulong sigc_pc; /* program counter */
2118 abi_ulong sigc_npc; /* next program counter */
2119 abi_ulong sigc_psr; /* for condition codes etc */
2120 abi_ulong sigc_g1; /* User uses these two registers */
2121 abi_ulong sigc_o0; /* within the trampoline code. */
bellard6d5e2162004-09-30 22:04:13 +00002122
2123 /* Now comes information regarding the users window set
2124 * at the time of the signal.
2125 */
blueswir1992f48a2007-10-14 16:27:31 +00002126 abi_ulong sigc_oswins; /* outstanding windows */
bellard6d5e2162004-09-30 22:04:13 +00002127
2128 /* stack ptrs for each regwin buf */
2129 char *sigc_spbuf[__SUNOS_MAXWIN];
2130
2131 /* Windows to restore after signal */
2132 struct {
blueswir1992f48a2007-10-14 16:27:31 +00002133 abi_ulong locals[8];
2134 abi_ulong ins[8];
bellard6d5e2162004-09-30 22:04:13 +00002135 } sigc_wbuf[__SUNOS_MAXWIN];
2136};
2137/* A Sparc stack frame */
2138struct sparc_stackf {
blueswir1992f48a2007-10-14 16:27:31 +00002139 abi_ulong locals[8];
Peter Maydelle321c342011-02-01 15:54:52 +00002140 abi_ulong ins[8];
2141 /* It's simpler to treat fp and callers_pc as elements of ins[]
2142 * since we never need to access them ourselves.
2143 */
bellard6d5e2162004-09-30 22:04:13 +00002144 char *structptr;
blueswir1992f48a2007-10-14 16:27:31 +00002145 abi_ulong xargs[6];
2146 abi_ulong xxargs[1];
bellard6d5e2162004-09-30 22:04:13 +00002147};
2148
2149typedef struct {
2150 struct {
blueswir1992f48a2007-10-14 16:27:31 +00002151 abi_ulong psr;
2152 abi_ulong pc;
2153 abi_ulong npc;
2154 abi_ulong y;
2155 abi_ulong u_regs[16]; /* globals and ins */
bellard6d5e2162004-09-30 22:04:13 +00002156 } si_regs;
2157 int si_mask;
2158} __siginfo_t;
2159
2160typedef struct {
Blue Swirl8954bae2012-07-30 15:29:11 +00002161 abi_ulong si_float_regs[32];
bellard6d5e2162004-09-30 22:04:13 +00002162 unsigned long si_fsr;
2163 unsigned long si_fpqdepth;
2164 struct {
2165 unsigned long *insn_addr;
2166 unsigned long insn;
2167 } si_fpqueue [16];
Anthony Liguoric227f092009-10-01 16:12:16 -05002168} qemu_siginfo_fpu_t;
bellard6d5e2162004-09-30 22:04:13 +00002169
2170
2171struct target_signal_frame {
2172 struct sparc_stackf ss;
2173 __siginfo_t info;
bellardf8b0aa22007-11-11 23:03:42 +00002174 abi_ulong fpu_save;
blueswir1992f48a2007-10-14 16:27:31 +00002175 abi_ulong insns[2] __attribute__ ((aligned (8)));
2176 abi_ulong extramask[TARGET_NSIG_WORDS - 1];
2177 abi_ulong extra_size; /* Should be 0 */
Anthony Liguoric227f092009-10-01 16:12:16 -05002178 qemu_siginfo_fpu_t fpu_state;
bellard6d5e2162004-09-30 22:04:13 +00002179};
2180struct target_rt_signal_frame {
2181 struct sparc_stackf ss;
2182 siginfo_t info;
blueswir1992f48a2007-10-14 16:27:31 +00002183 abi_ulong regs[20];
bellard6d5e2162004-09-30 22:04:13 +00002184 sigset_t mask;
bellardf8b0aa22007-11-11 23:03:42 +00002185 abi_ulong fpu_save;
bellard6d5e2162004-09-30 22:04:13 +00002186 unsigned int insns[2];
2187 stack_t stack;
2188 unsigned int extra_size; /* Should be 0 */
Anthony Liguoric227f092009-10-01 16:12:16 -05002189 qemu_siginfo_fpu_t fpu_state;
bellard6d5e2162004-09-30 22:04:13 +00002190};
2191
bellarde80cfcf2004-12-19 23:18:01 +00002192#define UREG_O0 16
2193#define UREG_O6 22
2194#define UREG_I0 0
2195#define UREG_I1 1
2196#define UREG_I2 2
blueswir15bfb56b2007-10-05 17:01:51 +00002197#define UREG_I3 3
2198#define UREG_I4 4
2199#define UREG_I5 5
bellarde80cfcf2004-12-19 23:18:01 +00002200#define UREG_I6 6
2201#define UREG_I7 7
2202#define UREG_L0 8
bellard6d5e2162004-09-30 22:04:13 +00002203#define UREG_FP UREG_I6
2204#define UREG_SP UREG_O6
2205
pbrook624f7972008-05-31 16:11:38 +00002206static inline abi_ulong get_sigframe(struct target_sigaction *sa,
Andreas Färber05390242012-02-25 03:37:53 +01002207 CPUSPARCState *env,
2208 unsigned long framesize)
bellard6d5e2162004-09-30 22:04:13 +00002209{
bellard459a4012007-11-11 19:45:10 +00002210 abi_ulong sp;
bellard6d5e2162004-09-30 22:04:13 +00002211
2212 sp = env->regwptr[UREG_FP];
bellard6d5e2162004-09-30 22:04:13 +00002213
2214 /* This is the X/Open sanctioned signal stack switching. */
pbrook624f7972008-05-31 16:11:38 +00002215 if (sa->sa_flags & TARGET_SA_ONSTACK) {
thsa04e1342007-09-27 13:57:58 +00002216 if (!on_sig_stack(sp)
2217 && !((target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size) & 7))
2218 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
bellard6d5e2162004-09-30 22:04:13 +00002219 }
bellard459a4012007-11-11 19:45:10 +00002220 return sp - framesize;
bellard6d5e2162004-09-30 22:04:13 +00002221}
2222
2223static int
Andreas Färber05390242012-02-25 03:37:53 +01002224setup___siginfo(__siginfo_t *si, CPUSPARCState *env, abi_ulong mask)
bellard6d5e2162004-09-30 22:04:13 +00002225{
2226 int err = 0, i;
2227
bellard6d5e2162004-09-30 22:04:13 +00002228 err |= __put_user(env->psr, &si->si_regs.psr);
bellard6d5e2162004-09-30 22:04:13 +00002229 err |= __put_user(env->pc, &si->si_regs.pc);
2230 err |= __put_user(env->npc, &si->si_regs.npc);
2231 err |= __put_user(env->y, &si->si_regs.y);
bellarda315a142005-01-30 22:59:18 +00002232 for (i=0; i < 8; i++) {
bellard6d5e2162004-09-30 22:04:13 +00002233 err |= __put_user(env->gregs[i], &si->si_regs.u_regs[i]);
2234 }
bellarda315a142005-01-30 22:59:18 +00002235 for (i=0; i < 8; i++) {
bellarde80cfcf2004-12-19 23:18:01 +00002236 err |= __put_user(env->regwptr[UREG_I0 + i], &si->si_regs.u_regs[i+8]);
bellard6d5e2162004-09-30 22:04:13 +00002237 }
bellard6d5e2162004-09-30 22:04:13 +00002238 err |= __put_user(mask, &si->si_mask);
2239 return err;
2240}
bellarde80cfcf2004-12-19 23:18:01 +00002241
bellard80a9d032005-01-03 23:31:27 +00002242#if 0
bellard6d5e2162004-09-30 22:04:13 +00002243static int
2244setup_sigcontext(struct target_sigcontext *sc, /*struct _fpstate *fpstate,*/
Andreas Färber05390242012-02-25 03:37:53 +01002245 CPUSPARCState *env, unsigned long mask)
bellard6d5e2162004-09-30 22:04:13 +00002246{
2247 int err = 0;
2248
2249 err |= __put_user(mask, &sc->sigc_mask);
2250 err |= __put_user(env->regwptr[UREG_SP], &sc->sigc_sp);
2251 err |= __put_user(env->pc, &sc->sigc_pc);
2252 err |= __put_user(env->npc, &sc->sigc_npc);
2253 err |= __put_user(env->psr, &sc->sigc_psr);
2254 err |= __put_user(env->gregs[1], &sc->sigc_g1);
2255 err |= __put_user(env->regwptr[UREG_O0], &sc->sigc_o0);
2256
2257 return err;
2258}
bellard80a9d032005-01-03 23:31:27 +00002259#endif
bellard6d5e2162004-09-30 22:04:13 +00002260#define NF_ALIGNEDSZ (((sizeof(struct target_signal_frame) + 7) & (~7)))
2261
pbrook624f7972008-05-31 16:11:38 +00002262static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01002263 target_sigset_t *set, CPUSPARCState *env)
bellard6d5e2162004-09-30 22:04:13 +00002264{
bellard459a4012007-11-11 19:45:10 +00002265 abi_ulong sf_addr;
bellard6d5e2162004-09-30 22:04:13 +00002266 struct target_signal_frame *sf;
2267 int sigframe_size, err, i;
2268
2269 /* 1. Make sure everything is clean */
2270 //synchronize_user_stack();
2271
2272 sigframe_size = NF_ALIGNEDSZ;
bellard459a4012007-11-11 19:45:10 +00002273 sf_addr = get_sigframe(ka, env, sigframe_size);
bellard6d5e2162004-09-30 22:04:13 +00002274
bellard459a4012007-11-11 19:45:10 +00002275 sf = lock_user(VERIFY_WRITE, sf_addr,
2276 sizeof(struct target_signal_frame), 0);
2277 if (!sf)
2278 goto sigsegv;
2279
bellarde80cfcf2004-12-19 23:18:01 +00002280 //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 +00002281#if 0
2282 if (invalid_frame_pointer(sf, sigframe_size))
2283 goto sigill_and_return;
2284#endif
2285 /* 2. Save the current process state */
2286 err = setup___siginfo(&sf->info, env, set->sig[0]);
2287 err |= __put_user(0, &sf->extra_size);
2288
2289 //err |= save_fpu_state(regs, &sf->fpu_state);
2290 //err |= __put_user(&sf->fpu_state, &sf->fpu_save);
2291
2292 err |= __put_user(set->sig[0], &sf->info.si_mask);
2293 for (i = 0; i < TARGET_NSIG_WORDS - 1; i++) {
2294 err |= __put_user(set->sig[i + 1], &sf->extramask[i]);
2295 }
2296
bellarda315a142005-01-30 22:59:18 +00002297 for (i = 0; i < 8; i++) {
bellarde80cfcf2004-12-19 23:18:01 +00002298 err |= __put_user(env->regwptr[i + UREG_L0], &sf->ss.locals[i]);
bellard6d5e2162004-09-30 22:04:13 +00002299 }
bellarda315a142005-01-30 22:59:18 +00002300 for (i = 0; i < 8; i++) {
bellarde80cfcf2004-12-19 23:18:01 +00002301 err |= __put_user(env->regwptr[i + UREG_I0], &sf->ss.ins[i]);
bellard6d5e2162004-09-30 22:04:13 +00002302 }
bellard6d5e2162004-09-30 22:04:13 +00002303 if (err)
2304 goto sigsegv;
2305
2306 /* 3. signal handler back-trampoline and parameters */
bellard459a4012007-11-11 19:45:10 +00002307 env->regwptr[UREG_FP] = sf_addr;
bellard6d5e2162004-09-30 22:04:13 +00002308 env->regwptr[UREG_I0] = sig;
bellard459a4012007-11-11 19:45:10 +00002309 env->regwptr[UREG_I1] = sf_addr +
2310 offsetof(struct target_signal_frame, info);
2311 env->regwptr[UREG_I2] = sf_addr +
2312 offsetof(struct target_signal_frame, info);
bellard6d5e2162004-09-30 22:04:13 +00002313
2314 /* 4. signal handler */
pbrook624f7972008-05-31 16:11:38 +00002315 env->pc = ka->_sa_handler;
bellard6d5e2162004-09-30 22:04:13 +00002316 env->npc = (env->pc + 4);
2317 /* 5. return to kernel instructions */
pbrook624f7972008-05-31 16:11:38 +00002318 if (ka->sa_restorer)
2319 env->regwptr[UREG_I7] = ka->sa_restorer;
bellard6d5e2162004-09-30 22:04:13 +00002320 else {
bellard775b58d2007-11-11 16:22:17 +00002321 uint32_t val32;
bellard459a4012007-11-11 19:45:10 +00002322
2323 env->regwptr[UREG_I7] = sf_addr +
2324 offsetof(struct target_signal_frame, insns) - 2 * 4;
bellard6d5e2162004-09-30 22:04:13 +00002325
2326 /* mov __NR_sigreturn, %g1 */
bellard775b58d2007-11-11 16:22:17 +00002327 val32 = 0x821020d8;
2328 err |= __put_user(val32, &sf->insns[0]);
bellard6d5e2162004-09-30 22:04:13 +00002329
2330 /* t 0x10 */
bellard775b58d2007-11-11 16:22:17 +00002331 val32 = 0x91d02010;
2332 err |= __put_user(val32, &sf->insns[1]);
bellard6d5e2162004-09-30 22:04:13 +00002333 if (err)
2334 goto sigsegv;
2335
2336 /* Flush instruction space. */
2337 //flush_sig_insns(current->mm, (unsigned long) &(sf->insns[0]));
bellard80a9d032005-01-03 23:31:27 +00002338 // tb_flush(env);
bellard6d5e2162004-09-30 22:04:13 +00002339 }
bellard459a4012007-11-11 19:45:10 +00002340 unlock_user(sf, sf_addr, sizeof(struct target_signal_frame));
bellard6d5e2162004-09-30 22:04:13 +00002341 return;
bellard459a4012007-11-11 19:45:10 +00002342#if 0
2343sigill_and_return:
bellard6d5e2162004-09-30 22:04:13 +00002344 force_sig(TARGET_SIGILL);
bellard459a4012007-11-11 19:45:10 +00002345#endif
bellard6d5e2162004-09-30 22:04:13 +00002346sigsegv:
bellarde80cfcf2004-12-19 23:18:01 +00002347 //fprintf(stderr, "force_sig\n");
bellard459a4012007-11-11 19:45:10 +00002348 unlock_user(sf, sf_addr, sizeof(struct target_signal_frame));
bellard6d5e2162004-09-30 22:04:13 +00002349 force_sig(TARGET_SIGSEGV);
2350}
2351static inline int
Andreas Färber05390242012-02-25 03:37:53 +01002352restore_fpu_state(CPUSPARCState *env, qemu_siginfo_fpu_t *fpu)
bellard6d5e2162004-09-30 22:04:13 +00002353{
2354 int err;
2355#if 0
2356#ifdef CONFIG_SMP
2357 if (current->flags & PF_USEDFPU)
2358 regs->psr &= ~PSR_EF;
2359#else
2360 if (current == last_task_used_math) {
2361 last_task_used_math = 0;
2362 regs->psr &= ~PSR_EF;
2363 }
2364#endif
2365 current->used_math = 1;
2366 current->flags &= ~PF_USEDFPU;
2367#endif
2368#if 0
2369 if (verify_area (VERIFY_READ, fpu, sizeof(*fpu)))
2370 return -EFAULT;
2371#endif
2372
bellardfafffae2006-10-28 12:09:16 +00002373 /* XXX: incorrect */
Blue Swirl8954bae2012-07-30 15:29:11 +00002374 err = copy_from_user(&env->fpr[0], fpu->si_float_regs[0],
2375 (sizeof(abi_ulong) * 32));
bellard6d5e2162004-09-30 22:04:13 +00002376 err |= __get_user(env->fsr, &fpu->si_fsr);
2377#if 0
2378 err |= __get_user(current->thread.fpqdepth, &fpu->si_fpqdepth);
2379 if (current->thread.fpqdepth != 0)
2380 err |= __copy_from_user(&current->thread.fpqueue[0],
2381 &fpu->si_fpqueue[0],
2382 ((sizeof(unsigned long) +
2383 (sizeof(unsigned long *)))*16));
2384#endif
2385 return err;
2386}
2387
2388
pbrook624f7972008-05-31 16:11:38 +00002389static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05002390 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01002391 target_sigset_t *set, CPUSPARCState *env)
bellard6d5e2162004-09-30 22:04:13 +00002392{
2393 fprintf(stderr, "setup_rt_frame: not implemented\n");
2394}
2395
Andreas Färber05390242012-02-25 03:37:53 +01002396long do_sigreturn(CPUSPARCState *env)
bellard6d5e2162004-09-30 22:04:13 +00002397{
bellardf8b0aa22007-11-11 23:03:42 +00002398 abi_ulong sf_addr;
bellard6d5e2162004-09-30 22:04:13 +00002399 struct target_signal_frame *sf;
bellarde80cfcf2004-12-19 23:18:01 +00002400 uint32_t up_psr, pc, npc;
Anthony Liguoric227f092009-10-01 16:12:16 -05002401 target_sigset_t set;
bellarde80cfcf2004-12-19 23:18:01 +00002402 sigset_t host_set;
bellarde80cfcf2004-12-19 23:18:01 +00002403 int err, i;
bellard6d5e2162004-09-30 22:04:13 +00002404
bellardf8b0aa22007-11-11 23:03:42 +00002405 sf_addr = env->regwptr[UREG_FP];
2406 if (!lock_user_struct(VERIFY_READ, sf, sf_addr, 1))
2407 goto segv_and_exit;
bellard80a9d032005-01-03 23:31:27 +00002408#if 0
bellarde80cfcf2004-12-19 23:18:01 +00002409 fprintf(stderr, "sigreturn\n");
2410 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 +00002411#endif
bellarde80cfcf2004-12-19 23:18:01 +00002412 //cpu_dump_state(env, stderr, fprintf, 0);
bellard6d5e2162004-09-30 22:04:13 +00002413
2414 /* 1. Make sure we are not getting garbage from the user */
bellard6d5e2162004-09-30 22:04:13 +00002415
bellardf8b0aa22007-11-11 23:03:42 +00002416 if (sf_addr & 3)
bellard6d5e2162004-09-30 22:04:13 +00002417 goto segv_and_exit;
2418
2419 err = __get_user(pc, &sf->info.si_regs.pc);
2420 err |= __get_user(npc, &sf->info.si_regs.npc);
2421
bellard6d5e2162004-09-30 22:04:13 +00002422 if ((pc | npc) & 3)
2423 goto segv_and_exit;
2424
2425 /* 2. Restore the state */
bellarde80cfcf2004-12-19 23:18:01 +00002426 err |= __get_user(up_psr, &sf->info.si_regs.psr);
2427
bellard6d5e2162004-09-30 22:04:13 +00002428 /* User can only change condition codes and FPU enabling in %psr. */
bellarda315a142005-01-30 22:59:18 +00002429 env->psr = (up_psr & (PSR_ICC /* | PSR_EF */))
2430 | (env->psr & ~(PSR_ICC /* | PSR_EF */));
2431
2432 env->pc = pc;
2433 env->npc = npc;
bellarde80cfcf2004-12-19 23:18:01 +00002434 err |= __get_user(env->y, &sf->info.si_regs.y);
bellarda315a142005-01-30 22:59:18 +00002435 for (i=0; i < 8; i++) {
bellarde80cfcf2004-12-19 23:18:01 +00002436 err |= __get_user(env->gregs[i], &sf->info.si_regs.u_regs[i]);
2437 }
bellarda315a142005-01-30 22:59:18 +00002438 for (i=0; i < 8; i++) {
bellarde80cfcf2004-12-19 23:18:01 +00002439 err |= __get_user(env->regwptr[i + UREG_I0], &sf->info.si_regs.u_regs[i+8]);
2440 }
bellard6d5e2162004-09-30 22:04:13 +00002441
Peter Maydell2aec3a22011-06-16 17:37:14 +01002442 /* FIXME: implement FPU save/restore:
2443 * __get_user(fpu_save, &sf->fpu_save);
2444 * if (fpu_save)
2445 * err |= restore_fpu_state(env, fpu_save);
2446 */
bellard6d5e2162004-09-30 22:04:13 +00002447
2448 /* This is pretty much atomic, no amount locking would prevent
2449 * the races which exist anyways.
2450 */
2451 err |= __get_user(set.sig[0], &sf->info.si_mask);
bellarde80cfcf2004-12-19 23:18:01 +00002452 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
2453 err |= (__get_user(set.sig[i], &sf->extramask[i - 1]));
2454 }
2455
2456 target_to_host_sigset_internal(&host_set, &set);
Alex Barcelo1c275922014-03-14 14:36:55 +00002457 do_sigprocmask(SIG_SETMASK, &host_set, NULL);
bellard6d5e2162004-09-30 22:04:13 +00002458
2459 if (err)
2460 goto segv_and_exit;
bellardf8b0aa22007-11-11 23:03:42 +00002461 unlock_user_struct(sf, sf_addr, 0);
bellard6d5e2162004-09-30 22:04:13 +00002462 return env->regwptr[0];
2463
2464segv_and_exit:
bellardf8b0aa22007-11-11 23:03:42 +00002465 unlock_user_struct(sf, sf_addr, 0);
bellard6d5e2162004-09-30 22:04:13 +00002466 force_sig(TARGET_SIGSEGV);
2467}
2468
Andreas Färber05390242012-02-25 03:37:53 +01002469long do_rt_sigreturn(CPUSPARCState *env)
bellard6d5e2162004-09-30 22:04:13 +00002470{
2471 fprintf(stderr, "do_rt_sigreturn: not implemented\n");
bellardf8b0aa22007-11-11 23:03:42 +00002472 return -TARGET_ENOSYS;
bellard6d5e2162004-09-30 22:04:13 +00002473}
2474
bellard459a4012007-11-11 19:45:10 +00002475#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
blueswir15bfb56b2007-10-05 17:01:51 +00002476#define MC_TSTATE 0
2477#define MC_PC 1
2478#define MC_NPC 2
2479#define MC_Y 3
2480#define MC_G1 4
2481#define MC_G2 5
2482#define MC_G3 6
2483#define MC_G4 7
2484#define MC_G5 8
2485#define MC_G6 9
2486#define MC_G7 10
2487#define MC_O0 11
2488#define MC_O1 12
2489#define MC_O2 13
2490#define MC_O3 14
2491#define MC_O4 15
2492#define MC_O5 16
2493#define MC_O6 17
2494#define MC_O7 18
2495#define MC_NGREG 19
2496
Anthony Liguoric227f092009-10-01 16:12:16 -05002497typedef abi_ulong target_mc_greg_t;
2498typedef target_mc_greg_t target_mc_gregset_t[MC_NGREG];
blueswir15bfb56b2007-10-05 17:01:51 +00002499
2500struct target_mc_fq {
blueswir1992f48a2007-10-14 16:27:31 +00002501 abi_ulong *mcfq_addr;
blueswir15bfb56b2007-10-05 17:01:51 +00002502 uint32_t mcfq_insn;
2503};
2504
2505struct target_mc_fpu {
2506 union {
2507 uint32_t sregs[32];
2508 uint64_t dregs[32];
2509 //uint128_t qregs[16];
2510 } mcfpu_fregs;
blueswir1992f48a2007-10-14 16:27:31 +00002511 abi_ulong mcfpu_fsr;
2512 abi_ulong mcfpu_fprs;
2513 abi_ulong mcfpu_gsr;
blueswir15bfb56b2007-10-05 17:01:51 +00002514 struct target_mc_fq *mcfpu_fq;
2515 unsigned char mcfpu_qcnt;
2516 unsigned char mcfpu_qentsz;
2517 unsigned char mcfpu_enab;
2518};
Anthony Liguoric227f092009-10-01 16:12:16 -05002519typedef struct target_mc_fpu target_mc_fpu_t;
blueswir15bfb56b2007-10-05 17:01:51 +00002520
2521typedef struct {
Anthony Liguoric227f092009-10-01 16:12:16 -05002522 target_mc_gregset_t mc_gregs;
2523 target_mc_greg_t mc_fp;
2524 target_mc_greg_t mc_i7;
2525 target_mc_fpu_t mc_fpregs;
2526} target_mcontext_t;
blueswir15bfb56b2007-10-05 17:01:51 +00002527
2528struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02002529 struct target_ucontext *tuc_link;
2530 abi_ulong tuc_flags;
2531 target_sigset_t tuc_sigmask;
2532 target_mcontext_t tuc_mcontext;
blueswir15bfb56b2007-10-05 17:01:51 +00002533};
2534
2535/* A V9 register window */
2536struct target_reg_window {
blueswir1992f48a2007-10-14 16:27:31 +00002537 abi_ulong locals[8];
2538 abi_ulong ins[8];
blueswir15bfb56b2007-10-05 17:01:51 +00002539};
2540
2541#define TARGET_STACK_BIAS 2047
2542
2543/* {set, get}context() needed for 64-bit SparcLinux userland. */
2544void sparc64_set_context(CPUSPARCState *env)
2545{
bellard459a4012007-11-11 19:45:10 +00002546 abi_ulong ucp_addr;
2547 struct target_ucontext *ucp;
Anthony Liguoric227f092009-10-01 16:12:16 -05002548 target_mc_gregset_t *grp;
blueswir1992f48a2007-10-14 16:27:31 +00002549 abi_ulong pc, npc, tstate;
bellard459a4012007-11-11 19:45:10 +00002550 abi_ulong fp, i7, w_addr;
blueswir15bfb56b2007-10-05 17:01:51 +00002551 int err;
2552 unsigned int i;
blueswir15bfb56b2007-10-05 17:01:51 +00002553
bellard459a4012007-11-11 19:45:10 +00002554 ucp_addr = env->regwptr[UREG_I0];
2555 if (!lock_user_struct(VERIFY_READ, ucp, ucp_addr, 1))
2556 goto do_sigsegv;
Aurelien Jarno60e99242010-03-29 02:12:51 +02002557 grp = &ucp->tuc_mcontext.mc_gregs;
bellard579a97f2007-11-11 14:26:47 +00002558 err = __get_user(pc, &((*grp)[MC_PC]));
2559 err |= __get_user(npc, &((*grp)[MC_NPC]));
blueswir15bfb56b2007-10-05 17:01:51 +00002560 if (err || ((pc | npc) & 3))
2561 goto do_sigsegv;
2562 if (env->regwptr[UREG_I1]) {
Anthony Liguoric227f092009-10-01 16:12:16 -05002563 target_sigset_t target_set;
blueswir15bfb56b2007-10-05 17:01:51 +00002564 sigset_t set;
2565
2566 if (TARGET_NSIG_WORDS == 1) {
Aurelien Jarno60e99242010-03-29 02:12:51 +02002567 if (__get_user(target_set.sig[0], &ucp->tuc_sigmask.sig[0]))
blueswir15bfb56b2007-10-05 17:01:51 +00002568 goto do_sigsegv;
2569 } else {
bellard459a4012007-11-11 19:45:10 +00002570 abi_ulong *src, *dst;
Aurelien Jarno60e99242010-03-29 02:12:51 +02002571 src = ucp->tuc_sigmask.sig;
bellard459a4012007-11-11 19:45:10 +00002572 dst = target_set.sig;
Stefan Weil0d9e61c2013-12-07 14:48:08 +01002573 for (i = 0; i < TARGET_NSIG_WORDS; i++, dst++, src++) {
bellard459a4012007-11-11 19:45:10 +00002574 err |= __get_user(*dst, src);
Stefan Weil0d9e61c2013-12-07 14:48:08 +01002575 }
blueswir15bfb56b2007-10-05 17:01:51 +00002576 if (err)
2577 goto do_sigsegv;
2578 }
2579 target_to_host_sigset_internal(&set, &target_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00002580 do_sigprocmask(SIG_SETMASK, &set, NULL);
blueswir15bfb56b2007-10-05 17:01:51 +00002581 }
2582 env->pc = pc;
2583 env->npc = npc;
bellard579a97f2007-11-11 14:26:47 +00002584 err |= __get_user(env->y, &((*grp)[MC_Y]));
2585 err |= __get_user(tstate, &((*grp)[MC_TSTATE]));
blueswir15bfb56b2007-10-05 17:01:51 +00002586 env->asi = (tstate >> 24) & 0xff;
Blue Swirl5a834bb2010-05-09 20:19:04 +00002587 cpu_put_ccr(env, tstate >> 32);
2588 cpu_put_cwp64(env, tstate & 0x1f);
bellard579a97f2007-11-11 14:26:47 +00002589 err |= __get_user(env->gregs[1], (&(*grp)[MC_G1]));
2590 err |= __get_user(env->gregs[2], (&(*grp)[MC_G2]));
2591 err |= __get_user(env->gregs[3], (&(*grp)[MC_G3]));
2592 err |= __get_user(env->gregs[4], (&(*grp)[MC_G4]));
2593 err |= __get_user(env->gregs[5], (&(*grp)[MC_G5]));
2594 err |= __get_user(env->gregs[6], (&(*grp)[MC_G6]));
2595 err |= __get_user(env->gregs[7], (&(*grp)[MC_G7]));
2596 err |= __get_user(env->regwptr[UREG_I0], (&(*grp)[MC_O0]));
2597 err |= __get_user(env->regwptr[UREG_I1], (&(*grp)[MC_O1]));
2598 err |= __get_user(env->regwptr[UREG_I2], (&(*grp)[MC_O2]));
2599 err |= __get_user(env->regwptr[UREG_I3], (&(*grp)[MC_O3]));
2600 err |= __get_user(env->regwptr[UREG_I4], (&(*grp)[MC_O4]));
2601 err |= __get_user(env->regwptr[UREG_I5], (&(*grp)[MC_O5]));
2602 err |= __get_user(env->regwptr[UREG_I6], (&(*grp)[MC_O6]));
2603 err |= __get_user(env->regwptr[UREG_I7], (&(*grp)[MC_O7]));
blueswir15bfb56b2007-10-05 17:01:51 +00002604
Aurelien Jarno60e99242010-03-29 02:12:51 +02002605 err |= __get_user(fp, &(ucp->tuc_mcontext.mc_fp));
2606 err |= __get_user(i7, &(ucp->tuc_mcontext.mc_i7));
blueswir15bfb56b2007-10-05 17:01:51 +00002607
bellard459a4012007-11-11 19:45:10 +00002608 w_addr = TARGET_STACK_BIAS+env->regwptr[UREG_I6];
2609 if (put_user(fp, w_addr + offsetof(struct target_reg_window, ins[6]),
2610 abi_ulong) != 0)
2611 goto do_sigsegv;
2612 if (put_user(i7, w_addr + offsetof(struct target_reg_window, ins[7]),
2613 abi_ulong) != 0)
2614 goto do_sigsegv;
Peter Maydellc7b016b2011-06-16 17:37:15 +01002615 /* FIXME this does not match how the kernel handles the FPU in
2616 * its sparc64_set_context implementation. In particular the FPU
2617 * is only restored if fenab is non-zero in:
2618 * __get_user(fenab, &(ucp->tuc_mcontext.mc_fpregs.mcfpu_enab));
2619 */
Aurelien Jarno60e99242010-03-29 02:12:51 +02002620 err |= __get_user(env->fprs, &(ucp->tuc_mcontext.mc_fpregs.mcfpu_fprs));
bellard459a4012007-11-11 19:45:10 +00002621 {
Richard Henderson30038fd2011-10-17 10:42:49 -07002622 uint32_t *src = ucp->tuc_mcontext.mc_fpregs.mcfpu_fregs.sregs;
2623 for (i = 0; i < 64; i++, src++) {
2624 if (i & 1) {
2625 err |= __get_user(env->fpr[i/2].l.lower, src);
2626 } else {
2627 err |= __get_user(env->fpr[i/2].l.upper, src);
2628 }
2629 }
bellard459a4012007-11-11 19:45:10 +00002630 }
bellard579a97f2007-11-11 14:26:47 +00002631 err |= __get_user(env->fsr,
Aurelien Jarno60e99242010-03-29 02:12:51 +02002632 &(ucp->tuc_mcontext.mc_fpregs.mcfpu_fsr));
bellard579a97f2007-11-11 14:26:47 +00002633 err |= __get_user(env->gsr,
Aurelien Jarno60e99242010-03-29 02:12:51 +02002634 &(ucp->tuc_mcontext.mc_fpregs.mcfpu_gsr));
blueswir15bfb56b2007-10-05 17:01:51 +00002635 if (err)
2636 goto do_sigsegv;
bellard459a4012007-11-11 19:45:10 +00002637 unlock_user_struct(ucp, ucp_addr, 0);
blueswir15bfb56b2007-10-05 17:01:51 +00002638 return;
2639 do_sigsegv:
bellard459a4012007-11-11 19:45:10 +00002640 unlock_user_struct(ucp, ucp_addr, 0);
Riku Voipio66393fb2009-12-04 15:16:32 +02002641 force_sig(TARGET_SIGSEGV);
blueswir15bfb56b2007-10-05 17:01:51 +00002642}
2643
2644void sparc64_get_context(CPUSPARCState *env)
2645{
bellard459a4012007-11-11 19:45:10 +00002646 abi_ulong ucp_addr;
2647 struct target_ucontext *ucp;
Anthony Liguoric227f092009-10-01 16:12:16 -05002648 target_mc_gregset_t *grp;
2649 target_mcontext_t *mcp;
bellard459a4012007-11-11 19:45:10 +00002650 abi_ulong fp, i7, w_addr;
blueswir15bfb56b2007-10-05 17:01:51 +00002651 int err;
2652 unsigned int i;
Anthony Liguoric227f092009-10-01 16:12:16 -05002653 target_sigset_t target_set;
blueswir15bfb56b2007-10-05 17:01:51 +00002654 sigset_t set;
2655
bellard459a4012007-11-11 19:45:10 +00002656 ucp_addr = env->regwptr[UREG_I0];
2657 if (!lock_user_struct(VERIFY_WRITE, ucp, ucp_addr, 0))
2658 goto do_sigsegv;
2659
Aurelien Jarno60e99242010-03-29 02:12:51 +02002660 mcp = &ucp->tuc_mcontext;
blueswir15bfb56b2007-10-05 17:01:51 +00002661 grp = &mcp->mc_gregs;
2662
2663 /* Skip over the trap instruction, first. */
2664 env->pc = env->npc;
2665 env->npc += 4;
2666
2667 err = 0;
2668
Alex Barcelo1c275922014-03-14 14:36:55 +00002669 do_sigprocmask(0, NULL, &set);
blueswir15bfb56b2007-10-05 17:01:51 +00002670 host_to_target_sigset_internal(&target_set, &set);
bellard459a4012007-11-11 19:45:10 +00002671 if (TARGET_NSIG_WORDS == 1) {
bellard579a97f2007-11-11 14:26:47 +00002672 err |= __put_user(target_set.sig[0],
Aurelien Jarno60e99242010-03-29 02:12:51 +02002673 (abi_ulong *)&ucp->tuc_sigmask);
bellard459a4012007-11-11 19:45:10 +00002674 } else {
2675 abi_ulong *src, *dst;
2676 src = target_set.sig;
Aurelien Jarno60e99242010-03-29 02:12:51 +02002677 dst = ucp->tuc_sigmask.sig;
Stefan Weil0d9e61c2013-12-07 14:48:08 +01002678 for (i = 0; i < TARGET_NSIG_WORDS; i++, dst++, src++) {
bellard459a4012007-11-11 19:45:10 +00002679 err |= __put_user(*src, dst);
Stefan Weil0d9e61c2013-12-07 14:48:08 +01002680 }
blueswir15bfb56b2007-10-05 17:01:51 +00002681 if (err)
2682 goto do_sigsegv;
2683 }
2684
bellard459a4012007-11-11 19:45:10 +00002685 /* XXX: tstate must be saved properly */
2686 // err |= __put_user(env->tstate, &((*grp)[MC_TSTATE]));
bellard579a97f2007-11-11 14:26:47 +00002687 err |= __put_user(env->pc, &((*grp)[MC_PC]));
2688 err |= __put_user(env->npc, &((*grp)[MC_NPC]));
2689 err |= __put_user(env->y, &((*grp)[MC_Y]));
2690 err |= __put_user(env->gregs[1], &((*grp)[MC_G1]));
2691 err |= __put_user(env->gregs[2], &((*grp)[MC_G2]));
2692 err |= __put_user(env->gregs[3], &((*grp)[MC_G3]));
2693 err |= __put_user(env->gregs[4], &((*grp)[MC_G4]));
2694 err |= __put_user(env->gregs[5], &((*grp)[MC_G5]));
2695 err |= __put_user(env->gregs[6], &((*grp)[MC_G6]));
2696 err |= __put_user(env->gregs[7], &((*grp)[MC_G7]));
2697 err |= __put_user(env->regwptr[UREG_I0], &((*grp)[MC_O0]));
2698 err |= __put_user(env->regwptr[UREG_I1], &((*grp)[MC_O1]));
2699 err |= __put_user(env->regwptr[UREG_I2], &((*grp)[MC_O2]));
2700 err |= __put_user(env->regwptr[UREG_I3], &((*grp)[MC_O3]));
2701 err |= __put_user(env->regwptr[UREG_I4], &((*grp)[MC_O4]));
2702 err |= __put_user(env->regwptr[UREG_I5], &((*grp)[MC_O5]));
2703 err |= __put_user(env->regwptr[UREG_I6], &((*grp)[MC_O6]));
2704 err |= __put_user(env->regwptr[UREG_I7], &((*grp)[MC_O7]));
blueswir15bfb56b2007-10-05 17:01:51 +00002705
bellard459a4012007-11-11 19:45:10 +00002706 w_addr = TARGET_STACK_BIAS+env->regwptr[UREG_I6];
2707 fp = i7 = 0;
2708 if (get_user(fp, w_addr + offsetof(struct target_reg_window, ins[6]),
2709 abi_ulong) != 0)
2710 goto do_sigsegv;
2711 if (get_user(i7, w_addr + offsetof(struct target_reg_window, ins[7]),
2712 abi_ulong) != 0)
2713 goto do_sigsegv;
bellard579a97f2007-11-11 14:26:47 +00002714 err |= __put_user(fp, &(mcp->mc_fp));
2715 err |= __put_user(i7, &(mcp->mc_i7));
blueswir15bfb56b2007-10-05 17:01:51 +00002716
bellard459a4012007-11-11 19:45:10 +00002717 {
Richard Henderson30038fd2011-10-17 10:42:49 -07002718 uint32_t *dst = ucp->tuc_mcontext.mc_fpregs.mcfpu_fregs.sregs;
2719 for (i = 0; i < 64; i++, dst++) {
2720 if (i & 1) {
2721 err |= __put_user(env->fpr[i/2].l.lower, dst);
2722 } else {
2723 err |= __put_user(env->fpr[i/2].l.upper, dst);
2724 }
2725 }
bellard459a4012007-11-11 19:45:10 +00002726 }
bellard579a97f2007-11-11 14:26:47 +00002727 err |= __put_user(env->fsr, &(mcp->mc_fpregs.mcfpu_fsr));
2728 err |= __put_user(env->gsr, &(mcp->mc_fpregs.mcfpu_gsr));
2729 err |= __put_user(env->fprs, &(mcp->mc_fpregs.mcfpu_fprs));
blueswir15bfb56b2007-10-05 17:01:51 +00002730
2731 if (err)
2732 goto do_sigsegv;
bellard459a4012007-11-11 19:45:10 +00002733 unlock_user_struct(ucp, ucp_addr, 1);
blueswir15bfb56b2007-10-05 17:01:51 +00002734 return;
2735 do_sigsegv:
bellard459a4012007-11-11 19:45:10 +00002736 unlock_user_struct(ucp, ucp_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02002737 force_sig(TARGET_SIGSEGV);
blueswir15bfb56b2007-10-05 17:01:51 +00002738}
2739#endif
Richard Hendersonff970902013-02-10 10:30:42 -08002740#elif defined(TARGET_MIPS) || defined(TARGET_MIPS64)
bellard106ec872006-06-27 21:08:10 +00002741
Richard Hendersonff970902013-02-10 10:30:42 -08002742# if defined(TARGET_ABI_MIPSO32)
bellard106ec872006-06-27 21:08:10 +00002743struct target_sigcontext {
2744 uint32_t sc_regmask; /* Unused */
2745 uint32_t sc_status;
2746 uint64_t sc_pc;
2747 uint64_t sc_regs[32];
2748 uint64_t sc_fpregs[32];
2749 uint32_t sc_ownedfp; /* Unused */
2750 uint32_t sc_fpc_csr;
2751 uint32_t sc_fpc_eir; /* Unused */
2752 uint32_t sc_used_math;
2753 uint32_t sc_dsp; /* dsp status, was sc_ssflags */
Paul Brook94c54952009-07-09 18:40:15 +01002754 uint32_t pad0;
bellard106ec872006-06-27 21:08:10 +00002755 uint64_t sc_mdhi;
2756 uint64_t sc_mdlo;
2757 target_ulong sc_hi1; /* Was sc_cause */
2758 target_ulong sc_lo1; /* Was sc_badvaddr */
2759 target_ulong sc_hi2; /* Was sc_sigset[4] */
2760 target_ulong sc_lo2;
2761 target_ulong sc_hi3;
2762 target_ulong sc_lo3;
2763};
Richard Hendersonff970902013-02-10 10:30:42 -08002764# else /* N32 || N64 */
2765struct target_sigcontext {
2766 uint64_t sc_regs[32];
2767 uint64_t sc_fpregs[32];
2768 uint64_t sc_mdhi;
2769 uint64_t sc_hi1;
2770 uint64_t sc_hi2;
2771 uint64_t sc_hi3;
2772 uint64_t sc_mdlo;
2773 uint64_t sc_lo1;
2774 uint64_t sc_lo2;
2775 uint64_t sc_lo3;
2776 uint64_t sc_pc;
2777 uint32_t sc_fpc_csr;
2778 uint32_t sc_used_math;
2779 uint32_t sc_dsp;
2780 uint32_t sc_reserved;
2781};
2782# endif /* O32 */
bellard106ec872006-06-27 21:08:10 +00002783
2784struct sigframe {
2785 uint32_t sf_ass[4]; /* argument save space for o32 */
2786 uint32_t sf_code[2]; /* signal trampoline */
2787 struct target_sigcontext sf_sc;
Anthony Liguoric227f092009-10-01 16:12:16 -05002788 target_sigset_t sf_mask;
bellard106ec872006-06-27 21:08:10 +00002789};
2790
pbrook0b1bcb02009-04-21 01:41:10 +00002791struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02002792 target_ulong tuc_flags;
2793 target_ulong tuc_link;
2794 target_stack_t tuc_stack;
Paul Brook94c54952009-07-09 18:40:15 +01002795 target_ulong pad0;
Aurelien Jarno60e99242010-03-29 02:12:51 +02002796 struct target_sigcontext tuc_mcontext;
2797 target_sigset_t tuc_sigmask;
pbrook0b1bcb02009-04-21 01:41:10 +00002798};
2799
2800struct target_rt_sigframe {
2801 uint32_t rs_ass[4]; /* argument save space for o32 */
2802 uint32_t rs_code[2]; /* signal trampoline */
2803 struct target_siginfo rs_info;
2804 struct target_ucontext rs_uc;
2805};
2806
bellard106ec872006-06-27 21:08:10 +00002807/* Install trampoline to jump back from signal handler */
2808static inline int install_sigtramp(unsigned int *tramp, unsigned int syscall)
2809{
Richard Henderson084d0492013-02-10 10:30:44 -08002810 int err = 0;
bellard106ec872006-06-27 21:08:10 +00002811
2812 /*
Richard Henderson084d0492013-02-10 10:30:44 -08002813 * Set up the return code ...
2814 *
2815 * li v0, __NR__foo_sigreturn
2816 * syscall
2817 */
bellard106ec872006-06-27 21:08:10 +00002818
Richard Henderson084d0492013-02-10 10:30:44 -08002819 err |= __put_user(0x24020000 + syscall, tramp + 0);
bellard106ec872006-06-27 21:08:10 +00002820 err |= __put_user(0x0000000c , tramp + 1);
bellard106ec872006-06-27 21:08:10 +00002821 return err;
2822}
2823
2824static inline int
Andreas Färber05390242012-02-25 03:37:53 +01002825setup_sigcontext(CPUMIPSState *regs, struct target_sigcontext *sc)
bellard106ec872006-06-27 21:08:10 +00002826{
2827 int err = 0;
Richard Henderson084d0492013-02-10 10:30:44 -08002828 int i;
bellard106ec872006-06-27 21:08:10 +00002829
Kwok Cheung Yeung1239b472013-05-17 14:51:21 -07002830 err |= __put_user(exception_resume_pc(regs), &sc->sc_pc);
2831 regs->hflags &= ~MIPS_HFLAG_BMASK;
bellard106ec872006-06-27 21:08:10 +00002832
Richard Henderson084d0492013-02-10 10:30:44 -08002833 __put_user(0, &sc->sc_regs[0]);
2834 for (i = 1; i < 32; ++i) {
2835 err |= __put_user(regs->active_tc.gpr[i], &sc->sc_regs[i]);
2836 }
bellard106ec872006-06-27 21:08:10 +00002837
thsb5dc7732008-06-27 10:02:35 +00002838 err |= __put_user(regs->active_tc.HI[0], &sc->sc_mdhi);
2839 err |= __put_user(regs->active_tc.LO[0], &sc->sc_mdlo);
bellard106ec872006-06-27 21:08:10 +00002840
Richard Henderson084d0492013-02-10 10:30:44 -08002841 /* Rather than checking for dsp existence, always copy. The storage
2842 would just be garbage otherwise. */
2843 err |= __put_user(regs->active_tc.HI[1], &sc->sc_hi1);
2844 err |= __put_user(regs->active_tc.HI[2], &sc->sc_hi2);
2845 err |= __put_user(regs->active_tc.HI[3], &sc->sc_hi3);
2846 err |= __put_user(regs->active_tc.LO[1], &sc->sc_lo1);
2847 err |= __put_user(regs->active_tc.LO[2], &sc->sc_lo2);
2848 err |= __put_user(regs->active_tc.LO[3], &sc->sc_lo3);
2849 {
2850 uint32_t dsp = cpu_rddsp(0x3ff, regs);
2851 err |= __put_user(dsp, &sc->sc_dsp);
bellard106ec872006-06-27 21:08:10 +00002852 }
Richard Henderson084d0492013-02-10 10:30:44 -08002853
2854 err |= __put_user(1, &sc->sc_used_math);
2855
2856 for (i = 0; i < 32; ++i) {
2857 err |= __put_user(regs->active_fpu.fpr[i].d, &sc->sc_fpregs[i]);
bellard106ec872006-06-27 21:08:10 +00002858 }
bellard106ec872006-06-27 21:08:10 +00002859
bellard106ec872006-06-27 21:08:10 +00002860 return err;
2861}
2862
2863static inline int
Andreas Färber05390242012-02-25 03:37:53 +01002864restore_sigcontext(CPUMIPSState *regs, struct target_sigcontext *sc)
bellard106ec872006-06-27 21:08:10 +00002865{
2866 int err = 0;
Richard Henderson084d0492013-02-10 10:30:44 -08002867 int i;
bellard106ec872006-06-27 21:08:10 +00002868
2869 err |= __get_user(regs->CP0_EPC, &sc->sc_pc);
2870
thsb5dc7732008-06-27 10:02:35 +00002871 err |= __get_user(regs->active_tc.HI[0], &sc->sc_mdhi);
2872 err |= __get_user(regs->active_tc.LO[0], &sc->sc_mdlo);
bellard106ec872006-06-27 21:08:10 +00002873
Richard Henderson084d0492013-02-10 10:30:44 -08002874 for (i = 1; i < 32; ++i) {
2875 err |= __get_user(regs->active_tc.gpr[i], &sc->sc_regs[i]);
bellard106ec872006-06-27 21:08:10 +00002876 }
2877
Richard Henderson084d0492013-02-10 10:30:44 -08002878 err |= __get_user(regs->active_tc.HI[1], &sc->sc_hi1);
2879 err |= __get_user(regs->active_tc.HI[2], &sc->sc_hi2);
2880 err |= __get_user(regs->active_tc.HI[3], &sc->sc_hi3);
2881 err |= __get_user(regs->active_tc.LO[1], &sc->sc_lo1);
2882 err |= __get_user(regs->active_tc.LO[2], &sc->sc_lo2);
2883 err |= __get_user(regs->active_tc.LO[3], &sc->sc_lo3);
2884 {
2885 uint32_t dsp;
2886 err |= __get_user(dsp, &sc->sc_dsp);
2887 cpu_wrdsp(dsp, 0x3ff, regs);
2888 }
2889
2890 for (i = 0; i < 32; ++i) {
2891 err |= __get_user(regs->active_fpu.fpr[i].d, &sc->sc_fpregs[i]);
2892 }
2893
bellard106ec872006-06-27 21:08:10 +00002894 return err;
2895}
Richard Hendersonff970902013-02-10 10:30:42 -08002896
bellard106ec872006-06-27 21:08:10 +00002897/*
2898 * Determine which stack to use..
2899 */
bellard579a97f2007-11-11 14:26:47 +00002900static inline abi_ulong
Andreas Färber05390242012-02-25 03:37:53 +01002901get_sigframe(struct target_sigaction *ka, CPUMIPSState *regs, size_t frame_size)
bellard106ec872006-06-27 21:08:10 +00002902{
2903 unsigned long sp;
2904
2905 /* Default to using normal stack */
thsb5dc7732008-06-27 10:02:35 +00002906 sp = regs->active_tc.gpr[29];
bellard106ec872006-06-27 21:08:10 +00002907
2908 /*
Stefan Weil93148aa2012-02-26 18:46:12 +01002909 * FPU emulator may have its own trampoline active just
bellard106ec872006-06-27 21:08:10 +00002910 * above the user stack, 16-bytes before the next lowest
2911 * 16 byte boundary. Try to avoid trashing it.
2912 */
2913 sp -= 32;
2914
bellard106ec872006-06-27 21:08:10 +00002915 /* This is the X/Open sanctioned signal stack switching. */
pbrook624f7972008-05-31 16:11:38 +00002916 if ((ka->sa_flags & TARGET_SA_ONSTACK) && (sas_ss_flags (sp) == 0)) {
thsa04e1342007-09-27 13:57:58 +00002917 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
2918 }
bellard106ec872006-06-27 21:08:10 +00002919
bellard579a97f2007-11-11 14:26:47 +00002920 return (sp - frame_size) & ~7;
bellard106ec872006-06-27 21:08:10 +00002921}
2922
Kwok Cheung Yeungea3164a2013-05-17 14:51:20 -07002923static void mips_set_hflags_isa_mode_from_pc(CPUMIPSState *env)
2924{
2925 if (env->insn_flags & (ASE_MIPS16 | ASE_MICROMIPS)) {
2926 env->hflags &= ~MIPS_HFLAG_M16;
2927 env->hflags |= (env->active_tc.PC & 1) << MIPS_HFLAG_M16_SHIFT;
2928 env->active_tc.PC &= ~(target_ulong) 1;
2929 }
2930}
2931
Richard Hendersonff970902013-02-10 10:30:42 -08002932# if defined(TARGET_ABI_MIPSO32)
bellard579a97f2007-11-11 14:26:47 +00002933/* compare linux/arch/mips/kernel/signal.c:setup_frame() */
pbrook624f7972008-05-31 16:11:38 +00002934static void setup_frame(int sig, struct target_sigaction * ka,
Andreas Färber05390242012-02-25 03:37:53 +01002935 target_sigset_t *set, CPUMIPSState *regs)
bellard106ec872006-06-27 21:08:10 +00002936{
2937 struct sigframe *frame;
bellard579a97f2007-11-11 14:26:47 +00002938 abi_ulong frame_addr;
bellard106ec872006-06-27 21:08:10 +00002939 int i;
2940
bellard579a97f2007-11-11 14:26:47 +00002941 frame_addr = get_sigframe(ka, regs, sizeof(*frame));
2942 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
bellard106ec872006-06-27 21:08:10 +00002943 goto give_sigsegv;
2944
2945 install_sigtramp(frame->sf_code, TARGET_NR_sigreturn);
2946
2947 if(setup_sigcontext(regs, &frame->sf_sc))
2948 goto give_sigsegv;
2949
2950 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
2951 if(__put_user(set->sig[i], &frame->sf_mask.sig[i]))
2952 goto give_sigsegv;
2953 }
2954
2955 /*
2956 * Arguments to signal handler:
2957 *
2958 * a0 = signal number
2959 * a1 = 0 (should be cause)
2960 * a2 = pointer to struct sigcontext
2961 *
2962 * $25 and PC point to the signal handler, $29 points to the
2963 * struct sigframe.
2964 */
thsb5dc7732008-06-27 10:02:35 +00002965 regs->active_tc.gpr[ 4] = sig;
2966 regs->active_tc.gpr[ 5] = 0;
2967 regs->active_tc.gpr[ 6] = frame_addr + offsetof(struct sigframe, sf_sc);
2968 regs->active_tc.gpr[29] = frame_addr;
2969 regs->active_tc.gpr[31] = frame_addr + offsetof(struct sigframe, sf_code);
bellard106ec872006-06-27 21:08:10 +00002970 /* The original kernel code sets CP0_EPC to the handler
2971 * since it returns to userland using eret
2972 * we cannot do this here, and we must set PC directly */
thsb5dc7732008-06-27 10:02:35 +00002973 regs->active_tc.PC = regs->active_tc.gpr[25] = ka->_sa_handler;
Kwok Cheung Yeungea3164a2013-05-17 14:51:20 -07002974 mips_set_hflags_isa_mode_from_pc(regs);
bellard579a97f2007-11-11 14:26:47 +00002975 unlock_user_struct(frame, frame_addr, 1);
bellard106ec872006-06-27 21:08:10 +00002976 return;
2977
2978give_sigsegv:
bellard579a97f2007-11-11 14:26:47 +00002979 unlock_user_struct(frame, frame_addr, 1);
bellard106ec872006-06-27 21:08:10 +00002980 force_sig(TARGET_SIGSEGV/*, current*/);
bellard106ec872006-06-27 21:08:10 +00002981}
2982
Andreas Färber05390242012-02-25 03:37:53 +01002983long do_sigreturn(CPUMIPSState *regs)
bellard106ec872006-06-27 21:08:10 +00002984{
ths388bb212007-05-13 13:58:00 +00002985 struct sigframe *frame;
bellard579a97f2007-11-11 14:26:47 +00002986 abi_ulong frame_addr;
ths388bb212007-05-13 13:58:00 +00002987 sigset_t blocked;
Anthony Liguoric227f092009-10-01 16:12:16 -05002988 target_sigset_t target_set;
ths388bb212007-05-13 13:58:00 +00002989 int i;
bellard106ec872006-06-27 21:08:10 +00002990
2991#if defined(DEBUG_SIGNAL)
ths388bb212007-05-13 13:58:00 +00002992 fprintf(stderr, "do_sigreturn\n");
bellard106ec872006-06-27 21:08:10 +00002993#endif
thsb5dc7732008-06-27 10:02:35 +00002994 frame_addr = regs->active_tc.gpr[29];
bellard579a97f2007-11-11 14:26:47 +00002995 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
bellard106ec872006-06-27 21:08:10 +00002996 goto badframe;
2997
ths388bb212007-05-13 13:58:00 +00002998 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
bellard106ec872006-06-27 21:08:10 +00002999 if(__get_user(target_set.sig[i], &frame->sf_mask.sig[i]))
3000 goto badframe;
ths388bb212007-05-13 13:58:00 +00003001 }
bellard106ec872006-06-27 21:08:10 +00003002
ths388bb212007-05-13 13:58:00 +00003003 target_to_host_sigset_internal(&blocked, &target_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00003004 do_sigprocmask(SIG_SETMASK, &blocked, NULL);
bellard106ec872006-06-27 21:08:10 +00003005
ths388bb212007-05-13 13:58:00 +00003006 if (restore_sigcontext(regs, &frame->sf_sc))
bellard106ec872006-06-27 21:08:10 +00003007 goto badframe;
3008
3009#if 0
ths388bb212007-05-13 13:58:00 +00003010 /*
3011 * Don't let your children do this ...
3012 */
3013 __asm__ __volatile__(
bellard106ec872006-06-27 21:08:10 +00003014 "move\t$29, %0\n\t"
3015 "j\tsyscall_exit"
3016 :/* no outputs */
3017 :"r" (&regs));
ths388bb212007-05-13 13:58:00 +00003018 /* Unreached */
bellard106ec872006-06-27 21:08:10 +00003019#endif
ths3b46e622007-09-17 08:09:54 +00003020
thsb5dc7732008-06-27 10:02:35 +00003021 regs->active_tc.PC = regs->CP0_EPC;
Kwok Cheung Yeungea3164a2013-05-17 14:51:20 -07003022 mips_set_hflags_isa_mode_from_pc(regs);
ths388bb212007-05-13 13:58:00 +00003023 /* I am not sure this is right, but it seems to work
bellard106ec872006-06-27 21:08:10 +00003024 * maybe a problem with nested signals ? */
3025 regs->CP0_EPC = 0;
pbrook0b1bcb02009-04-21 01:41:10 +00003026 return -TARGET_QEMU_ESIGRETURN;
bellard106ec872006-06-27 21:08:10 +00003027
3028badframe:
ths388bb212007-05-13 13:58:00 +00003029 force_sig(TARGET_SIGSEGV/*, current*/);
3030 return 0;
bellard106ec872006-06-27 21:08:10 +00003031}
Richard Hendersonff970902013-02-10 10:30:42 -08003032# endif /* O32 */
bellard106ec872006-06-27 21:08:10 +00003033
pbrook624f7972008-05-31 16:11:38 +00003034static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05003035 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01003036 target_sigset_t *set, CPUMIPSState *env)
bellard106ec872006-06-27 21:08:10 +00003037{
pbrook0b1bcb02009-04-21 01:41:10 +00003038 struct target_rt_sigframe *frame;
3039 abi_ulong frame_addr;
3040 int i;
3041
3042 frame_addr = get_sigframe(ka, env, sizeof(*frame));
3043 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
3044 goto give_sigsegv;
3045
3046 install_sigtramp(frame->rs_code, TARGET_NR_rt_sigreturn);
3047
3048 copy_siginfo_to_user(&frame->rs_info, info);
3049
Aurelien Jarno60e99242010-03-29 02:12:51 +02003050 __put_user(0, &frame->rs_uc.tuc_flags);
3051 __put_user(0, &frame->rs_uc.tuc_link);
3052 __put_user(target_sigaltstack_used.ss_sp, &frame->rs_uc.tuc_stack.ss_sp);
3053 __put_user(target_sigaltstack_used.ss_size, &frame->rs_uc.tuc_stack.ss_size);
pbrook0b1bcb02009-04-21 01:41:10 +00003054 __put_user(sas_ss_flags(get_sp_from_cpustate(env)),
Aurelien Jarno60e99242010-03-29 02:12:51 +02003055 &frame->rs_uc.tuc_stack.ss_flags);
pbrook0b1bcb02009-04-21 01:41:10 +00003056
Aurelien Jarno60e99242010-03-29 02:12:51 +02003057 setup_sigcontext(env, &frame->rs_uc.tuc_mcontext);
pbrook0b1bcb02009-04-21 01:41:10 +00003058
3059 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
Aurelien Jarno60e99242010-03-29 02:12:51 +02003060 __put_user(set->sig[i], &frame->rs_uc.tuc_sigmask.sig[i]);
pbrook0b1bcb02009-04-21 01:41:10 +00003061 }
3062
3063 /*
3064 * Arguments to signal handler:
3065 *
3066 * a0 = signal number
Richard W.M. Jones02d2bd52012-07-05 03:32:44 +00003067 * a1 = pointer to siginfo_t
pbrook0b1bcb02009-04-21 01:41:10 +00003068 * a2 = pointer to struct ucontext
3069 *
3070 * $25 and PC point to the signal handler, $29 points to the
3071 * struct sigframe.
3072 */
3073 env->active_tc.gpr[ 4] = sig;
3074 env->active_tc.gpr[ 5] = frame_addr
3075 + offsetof(struct target_rt_sigframe, rs_info);
3076 env->active_tc.gpr[ 6] = frame_addr
3077 + offsetof(struct target_rt_sigframe, rs_uc);
3078 env->active_tc.gpr[29] = frame_addr;
3079 env->active_tc.gpr[31] = frame_addr
3080 + offsetof(struct target_rt_sigframe, rs_code);
3081 /* The original kernel code sets CP0_EPC to the handler
3082 * since it returns to userland using eret
3083 * we cannot do this here, and we must set PC directly */
3084 env->active_tc.PC = env->active_tc.gpr[25] = ka->_sa_handler;
Kwok Cheung Yeungea3164a2013-05-17 14:51:20 -07003085 mips_set_hflags_isa_mode_from_pc(env);
pbrook0b1bcb02009-04-21 01:41:10 +00003086 unlock_user_struct(frame, frame_addr, 1);
3087 return;
3088
3089give_sigsegv:
3090 unlock_user_struct(frame, frame_addr, 1);
3091 force_sig(TARGET_SIGSEGV/*, current*/);
bellard106ec872006-06-27 21:08:10 +00003092}
3093
Andreas Färber05390242012-02-25 03:37:53 +01003094long do_rt_sigreturn(CPUMIPSState *env)
bellard106ec872006-06-27 21:08:10 +00003095{
pbrook0b1bcb02009-04-21 01:41:10 +00003096 struct target_rt_sigframe *frame;
3097 abi_ulong frame_addr;
3098 sigset_t blocked;
3099
3100#if defined(DEBUG_SIGNAL)
3101 fprintf(stderr, "do_rt_sigreturn\n");
3102#endif
3103 frame_addr = env->active_tc.gpr[29];
3104 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
3105 goto badframe;
3106
Aurelien Jarno60e99242010-03-29 02:12:51 +02003107 target_to_host_sigset(&blocked, &frame->rs_uc.tuc_sigmask);
Alex Barcelo1c275922014-03-14 14:36:55 +00003108 do_sigprocmask(SIG_SETMASK, &blocked, NULL);
pbrook0b1bcb02009-04-21 01:41:10 +00003109
Aurelien Jarno60e99242010-03-29 02:12:51 +02003110 if (restore_sigcontext(env, &frame->rs_uc.tuc_mcontext))
pbrook0b1bcb02009-04-21 01:41:10 +00003111 goto badframe;
3112
3113 if (do_sigaltstack(frame_addr +
Aurelien Jarno60e99242010-03-29 02:12:51 +02003114 offsetof(struct target_rt_sigframe, rs_uc.tuc_stack),
pbrook0b1bcb02009-04-21 01:41:10 +00003115 0, get_sp_from_cpustate(env)) == -EFAULT)
3116 goto badframe;
3117
3118 env->active_tc.PC = env->CP0_EPC;
Kwok Cheung Yeungea3164a2013-05-17 14:51:20 -07003119 mips_set_hflags_isa_mode_from_pc(env);
pbrook0b1bcb02009-04-21 01:41:10 +00003120 /* I am not sure this is right, but it seems to work
3121 * maybe a problem with nested signals ? */
3122 env->CP0_EPC = 0;
3123 return -TARGET_QEMU_ESIGRETURN;
3124
3125badframe:
3126 force_sig(TARGET_SIGSEGV/*, current*/);
3127 return 0;
bellard106ec872006-06-27 21:08:10 +00003128}
bellard6d5e2162004-09-30 22:04:13 +00003129
thsc3b5bc82007-12-02 06:31:25 +00003130#elif defined(TARGET_SH4)
3131
3132/*
3133 * code and data structures from linux kernel:
3134 * include/asm-sh/sigcontext.h
3135 * arch/sh/kernel/signal.c
3136 */
3137
3138struct target_sigcontext {
3139 target_ulong oldmask;
3140
3141 /* CPU registers */
3142 target_ulong sc_gregs[16];
3143 target_ulong sc_pc;
3144 target_ulong sc_pr;
3145 target_ulong sc_sr;
3146 target_ulong sc_gbr;
3147 target_ulong sc_mach;
3148 target_ulong sc_macl;
3149
3150 /* FPU registers */
3151 target_ulong sc_fpregs[16];
3152 target_ulong sc_xfpregs[16];
3153 unsigned int sc_fpscr;
3154 unsigned int sc_fpul;
3155 unsigned int sc_ownedfp;
3156};
3157
3158struct target_sigframe
3159{
3160 struct target_sigcontext sc;
3161 target_ulong extramask[TARGET_NSIG_WORDS-1];
3162 uint16_t retcode[3];
3163};
3164
3165
3166struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02003167 target_ulong tuc_flags;
3168 struct target_ucontext *tuc_link;
3169 target_stack_t tuc_stack;
3170 struct target_sigcontext tuc_mcontext;
3171 target_sigset_t tuc_sigmask; /* mask last for extensibility */
thsc3b5bc82007-12-02 06:31:25 +00003172};
3173
3174struct target_rt_sigframe
3175{
3176 struct target_siginfo info;
3177 struct target_ucontext uc;
3178 uint16_t retcode[3];
3179};
3180
3181
3182#define MOVW(n) (0x9300|((n)-2)) /* Move mem word at PC+n to R3 */
3183#define TRAP_NOARG 0xc310 /* Syscall w/no args (NR in R3) SH3/4 */
3184
pbrook624f7972008-05-31 16:11:38 +00003185static abi_ulong get_sigframe(struct target_sigaction *ka,
thsc3b5bc82007-12-02 06:31:25 +00003186 unsigned long sp, size_t frame_size)
3187{
pbrook624f7972008-05-31 16:11:38 +00003188 if ((ka->sa_flags & TARGET_SA_ONSTACK) && (sas_ss_flags(sp) == 0)) {
thsc3b5bc82007-12-02 06:31:25 +00003189 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
3190 }
3191
3192 return (sp - frame_size) & -8ul;
3193}
3194
3195static int setup_sigcontext(struct target_sigcontext *sc,
Andreas Färber05390242012-02-25 03:37:53 +01003196 CPUSH4State *regs, unsigned long mask)
thsc3b5bc82007-12-02 06:31:25 +00003197{
3198 int err = 0;
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003199 int i;
thsc3b5bc82007-12-02 06:31:25 +00003200
3201#define COPY(x) err |= __put_user(regs->x, &sc->sc_##x)
3202 COPY(gregs[0]); COPY(gregs[1]);
3203 COPY(gregs[2]); COPY(gregs[3]);
3204 COPY(gregs[4]); COPY(gregs[5]);
3205 COPY(gregs[6]); COPY(gregs[7]);
3206 COPY(gregs[8]); COPY(gregs[9]);
3207 COPY(gregs[10]); COPY(gregs[11]);
3208 COPY(gregs[12]); COPY(gregs[13]);
3209 COPY(gregs[14]); COPY(gregs[15]);
3210 COPY(gbr); COPY(mach);
3211 COPY(macl); COPY(pr);
3212 COPY(sr); COPY(pc);
3213#undef COPY
3214
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003215 for (i=0; i<16; i++) {
3216 err |= __put_user(regs->fregs[i], &sc->sc_fpregs[i]);
3217 }
3218 err |= __put_user(regs->fpscr, &sc->sc_fpscr);
3219 err |= __put_user(regs->fpul, &sc->sc_fpul);
thsc3b5bc82007-12-02 06:31:25 +00003220
3221 /* non-iBCS2 extensions.. */
3222 err |= __put_user(mask, &sc->oldmask);
3223
3224 return err;
3225}
3226
Andreas Färber05390242012-02-25 03:37:53 +01003227static int restore_sigcontext(CPUSH4State *regs, struct target_sigcontext *sc,
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003228 target_ulong *r0_p)
thsc3b5bc82007-12-02 06:31:25 +00003229{
3230 unsigned int err = 0;
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003231 int i;
thsc3b5bc82007-12-02 06:31:25 +00003232
3233#define COPY(x) err |= __get_user(regs->x, &sc->sc_##x)
3234 COPY(gregs[1]);
3235 COPY(gregs[2]); COPY(gregs[3]);
3236 COPY(gregs[4]); COPY(gregs[5]);
3237 COPY(gregs[6]); COPY(gregs[7]);
3238 COPY(gregs[8]); COPY(gregs[9]);
3239 COPY(gregs[10]); COPY(gregs[11]);
3240 COPY(gregs[12]); COPY(gregs[13]);
3241 COPY(gregs[14]); COPY(gregs[15]);
3242 COPY(gbr); COPY(mach);
3243 COPY(macl); COPY(pr);
3244 COPY(sr); COPY(pc);
3245#undef COPY
3246
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003247 for (i=0; i<16; i++) {
3248 err |= __get_user(regs->fregs[i], &sc->sc_fpregs[i]);
3249 }
3250 err |= __get_user(regs->fpscr, &sc->sc_fpscr);
3251 err |= __get_user(regs->fpul, &sc->sc_fpul);
thsc3b5bc82007-12-02 06:31:25 +00003252
3253 regs->tra = -1; /* disable syscall checks */
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003254 err |= __get_user(*r0_p, &sc->sc_gregs[0]);
thsc3b5bc82007-12-02 06:31:25 +00003255 return err;
3256}
3257
pbrook624f7972008-05-31 16:11:38 +00003258static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01003259 target_sigset_t *set, CPUSH4State *regs)
thsc3b5bc82007-12-02 06:31:25 +00003260{
3261 struct target_sigframe *frame;
3262 abi_ulong frame_addr;
3263 int i;
3264 int err = 0;
3265 int signal;
3266
3267 frame_addr = get_sigframe(ka, regs->gregs[15], sizeof(*frame));
3268 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
3269 goto give_sigsegv;
3270
3271 signal = current_exec_domain_sig(sig);
3272
3273 err |= setup_sigcontext(&frame->sc, regs, set->sig[0]);
3274
3275 for (i = 0; i < TARGET_NSIG_WORDS - 1; i++) {
3276 err |= __put_user(set->sig[i + 1], &frame->extramask[i]);
3277 }
3278
3279 /* Set up to return from userspace. If provided, use a stub
3280 already in userspace. */
pbrook624f7972008-05-31 16:11:38 +00003281 if (ka->sa_flags & TARGET_SA_RESTORER) {
3282 regs->pr = (unsigned long) ka->sa_restorer;
thsc3b5bc82007-12-02 06:31:25 +00003283 } else {
3284 /* Generate return code (system call to sigreturn) */
3285 err |= __put_user(MOVW(2), &frame->retcode[0]);
3286 err |= __put_user(TRAP_NOARG, &frame->retcode[1]);
3287 err |= __put_user((TARGET_NR_sigreturn), &frame->retcode[2]);
3288 regs->pr = (unsigned long) frame->retcode;
3289 }
3290
3291 if (err)
3292 goto give_sigsegv;
3293
3294 /* Set up registers for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003295 regs->gregs[15] = frame_addr;
thsc3b5bc82007-12-02 06:31:25 +00003296 regs->gregs[4] = signal; /* Arg for signal handler */
3297 regs->gregs[5] = 0;
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003298 regs->gregs[6] = frame_addr += offsetof(typeof(*frame), sc);
pbrook624f7972008-05-31 16:11:38 +00003299 regs->pc = (unsigned long) ka->_sa_handler;
thsc3b5bc82007-12-02 06:31:25 +00003300
3301 unlock_user_struct(frame, frame_addr, 1);
3302 return;
3303
3304give_sigsegv:
3305 unlock_user_struct(frame, frame_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02003306 force_sig(TARGET_SIGSEGV);
thsc3b5bc82007-12-02 06:31:25 +00003307}
3308
pbrook624f7972008-05-31 16:11:38 +00003309static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05003310 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01003311 target_sigset_t *set, CPUSH4State *regs)
thsc3b5bc82007-12-02 06:31:25 +00003312{
3313 struct target_rt_sigframe *frame;
3314 abi_ulong frame_addr;
3315 int i;
3316 int err = 0;
3317 int signal;
3318
3319 frame_addr = get_sigframe(ka, regs->gregs[15], sizeof(*frame));
3320 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
3321 goto give_sigsegv;
3322
3323 signal = current_exec_domain_sig(sig);
3324
3325 err |= copy_siginfo_to_user(&frame->info, info);
3326
3327 /* Create the ucontext. */
Aurelien Jarno60e99242010-03-29 02:12:51 +02003328 err |= __put_user(0, &frame->uc.tuc_flags);
3329 err |= __put_user(0, (unsigned long *)&frame->uc.tuc_link);
balrog526ccb72008-07-16 12:13:52 +00003330 err |= __put_user((unsigned long)target_sigaltstack_used.ss_sp,
Aurelien Jarno60e99242010-03-29 02:12:51 +02003331 &frame->uc.tuc_stack.ss_sp);
thsc3b5bc82007-12-02 06:31:25 +00003332 err |= __put_user(sas_ss_flags(regs->gregs[15]),
Aurelien Jarno60e99242010-03-29 02:12:51 +02003333 &frame->uc.tuc_stack.ss_flags);
thsc3b5bc82007-12-02 06:31:25 +00003334 err |= __put_user(target_sigaltstack_used.ss_size,
Aurelien Jarno60e99242010-03-29 02:12:51 +02003335 &frame->uc.tuc_stack.ss_size);
3336 err |= setup_sigcontext(&frame->uc.tuc_mcontext,
thsc3b5bc82007-12-02 06:31:25 +00003337 regs, set->sig[0]);
3338 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
Aurelien Jarno60e99242010-03-29 02:12:51 +02003339 err |= __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
thsc3b5bc82007-12-02 06:31:25 +00003340 }
3341
3342 /* Set up to return from userspace. If provided, use a stub
3343 already in userspace. */
pbrook624f7972008-05-31 16:11:38 +00003344 if (ka->sa_flags & TARGET_SA_RESTORER) {
3345 regs->pr = (unsigned long) ka->sa_restorer;
thsc3b5bc82007-12-02 06:31:25 +00003346 } else {
3347 /* Generate return code (system call to sigreturn) */
3348 err |= __put_user(MOVW(2), &frame->retcode[0]);
3349 err |= __put_user(TRAP_NOARG, &frame->retcode[1]);
3350 err |= __put_user((TARGET_NR_rt_sigreturn), &frame->retcode[2]);
3351 regs->pr = (unsigned long) frame->retcode;
3352 }
3353
3354 if (err)
3355 goto give_sigsegv;
3356
3357 /* Set up registers for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003358 regs->gregs[15] = frame_addr;
thsc3b5bc82007-12-02 06:31:25 +00003359 regs->gregs[4] = signal; /* Arg for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003360 regs->gregs[5] = frame_addr + offsetof(typeof(*frame), info);
3361 regs->gregs[6] = frame_addr + offsetof(typeof(*frame), uc);
pbrook624f7972008-05-31 16:11:38 +00003362 regs->pc = (unsigned long) ka->_sa_handler;
thsc3b5bc82007-12-02 06:31:25 +00003363
3364 unlock_user_struct(frame, frame_addr, 1);
3365 return;
3366
3367give_sigsegv:
3368 unlock_user_struct(frame, frame_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02003369 force_sig(TARGET_SIGSEGV);
thsc3b5bc82007-12-02 06:31:25 +00003370}
3371
Andreas Färber05390242012-02-25 03:37:53 +01003372long do_sigreturn(CPUSH4State *regs)
thsc3b5bc82007-12-02 06:31:25 +00003373{
3374 struct target_sigframe *frame;
3375 abi_ulong frame_addr;
3376 sigset_t blocked;
Anthony Liguoric227f092009-10-01 16:12:16 -05003377 target_sigset_t target_set;
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003378 target_ulong r0;
thsc3b5bc82007-12-02 06:31:25 +00003379 int i;
3380 int err = 0;
3381
3382#if defined(DEBUG_SIGNAL)
3383 fprintf(stderr, "do_sigreturn\n");
3384#endif
3385 frame_addr = regs->gregs[15];
3386 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
3387 goto badframe;
3388
3389 err |= __get_user(target_set.sig[0], &frame->sc.oldmask);
3390 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
3391 err |= (__get_user(target_set.sig[i], &frame->extramask[i - 1]));
3392 }
3393
3394 if (err)
3395 goto badframe;
3396
3397 target_to_host_sigset_internal(&blocked, &target_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00003398 do_sigprocmask(SIG_SETMASK, &blocked, NULL);
thsc3b5bc82007-12-02 06:31:25 +00003399
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003400 if (restore_sigcontext(regs, &frame->sc, &r0))
thsc3b5bc82007-12-02 06:31:25 +00003401 goto badframe;
3402
3403 unlock_user_struct(frame, frame_addr, 0);
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003404 return r0;
thsc3b5bc82007-12-02 06:31:25 +00003405
3406badframe:
3407 unlock_user_struct(frame, frame_addr, 0);
3408 force_sig(TARGET_SIGSEGV);
3409 return 0;
3410}
3411
Andreas Färber05390242012-02-25 03:37:53 +01003412long do_rt_sigreturn(CPUSH4State *regs)
thsc3b5bc82007-12-02 06:31:25 +00003413{
3414 struct target_rt_sigframe *frame;
3415 abi_ulong frame_addr;
3416 sigset_t blocked;
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003417 target_ulong r0;
thsc3b5bc82007-12-02 06:31:25 +00003418
3419#if defined(DEBUG_SIGNAL)
3420 fprintf(stderr, "do_rt_sigreturn\n");
3421#endif
3422 frame_addr = regs->gregs[15];
3423 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
3424 goto badframe;
3425
Aurelien Jarno60e99242010-03-29 02:12:51 +02003426 target_to_host_sigset(&blocked, &frame->uc.tuc_sigmask);
Alex Barcelo1c275922014-03-14 14:36:55 +00003427 do_sigprocmask(SIG_SETMASK, &blocked, NULL);
thsc3b5bc82007-12-02 06:31:25 +00003428
Aurelien Jarno60e99242010-03-29 02:12:51 +02003429 if (restore_sigcontext(regs, &frame->uc.tuc_mcontext, &r0))
thsc3b5bc82007-12-02 06:31:25 +00003430 goto badframe;
3431
3432 if (do_sigaltstack(frame_addr +
Aurelien Jarno60e99242010-03-29 02:12:51 +02003433 offsetof(struct target_rt_sigframe, uc.tuc_stack),
thsc3b5bc82007-12-02 06:31:25 +00003434 0, get_sp_from_cpustate(regs)) == -EFAULT)
3435 goto badframe;
3436
3437 unlock_user_struct(frame, frame_addr, 0);
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003438 return r0;
thsc3b5bc82007-12-02 06:31:25 +00003439
3440badframe:
3441 unlock_user_struct(frame, frame_addr, 0);
3442 force_sig(TARGET_SIGSEGV);
3443 return 0;
3444}
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003445#elif defined(TARGET_MICROBLAZE)
3446
3447struct target_sigcontext {
3448 struct target_pt_regs regs; /* needs to be first */
3449 uint32_t oldmask;
3450};
3451
Edgar E. Iglesiasb2178702010-07-23 09:30:37 +02003452struct target_stack_t {
3453 abi_ulong ss_sp;
3454 int ss_flags;
3455 unsigned int ss_size;
3456};
3457
3458struct target_ucontext {
Richard Hendersonf711df62010-11-22 14:57:52 -08003459 abi_ulong tuc_flags;
3460 abi_ulong tuc_link;
3461 struct target_stack_t tuc_stack;
3462 struct target_sigcontext tuc_mcontext;
3463 uint32_t tuc_extramask[TARGET_NSIG_WORDS - 1];
Edgar E. Iglesiasb2178702010-07-23 09:30:37 +02003464};
3465
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003466/* Signal frames. */
3467struct target_signal_frame {
Edgar E. Iglesiasb2178702010-07-23 09:30:37 +02003468 struct target_ucontext uc;
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003469 uint32_t extramask[TARGET_NSIG_WORDS - 1];
3470 uint32_t tramp[2];
3471};
3472
3473struct rt_signal_frame {
Richard W.M. Jones02d2bd52012-07-05 03:32:44 +00003474 siginfo_t info;
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003475 struct ucontext uc;
3476 uint32_t tramp[2];
3477};
3478
Andreas Färber05390242012-02-25 03:37:53 +01003479static void setup_sigcontext(struct target_sigcontext *sc, CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003480{
3481 __put_user(env->regs[0], &sc->regs.r0);
3482 __put_user(env->regs[1], &sc->regs.r1);
3483 __put_user(env->regs[2], &sc->regs.r2);
3484 __put_user(env->regs[3], &sc->regs.r3);
3485 __put_user(env->regs[4], &sc->regs.r4);
3486 __put_user(env->regs[5], &sc->regs.r5);
3487 __put_user(env->regs[6], &sc->regs.r6);
3488 __put_user(env->regs[7], &sc->regs.r7);
3489 __put_user(env->regs[8], &sc->regs.r8);
3490 __put_user(env->regs[9], &sc->regs.r9);
3491 __put_user(env->regs[10], &sc->regs.r10);
3492 __put_user(env->regs[11], &sc->regs.r11);
3493 __put_user(env->regs[12], &sc->regs.r12);
3494 __put_user(env->regs[13], &sc->regs.r13);
3495 __put_user(env->regs[14], &sc->regs.r14);
3496 __put_user(env->regs[15], &sc->regs.r15);
3497 __put_user(env->regs[16], &sc->regs.r16);
3498 __put_user(env->regs[17], &sc->regs.r17);
3499 __put_user(env->regs[18], &sc->regs.r18);
3500 __put_user(env->regs[19], &sc->regs.r19);
3501 __put_user(env->regs[20], &sc->regs.r20);
3502 __put_user(env->regs[21], &sc->regs.r21);
3503 __put_user(env->regs[22], &sc->regs.r22);
3504 __put_user(env->regs[23], &sc->regs.r23);
3505 __put_user(env->regs[24], &sc->regs.r24);
3506 __put_user(env->regs[25], &sc->regs.r25);
3507 __put_user(env->regs[26], &sc->regs.r26);
3508 __put_user(env->regs[27], &sc->regs.r27);
3509 __put_user(env->regs[28], &sc->regs.r28);
3510 __put_user(env->regs[29], &sc->regs.r29);
3511 __put_user(env->regs[30], &sc->regs.r30);
3512 __put_user(env->regs[31], &sc->regs.r31);
3513 __put_user(env->sregs[SR_PC], &sc->regs.pc);
3514}
3515
Andreas Färber05390242012-02-25 03:37:53 +01003516static void restore_sigcontext(struct target_sigcontext *sc, CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003517{
3518 __get_user(env->regs[0], &sc->regs.r0);
3519 __get_user(env->regs[1], &sc->regs.r1);
3520 __get_user(env->regs[2], &sc->regs.r2);
3521 __get_user(env->regs[3], &sc->regs.r3);
3522 __get_user(env->regs[4], &sc->regs.r4);
3523 __get_user(env->regs[5], &sc->regs.r5);
3524 __get_user(env->regs[6], &sc->regs.r6);
3525 __get_user(env->regs[7], &sc->regs.r7);
3526 __get_user(env->regs[8], &sc->regs.r8);
3527 __get_user(env->regs[9], &sc->regs.r9);
3528 __get_user(env->regs[10], &sc->regs.r10);
3529 __get_user(env->regs[11], &sc->regs.r11);
3530 __get_user(env->regs[12], &sc->regs.r12);
3531 __get_user(env->regs[13], &sc->regs.r13);
3532 __get_user(env->regs[14], &sc->regs.r14);
3533 __get_user(env->regs[15], &sc->regs.r15);
3534 __get_user(env->regs[16], &sc->regs.r16);
3535 __get_user(env->regs[17], &sc->regs.r17);
3536 __get_user(env->regs[18], &sc->regs.r18);
3537 __get_user(env->regs[19], &sc->regs.r19);
3538 __get_user(env->regs[20], &sc->regs.r20);
3539 __get_user(env->regs[21], &sc->regs.r21);
3540 __get_user(env->regs[22], &sc->regs.r22);
3541 __get_user(env->regs[23], &sc->regs.r23);
3542 __get_user(env->regs[24], &sc->regs.r24);
3543 __get_user(env->regs[25], &sc->regs.r25);
3544 __get_user(env->regs[26], &sc->regs.r26);
3545 __get_user(env->regs[27], &sc->regs.r27);
3546 __get_user(env->regs[28], &sc->regs.r28);
3547 __get_user(env->regs[29], &sc->regs.r29);
3548 __get_user(env->regs[30], &sc->regs.r30);
3549 __get_user(env->regs[31], &sc->regs.r31);
3550 __get_user(env->sregs[SR_PC], &sc->regs.pc);
3551}
3552
3553static abi_ulong get_sigframe(struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01003554 CPUMBState *env, int frame_size)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003555{
3556 abi_ulong sp = env->regs[1];
3557
3558 if ((ka->sa_flags & SA_ONSTACK) != 0 && !on_sig_stack(sp))
3559 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
3560
3561 return ((sp - frame_size) & -8UL);
3562}
3563
3564static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01003565 target_sigset_t *set, CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003566{
3567 struct target_signal_frame *frame;
3568 abi_ulong frame_addr;
3569 int err = 0;
3570 int i;
3571
3572 frame_addr = get_sigframe(ka, env, sizeof *frame);
3573 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
3574 goto badframe;
3575
3576 /* Save the mask. */
Richard Hendersonf711df62010-11-22 14:57:52 -08003577 err |= __put_user(set->sig[0], &frame->uc.tuc_mcontext.oldmask);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003578 if (err)
3579 goto badframe;
3580
3581 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
3582 if (__put_user(set->sig[i], &frame->extramask[i - 1]))
3583 goto badframe;
3584 }
3585
Richard Hendersonf711df62010-11-22 14:57:52 -08003586 setup_sigcontext(&frame->uc.tuc_mcontext, env);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003587
3588 /* Set up to return from userspace. If provided, use a stub
3589 already in userspace. */
3590 /* minus 8 is offset to cater for "rtsd r15,8" offset */
3591 if (ka->sa_flags & TARGET_SA_RESTORER) {
3592 env->regs[15] = ((unsigned long)ka->sa_restorer)-8;
3593 } else {
3594 uint32_t t;
3595 /* Note, these encodings are _big endian_! */
3596 /* addi r12, r0, __NR_sigreturn */
3597 t = 0x31800000UL | TARGET_NR_sigreturn;
3598 err |= __put_user(t, frame->tramp + 0);
3599 /* brki r14, 0x8 */
3600 t = 0xb9cc0008UL;
3601 err |= __put_user(t, frame->tramp + 1);
3602
3603 /* Return from sighandler will jump to the tramp.
3604 Negative 8 offset because return is rtsd r15, 8 */
3605 env->regs[15] = ((unsigned long)frame->tramp) - 8;
3606 }
3607
3608 if (err)
3609 goto badframe;
3610
3611 /* Set up registers for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003612 env->regs[1] = frame_addr;
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003613 /* Signal handler args: */
3614 env->regs[5] = sig; /* Arg 0: signum */
Edgar E. Iglesias187b4e02010-07-15 15:32:51 +02003615 env->regs[6] = 0;
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003616 /* arg 1: sigcontext */
3617 env->regs[7] = frame_addr += offsetof(typeof(*frame), uc);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003618
3619 /* Offset of 4 to handle microblaze rtid r14, 0 */
3620 env->sregs[SR_PC] = (unsigned long)ka->_sa_handler;
3621
3622 unlock_user_struct(frame, frame_addr, 1);
3623 return;
3624 badframe:
3625 unlock_user_struct(frame, frame_addr, 1);
3626 force_sig(TARGET_SIGSEGV);
3627}
3628
3629static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05003630 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01003631 target_sigset_t *set, CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003632{
3633 fprintf(stderr, "Microblaze setup_rt_frame: not implemented\n");
3634}
3635
Andreas Färber05390242012-02-25 03:37:53 +01003636long do_sigreturn(CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003637{
3638 struct target_signal_frame *frame;
3639 abi_ulong frame_addr;
Anthony Liguoric227f092009-10-01 16:12:16 -05003640 target_sigset_t target_set;
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003641 sigset_t set;
3642 int i;
3643
3644 frame_addr = env->regs[R_SP];
3645 /* Make sure the guest isn't playing games. */
3646 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 1))
3647 goto badframe;
3648
3649 /* Restore blocked signals */
Richard Hendersonf711df62010-11-22 14:57:52 -08003650 if (__get_user(target_set.sig[0], &frame->uc.tuc_mcontext.oldmask))
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003651 goto badframe;
3652 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
3653 if (__get_user(target_set.sig[i], &frame->extramask[i - 1]))
3654 goto badframe;
3655 }
3656 target_to_host_sigset_internal(&set, &target_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00003657 do_sigprocmask(SIG_SETMASK, &set, NULL);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003658
Richard Hendersonf711df62010-11-22 14:57:52 -08003659 restore_sigcontext(&frame->uc.tuc_mcontext, env);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003660 /* We got here through a sigreturn syscall, our path back is via an
3661 rtb insn so setup r14 for that. */
3662 env->regs[14] = env->sregs[SR_PC];
3663
3664 unlock_user_struct(frame, frame_addr, 0);
3665 return env->regs[10];
3666 badframe:
3667 unlock_user_struct(frame, frame_addr, 0);
3668 force_sig(TARGET_SIGSEGV);
3669}
3670
Andreas Färber05390242012-02-25 03:37:53 +01003671long do_rt_sigreturn(CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003672{
3673 fprintf(stderr, "Microblaze do_rt_sigreturn: not implemented\n");
3674 return -TARGET_ENOSYS;
3675}
3676
edgar_iglb6d3abd2008-02-28 11:29:27 +00003677#elif defined(TARGET_CRIS)
3678
3679struct target_sigcontext {
3680 struct target_pt_regs regs; /* needs to be first */
3681 uint32_t oldmask;
3682 uint32_t usp; /* usp before stacking this gunk on it */
3683};
3684
3685/* Signal frames. */
3686struct target_signal_frame {
3687 struct target_sigcontext sc;
3688 uint32_t extramask[TARGET_NSIG_WORDS - 1];
Stefan Weil8cfc1142014-02-01 09:41:09 +01003689 uint16_t retcode[4]; /* Trampoline code. */
edgar_iglb6d3abd2008-02-28 11:29:27 +00003690};
3691
3692struct rt_signal_frame {
Richard W.M. Jones02d2bd52012-07-05 03:32:44 +00003693 siginfo_t *pinfo;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003694 void *puc;
Richard W.M. Jones02d2bd52012-07-05 03:32:44 +00003695 siginfo_t info;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003696 struct ucontext uc;
Stefan Weil8cfc1142014-02-01 09:41:09 +01003697 uint16_t retcode[4]; /* Trampoline code. */
edgar_iglb6d3abd2008-02-28 11:29:27 +00003698};
3699
Andreas Färber05390242012-02-25 03:37:53 +01003700static void setup_sigcontext(struct target_sigcontext *sc, CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003701{
edgar_igl9664d922008-03-03 22:23:53 +00003702 __put_user(env->regs[0], &sc->regs.r0);
3703 __put_user(env->regs[1], &sc->regs.r1);
3704 __put_user(env->regs[2], &sc->regs.r2);
3705 __put_user(env->regs[3], &sc->regs.r3);
3706 __put_user(env->regs[4], &sc->regs.r4);
3707 __put_user(env->regs[5], &sc->regs.r5);
3708 __put_user(env->regs[6], &sc->regs.r6);
3709 __put_user(env->regs[7], &sc->regs.r7);
3710 __put_user(env->regs[8], &sc->regs.r8);
3711 __put_user(env->regs[9], &sc->regs.r9);
3712 __put_user(env->regs[10], &sc->regs.r10);
3713 __put_user(env->regs[11], &sc->regs.r11);
3714 __put_user(env->regs[12], &sc->regs.r12);
3715 __put_user(env->regs[13], &sc->regs.r13);
3716 __put_user(env->regs[14], &sc->usp);
3717 __put_user(env->regs[15], &sc->regs.acr);
3718 __put_user(env->pregs[PR_MOF], &sc->regs.mof);
3719 __put_user(env->pregs[PR_SRP], &sc->regs.srp);
3720 __put_user(env->pc, &sc->regs.erp);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003721}
edgar_igl9664d922008-03-03 22:23:53 +00003722
Andreas Färber05390242012-02-25 03:37:53 +01003723static void restore_sigcontext(struct target_sigcontext *sc, CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003724{
edgar_igl9664d922008-03-03 22:23:53 +00003725 __get_user(env->regs[0], &sc->regs.r0);
3726 __get_user(env->regs[1], &sc->regs.r1);
3727 __get_user(env->regs[2], &sc->regs.r2);
3728 __get_user(env->regs[3], &sc->regs.r3);
3729 __get_user(env->regs[4], &sc->regs.r4);
3730 __get_user(env->regs[5], &sc->regs.r5);
3731 __get_user(env->regs[6], &sc->regs.r6);
3732 __get_user(env->regs[7], &sc->regs.r7);
3733 __get_user(env->regs[8], &sc->regs.r8);
3734 __get_user(env->regs[9], &sc->regs.r9);
3735 __get_user(env->regs[10], &sc->regs.r10);
3736 __get_user(env->regs[11], &sc->regs.r11);
3737 __get_user(env->regs[12], &sc->regs.r12);
3738 __get_user(env->regs[13], &sc->regs.r13);
3739 __get_user(env->regs[14], &sc->usp);
3740 __get_user(env->regs[15], &sc->regs.acr);
3741 __get_user(env->pregs[PR_MOF], &sc->regs.mof);
3742 __get_user(env->pregs[PR_SRP], &sc->regs.srp);
3743 __get_user(env->pc, &sc->regs.erp);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003744}
3745
Andreas Färber05390242012-02-25 03:37:53 +01003746static abi_ulong get_sigframe(CPUCRISState *env, int framesize)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003747{
edgar_igl9664d922008-03-03 22:23:53 +00003748 abi_ulong sp;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003749 /* Align the stack downwards to 4. */
edgar_igl9664d922008-03-03 22:23:53 +00003750 sp = (env->regs[R_SP] & ~3);
3751 return sp - framesize;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003752}
3753
pbrook624f7972008-05-31 16:11:38 +00003754static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01003755 target_sigset_t *set, CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003756{
3757 struct target_signal_frame *frame;
edgar_igl9664d922008-03-03 22:23:53 +00003758 abi_ulong frame_addr;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003759 int err = 0;
3760 int i;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003761
edgar_igl9664d922008-03-03 22:23:53 +00003762 frame_addr = get_sigframe(env, sizeof *frame);
3763 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
edgar_iglb6d3abd2008-02-28 11:29:27 +00003764 goto badframe;
3765
3766 /*
3767 * The CRIS signal return trampoline. A real linux/CRIS kernel doesn't
3768 * use this trampoline anymore but it sets it up for GDB.
3769 * In QEMU, using the trampoline simplifies things a bit so we use it.
3770 *
3771 * This is movu.w __NR_sigreturn, r9; break 13;
3772 */
3773 err |= __put_user(0x9c5f, frame->retcode+0);
3774 err |= __put_user(TARGET_NR_sigreturn,
Stefan Weil8cfc1142014-02-01 09:41:09 +01003775 frame->retcode + 1);
3776 err |= __put_user(0xe93d, frame->retcode + 2);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003777
3778 /* Save the mask. */
3779 err |= __put_user(set->sig[0], &frame->sc.oldmask);
3780 if (err)
3781 goto badframe;
3782
3783 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
3784 if (__put_user(set->sig[i], &frame->extramask[i - 1]))
3785 goto badframe;
3786 }
3787
3788 setup_sigcontext(&frame->sc, env);
3789
3790 /* Move the stack and setup the arguments for the handler. */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003791 env->regs[R_SP] = frame_addr;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003792 env->regs[10] = sig;
pbrook624f7972008-05-31 16:11:38 +00003793 env->pc = (unsigned long) ka->_sa_handler;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003794 /* Link SRP so the guest returns through the trampoline. */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003795 env->pregs[PR_SRP] = frame_addr + offsetof(typeof(*frame), retcode);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003796
edgar_igl9664d922008-03-03 22:23:53 +00003797 unlock_user_struct(frame, frame_addr, 1);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003798 return;
3799 badframe:
edgar_igl9664d922008-03-03 22:23:53 +00003800 unlock_user_struct(frame, frame_addr, 1);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003801 force_sig(TARGET_SIGSEGV);
3802}
3803
pbrook624f7972008-05-31 16:11:38 +00003804static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05003805 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01003806 target_sigset_t *set, CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003807{
3808 fprintf(stderr, "CRIS setup_rt_frame: not implemented\n");
3809}
3810
Andreas Färber05390242012-02-25 03:37:53 +01003811long do_sigreturn(CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003812{
3813 struct target_signal_frame *frame;
edgar_igl9664d922008-03-03 22:23:53 +00003814 abi_ulong frame_addr;
Anthony Liguoric227f092009-10-01 16:12:16 -05003815 target_sigset_t target_set;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003816 sigset_t set;
3817 int i;
3818
edgar_igl9664d922008-03-03 22:23:53 +00003819 frame_addr = env->regs[R_SP];
edgar_iglb6d3abd2008-02-28 11:29:27 +00003820 /* Make sure the guest isn't playing games. */
edgar_igl9664d922008-03-03 22:23:53 +00003821 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 1))
edgar_iglb6d3abd2008-02-28 11:29:27 +00003822 goto badframe;
3823
3824 /* Restore blocked signals */
3825 if (__get_user(target_set.sig[0], &frame->sc.oldmask))
3826 goto badframe;
3827 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
3828 if (__get_user(target_set.sig[i], &frame->extramask[i - 1]))
3829 goto badframe;
3830 }
3831 target_to_host_sigset_internal(&set, &target_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00003832 do_sigprocmask(SIG_SETMASK, &set, NULL);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003833
3834 restore_sigcontext(&frame->sc, env);
edgar_igl9664d922008-03-03 22:23:53 +00003835 unlock_user_struct(frame, frame_addr, 0);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003836 return env->regs[10];
3837 badframe:
edgar_igl9664d922008-03-03 22:23:53 +00003838 unlock_user_struct(frame, frame_addr, 0);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003839 force_sig(TARGET_SIGSEGV);
3840}
3841
Andreas Färber05390242012-02-25 03:37:53 +01003842long do_rt_sigreturn(CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003843{
3844 fprintf(stderr, "CRIS do_rt_sigreturn: not implemented\n");
3845 return -TARGET_ENOSYS;
3846}
thsc3b5bc82007-12-02 06:31:25 +00003847
Jia Liud9627832012-07-20 15:50:52 +08003848#elif defined(TARGET_OPENRISC)
3849
3850struct target_sigcontext {
3851 struct target_pt_regs regs;
3852 abi_ulong oldmask;
3853 abi_ulong usp;
3854};
3855
3856struct target_ucontext {
3857 abi_ulong tuc_flags;
3858 abi_ulong tuc_link;
3859 target_stack_t tuc_stack;
3860 struct target_sigcontext tuc_mcontext;
3861 target_sigset_t tuc_sigmask; /* mask last for extensibility */
3862};
3863
3864struct target_rt_sigframe {
3865 abi_ulong pinfo;
3866 uint64_t puc;
3867 struct target_siginfo info;
3868 struct target_sigcontext sc;
3869 struct target_ucontext uc;
3870 unsigned char retcode[16]; /* trampoline code */
3871};
3872
3873/* This is the asm-generic/ucontext.h version */
3874#if 0
3875static int restore_sigcontext(CPUOpenRISCState *regs,
3876 struct target_sigcontext *sc)
3877{
3878 unsigned int err = 0;
3879 unsigned long old_usp;
3880
3881 /* Alwys make any pending restarted system call return -EINTR */
3882 current_thread_info()->restart_block.fn = do_no_restart_syscall;
3883
3884 /* restore the regs from &sc->regs (same as sc, since regs is first)
3885 * (sc is already checked for VERIFY_READ since the sigframe was
3886 * checked in sys_sigreturn previously)
3887 */
3888
3889 if (copy_from_user(regs, &sc, sizeof(struct target_pt_regs))) {
3890 goto badframe;
3891 }
3892
3893 /* make sure the U-flag is set so user-mode cannot fool us */
3894
3895 regs->sr &= ~SR_SM;
3896
3897 /* restore the old USP as it was before we stacked the sc etc.
3898 * (we cannot just pop the sigcontext since we aligned the sp and
3899 * stuff after pushing it)
3900 */
3901
3902 err |= __get_user(old_usp, &sc->usp);
3903 phx_signal("old_usp 0x%lx", old_usp);
3904
3905 __PHX__ REALLY /* ??? */
3906 wrusp(old_usp);
3907 regs->gpr[1] = old_usp;
3908
3909 /* TODO: the other ports use regs->orig_XX to disable syscall checks
3910 * after this completes, but we don't use that mechanism. maybe we can
3911 * use it now ?
3912 */
3913
3914 return err;
3915
3916badframe:
3917 return 1;
3918}
3919#endif
3920
3921/* Set up a signal frame. */
3922
3923static int setup_sigcontext(struct target_sigcontext *sc,
3924 CPUOpenRISCState *regs,
3925 unsigned long mask)
3926{
3927 int err = 0;
3928 unsigned long usp = regs->gpr[1];
3929
3930 /* copy the regs. they are first in sc so we can use sc directly */
3931
3932 /*err |= copy_to_user(&sc, regs, sizeof(struct target_pt_regs));*/
3933
3934 /* Set the frametype to CRIS_FRAME_NORMAL for the execution of
3935 the signal handler. The frametype will be restored to its previous
3936 value in restore_sigcontext. */
3937 /*regs->frametype = CRIS_FRAME_NORMAL;*/
3938
3939 /* then some other stuff */
3940 err |= __put_user(mask, &sc->oldmask);
3941 err |= __put_user(usp, &sc->usp); return err;
3942}
3943
3944static inline unsigned long align_sigframe(unsigned long sp)
3945{
3946 unsigned long i;
3947 i = sp & ~3UL;
3948 return i;
3949}
3950
3951static inline abi_ulong get_sigframe(struct target_sigaction *ka,
3952 CPUOpenRISCState *regs,
3953 size_t frame_size)
3954{
3955 unsigned long sp = regs->gpr[1];
3956 int onsigstack = on_sig_stack(sp);
3957
3958 /* redzone */
3959 /* This is the X/Open sanctioned signal stack switching. */
3960 if ((ka->sa_flags & SA_ONSTACK) != 0 && !onsigstack) {
3961 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
3962 }
3963
3964 sp = align_sigframe(sp - frame_size);
3965
3966 /*
3967 * If we are on the alternate signal stack and would overflow it, don't.
3968 * Return an always-bogus address instead so we will die with SIGSEGV.
3969 */
3970
3971 if (onsigstack && !likely(on_sig_stack(sp))) {
3972 return -1L;
3973 }
3974
3975 return sp;
3976}
3977
3978static void setup_frame(int sig, struct target_sigaction *ka,
3979 target_sigset_t *set, CPUOpenRISCState *env)
3980{
3981 qemu_log("Not implement.\n");
3982}
3983
3984static void setup_rt_frame(int sig, struct target_sigaction *ka,
3985 target_siginfo_t *info,
3986 target_sigset_t *set, CPUOpenRISCState *env)
3987{
3988 int err = 0;
3989 abi_ulong frame_addr;
3990 unsigned long return_ip;
3991 struct target_rt_sigframe *frame;
3992 abi_ulong info_addr, uc_addr;
3993
3994 frame_addr = get_sigframe(ka, env, sizeof *frame);
3995
3996 frame_addr = get_sigframe(ka, env, sizeof(*frame));
3997 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
3998 goto give_sigsegv;
3999 }
4000
4001 info_addr = frame_addr + offsetof(struct target_rt_sigframe, info);
4002 err |= __put_user(info_addr, &frame->pinfo);
4003 uc_addr = frame_addr + offsetof(struct target_rt_sigframe, uc);
4004 err |= __put_user(uc_addr, &frame->puc);
4005
4006 if (ka->sa_flags & SA_SIGINFO) {
4007 err |= copy_siginfo_to_user(&frame->info, info);
4008 }
4009 if (err) {
4010 goto give_sigsegv;
4011 }
4012
4013 /*err |= __clear_user(&frame->uc, offsetof(struct ucontext, uc_mcontext));*/
4014 err |= __put_user(0, &frame->uc.tuc_flags);
4015 err |= __put_user(0, &frame->uc.tuc_link);
4016 err |= __put_user(target_sigaltstack_used.ss_sp,
4017 &frame->uc.tuc_stack.ss_sp);
4018 err |= __put_user(sas_ss_flags(env->gpr[1]), &frame->uc.tuc_stack.ss_flags);
4019 err |= __put_user(target_sigaltstack_used.ss_size,
4020 &frame->uc.tuc_stack.ss_size);
4021 err |= setup_sigcontext(&frame->sc, env, set->sig[0]);
4022
4023 /*err |= copy_to_user(frame->uc.tuc_sigmask, set, sizeof(*set));*/
4024
4025 if (err) {
4026 goto give_sigsegv;
4027 }
4028
4029 /* trampoline - the desired return ip is the retcode itself */
4030 return_ip = (unsigned long)&frame->retcode;
4031 /* This is l.ori r11,r0,__NR_sigreturn, l.sys 1 */
4032 err |= __put_user(0xa960, (short *)(frame->retcode + 0));
4033 err |= __put_user(TARGET_NR_rt_sigreturn, (short *)(frame->retcode + 2));
4034 err |= __put_user(0x20000001, (unsigned long *)(frame->retcode + 4));
4035 err |= __put_user(0x15000000, (unsigned long *)(frame->retcode + 8));
4036
4037 if (err) {
4038 goto give_sigsegv;
4039 }
4040
4041 /* TODO what is the current->exec_domain stuff and invmap ? */
4042
4043 /* Set up registers for signal handler */
4044 env->pc = (unsigned long)ka->_sa_handler; /* what we enter NOW */
4045 env->gpr[9] = (unsigned long)return_ip; /* what we enter LATER */
4046 env->gpr[3] = (unsigned long)sig; /* arg 1: signo */
4047 env->gpr[4] = (unsigned long)&frame->info; /* arg 2: (siginfo_t*) */
4048 env->gpr[5] = (unsigned long)&frame->uc; /* arg 3: ucontext */
4049
4050 /* actually move the usp to reflect the stacked frame */
4051 env->gpr[1] = (unsigned long)frame;
4052
4053 return;
4054
4055give_sigsegv:
4056 unlock_user_struct(frame, frame_addr, 1);
4057 if (sig == TARGET_SIGSEGV) {
4058 ka->_sa_handler = TARGET_SIG_DFL;
4059 }
4060 force_sig(TARGET_SIGSEGV);
4061}
4062
4063long do_sigreturn(CPUOpenRISCState *env)
4064{
4065
4066 qemu_log("do_sigreturn: not implemented\n");
4067 return -TARGET_ENOSYS;
4068}
4069
4070long do_rt_sigreturn(CPUOpenRISCState *env)
4071{
4072 qemu_log("do_rt_sigreturn: not implemented\n");
4073 return -TARGET_ENOSYS;
4074}
4075/* TARGET_OPENRISC */
4076
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004077#elif defined(TARGET_S390X)
4078
4079#define __NUM_GPRS 16
4080#define __NUM_FPRS 16
4081#define __NUM_ACRS 16
4082
4083#define S390_SYSCALL_SIZE 2
4084#define __SIGNAL_FRAMESIZE 160 /* FIXME: 31-bit mode -> 96 */
4085
4086#define _SIGCONTEXT_NSIG 64
4087#define _SIGCONTEXT_NSIG_BPW 64 /* FIXME: 31-bit mode -> 32 */
4088#define _SIGCONTEXT_NSIG_WORDS (_SIGCONTEXT_NSIG / _SIGCONTEXT_NSIG_BPW)
4089#define _SIGMASK_COPY_SIZE (sizeof(unsigned long)*_SIGCONTEXT_NSIG_WORDS)
4090#define PSW_ADDR_AMODE 0x0000000000000000UL /* 0x80000000UL for 31-bit */
4091#define S390_SYSCALL_OPCODE ((uint16_t)0x0a00)
4092
4093typedef struct {
4094 target_psw_t psw;
4095 target_ulong gprs[__NUM_GPRS];
4096 unsigned int acrs[__NUM_ACRS];
4097} target_s390_regs_common;
4098
4099typedef struct {
4100 unsigned int fpc;
4101 double fprs[__NUM_FPRS];
4102} target_s390_fp_regs;
4103
4104typedef struct {
4105 target_s390_regs_common regs;
4106 target_s390_fp_regs fpregs;
4107} target_sigregs;
4108
4109struct target_sigcontext {
4110 target_ulong oldmask[_SIGCONTEXT_NSIG_WORDS];
4111 target_sigregs *sregs;
4112};
4113
4114typedef struct {
4115 uint8_t callee_used_stack[__SIGNAL_FRAMESIZE];
4116 struct target_sigcontext sc;
4117 target_sigregs sregs;
4118 int signo;
4119 uint8_t retcode[S390_SYSCALL_SIZE];
4120} sigframe;
4121
4122struct target_ucontext {
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004123 target_ulong tuc_flags;
4124 struct target_ucontext *tuc_link;
4125 target_stack_t tuc_stack;
4126 target_sigregs tuc_mcontext;
4127 target_sigset_t tuc_sigmask; /* mask last for extensibility */
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004128};
4129
4130typedef struct {
4131 uint8_t callee_used_stack[__SIGNAL_FRAMESIZE];
4132 uint8_t retcode[S390_SYSCALL_SIZE];
4133 struct target_siginfo info;
4134 struct target_ucontext uc;
4135} rt_sigframe;
4136
4137static inline abi_ulong
Andreas Färber05390242012-02-25 03:37:53 +01004138get_sigframe(struct target_sigaction *ka, CPUS390XState *env, size_t frame_size)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004139{
4140 abi_ulong sp;
4141
4142 /* Default to using normal stack */
4143 sp = env->regs[15];
4144
4145 /* This is the X/Open sanctioned signal stack switching. */
4146 if (ka->sa_flags & TARGET_SA_ONSTACK) {
4147 if (!sas_ss_flags(sp)) {
4148 sp = target_sigaltstack_used.ss_sp +
4149 target_sigaltstack_used.ss_size;
4150 }
4151 }
4152
4153 /* This is the legacy signal stack switching. */
4154 else if (/* FIXME !user_mode(regs) */ 0 &&
4155 !(ka->sa_flags & TARGET_SA_RESTORER) &&
4156 ka->sa_restorer) {
4157 sp = (abi_ulong) ka->sa_restorer;
4158 }
4159
4160 return (sp - frame_size) & -8ul;
4161}
4162
Andreas Färber05390242012-02-25 03:37:53 +01004163static void save_sigregs(CPUS390XState *env, target_sigregs *sregs)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004164{
4165 int i;
4166 //save_access_regs(current->thread.acrs); FIXME
4167
4168 /* Copy a 'clean' PSW mask to the user to avoid leaking
4169 information about whether PER is currently on. */
4170 __put_user(env->psw.mask, &sregs->regs.psw.mask);
4171 __put_user(env->psw.addr, &sregs->regs.psw.addr);
4172 for (i = 0; i < 16; i++) {
4173 __put_user(env->regs[i], &sregs->regs.gprs[i]);
4174 }
4175 for (i = 0; i < 16; i++) {
4176 __put_user(env->aregs[i], &sregs->regs.acrs[i]);
4177 }
4178 /*
4179 * We have to store the fp registers to current->thread.fp_regs
4180 * to merge them with the emulated registers.
4181 */
4182 //save_fp_regs(&current->thread.fp_regs); FIXME
4183 for (i = 0; i < 16; i++) {
4184 __put_user(env->fregs[i].ll, &sregs->fpregs.fprs[i]);
4185 }
4186}
4187
4188static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01004189 target_sigset_t *set, CPUS390XState *env)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004190{
4191 sigframe *frame;
4192 abi_ulong frame_addr;
4193
4194 frame_addr = get_sigframe(ka, env, sizeof(*frame));
4195 qemu_log("%s: frame_addr 0x%llx\n", __FUNCTION__,
4196 (unsigned long long)frame_addr);
4197 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
4198 goto give_sigsegv;
4199 }
4200
4201 qemu_log("%s: 1\n", __FUNCTION__);
4202 if (__put_user(set->sig[0], &frame->sc.oldmask[0])) {
4203 goto give_sigsegv;
4204 }
4205
4206 save_sigregs(env, &frame->sregs);
4207
4208 __put_user((abi_ulong)(unsigned long)&frame->sregs,
4209 (abi_ulong *)&frame->sc.sregs);
4210
4211 /* Set up to return from userspace. If provided, use a stub
4212 already in userspace. */
4213 if (ka->sa_flags & TARGET_SA_RESTORER) {
4214 env->regs[14] = (unsigned long)
4215 ka->sa_restorer | PSW_ADDR_AMODE;
4216 } else {
4217 env->regs[14] = (unsigned long)
4218 frame->retcode | PSW_ADDR_AMODE;
4219 if (__put_user(S390_SYSCALL_OPCODE | TARGET_NR_sigreturn,
4220 (uint16_t *)(frame->retcode)))
4221 goto give_sigsegv;
4222 }
4223
4224 /* Set up backchain. */
4225 if (__put_user(env->regs[15], (abi_ulong *) frame)) {
4226 goto give_sigsegv;
4227 }
4228
4229 /* Set up registers for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02004230 env->regs[15] = frame_addr;
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004231 env->psw.addr = (target_ulong) ka->_sa_handler | PSW_ADDR_AMODE;
4232
4233 env->regs[2] = sig; //map_signal(sig);
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02004234 env->regs[3] = frame_addr += offsetof(typeof(*frame), sc);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004235
4236 /* We forgot to include these in the sigcontext.
4237 To avoid breaking binary compatibility, they are passed as args. */
4238 env->regs[4] = 0; // FIXME: no clue... current->thread.trap_no;
4239 env->regs[5] = 0; // FIXME: no clue... current->thread.prot_addr;
4240
4241 /* Place signal number on stack to allow backtrace from handler. */
4242 if (__put_user(env->regs[2], (int *) &frame->signo)) {
4243 goto give_sigsegv;
4244 }
4245 unlock_user_struct(frame, frame_addr, 1);
4246 return;
4247
4248give_sigsegv:
4249 qemu_log("%s: give_sigsegv\n", __FUNCTION__);
4250 unlock_user_struct(frame, frame_addr, 1);
4251 force_sig(TARGET_SIGSEGV);
4252}
4253
4254static void setup_rt_frame(int sig, struct target_sigaction *ka,
4255 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01004256 target_sigset_t *set, CPUS390XState *env)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004257{
4258 int i;
4259 rt_sigframe *frame;
4260 abi_ulong frame_addr;
4261
4262 frame_addr = get_sigframe(ka, env, sizeof *frame);
4263 qemu_log("%s: frame_addr 0x%llx\n", __FUNCTION__,
4264 (unsigned long long)frame_addr);
4265 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
4266 goto give_sigsegv;
4267 }
4268
4269 qemu_log("%s: 1\n", __FUNCTION__);
4270 if (copy_siginfo_to_user(&frame->info, info)) {
4271 goto give_sigsegv;
4272 }
4273
4274 /* Create the ucontext. */
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004275 __put_user(0, &frame->uc.tuc_flags);
4276 __put_user((abi_ulong)0, (abi_ulong *)&frame->uc.tuc_link);
4277 __put_user(target_sigaltstack_used.ss_sp, &frame->uc.tuc_stack.ss_sp);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004278 __put_user(sas_ss_flags(get_sp_from_cpustate(env)),
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004279 &frame->uc.tuc_stack.ss_flags);
4280 __put_user(target_sigaltstack_used.ss_size, &frame->uc.tuc_stack.ss_size);
4281 save_sigregs(env, &frame->uc.tuc_mcontext);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004282 for (i = 0; i < TARGET_NSIG_WORDS; i++) {
4283 __put_user((abi_ulong)set->sig[i],
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004284 (abi_ulong *)&frame->uc.tuc_sigmask.sig[i]);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004285 }
4286
4287 /* Set up to return from userspace. If provided, use a stub
4288 already in userspace. */
4289 if (ka->sa_flags & TARGET_SA_RESTORER) {
4290 env->regs[14] = (unsigned long) ka->sa_restorer | PSW_ADDR_AMODE;
4291 } else {
4292 env->regs[14] = (unsigned long) frame->retcode | PSW_ADDR_AMODE;
4293 if (__put_user(S390_SYSCALL_OPCODE | TARGET_NR_rt_sigreturn,
4294 (uint16_t *)(frame->retcode))) {
4295 goto give_sigsegv;
4296 }
4297 }
4298
4299 /* Set up backchain. */
4300 if (__put_user(env->regs[15], (abi_ulong *) frame)) {
4301 goto give_sigsegv;
4302 }
4303
4304 /* Set up registers for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02004305 env->regs[15] = frame_addr;
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004306 env->psw.addr = (target_ulong) ka->_sa_handler | PSW_ADDR_AMODE;
4307
4308 env->regs[2] = sig; //map_signal(sig);
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02004309 env->regs[3] = frame_addr + offsetof(typeof(*frame), info);
4310 env->regs[4] = frame_addr + offsetof(typeof(*frame), uc);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004311 return;
4312
4313give_sigsegv:
4314 qemu_log("%s: give_sigsegv\n", __FUNCTION__);
4315 unlock_user_struct(frame, frame_addr, 1);
4316 force_sig(TARGET_SIGSEGV);
4317}
4318
4319static int
Andreas Färber05390242012-02-25 03:37:53 +01004320restore_sigregs(CPUS390XState *env, target_sigregs *sc)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004321{
4322 int err = 0;
4323 int i;
4324
4325 for (i = 0; i < 16; i++) {
4326 err |= __get_user(env->regs[i], &sc->regs.gprs[i]);
4327 }
4328
4329 err |= __get_user(env->psw.mask, &sc->regs.psw.mask);
4330 qemu_log("%s: sc->regs.psw.addr 0x%llx env->psw.addr 0x%llx\n",
4331 __FUNCTION__, (unsigned long long)sc->regs.psw.addr,
4332 (unsigned long long)env->psw.addr);
4333 err |= __get_user(env->psw.addr, &sc->regs.psw.addr);
4334 /* FIXME: 31-bit -> | PSW_ADDR_AMODE */
4335
4336 for (i = 0; i < 16; i++) {
4337 err |= __get_user(env->aregs[i], &sc->regs.acrs[i]);
4338 }
4339 for (i = 0; i < 16; i++) {
4340 err |= __get_user(env->fregs[i].ll, &sc->fpregs.fprs[i]);
4341 }
4342
4343 return err;
4344}
4345
Andreas Färber05390242012-02-25 03:37:53 +01004346long do_sigreturn(CPUS390XState *env)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004347{
4348 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 target_sigset_t target_set;
4353 sigset_t set;
4354
4355 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
4356 goto badframe;
4357 }
4358 if (__get_user(target_set.sig[0], &frame->sc.oldmask[0])) {
4359 goto badframe;
4360 }
4361
4362 target_to_host_sigset_internal(&set, &target_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00004363 do_sigprocmask(SIG_SETMASK, &set, NULL); /* ~_BLOCKABLE? */
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004364
4365 if (restore_sigregs(env, &frame->sregs)) {
4366 goto badframe;
4367 }
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
Andreas Färber05390242012-02-25 03:37:53 +01004378long do_rt_sigreturn(CPUS390XState *env)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004379{
4380 rt_sigframe *frame;
4381 abi_ulong frame_addr = env->regs[15];
4382 qemu_log("%s: frame_addr 0x%llx\n", __FUNCTION__,
4383 (unsigned long long)frame_addr);
4384 sigset_t set;
4385
4386 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
4387 goto badframe;
4388 }
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004389 target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004390
Alex Barcelo1c275922014-03-14 14:36:55 +00004391 do_sigprocmask(SIG_SETMASK, &set, NULL); /* ~_BLOCKABLE? */
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004392
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004393 if (restore_sigregs(env, &frame->uc.tuc_mcontext)) {
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004394 goto badframe;
4395 }
4396
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004397 if (do_sigaltstack(frame_addr + offsetof(rt_sigframe, uc.tuc_stack), 0,
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004398 get_sp_from_cpustate(env)) == -EFAULT) {
4399 goto badframe;
4400 }
4401 unlock_user_struct(frame, frame_addr, 0);
4402 return env->regs[2];
4403
4404badframe:
4405 unlock_user_struct(frame, frame_addr, 0);
4406 force_sig(TARGET_SIGSEGV);
4407 return 0;
4408}
4409
Nathan Froydbcd49332009-05-12 19:13:18 -07004410#elif defined(TARGET_PPC) && !defined(TARGET_PPC64)
4411
4412/* FIXME: Many of the structures are defined for both PPC and PPC64, but
4413 the signal handling is different enough that we haven't implemented
4414 support for PPC64 yet. Hence the restriction above.
4415
4416 There are various #if'd blocks for code for TARGET_PPC64. These
4417 blocks should go away so that we can successfully run 32-bit and
4418 64-bit binaries on a QEMU configured for PPC64. */
4419
4420/* Size of dummy stack frame allocated when calling signal handler.
4421 See arch/powerpc/include/asm/ptrace.h. */
4422#if defined(TARGET_PPC64)
4423#define SIGNAL_FRAMESIZE 128
4424#else
4425#define SIGNAL_FRAMESIZE 64
4426#endif
4427
4428/* See arch/powerpc/include/asm/sigcontext.h. */
4429struct target_sigcontext {
4430 target_ulong _unused[4];
4431 int32_t signal;
4432#if defined(TARGET_PPC64)
4433 int32_t pad0;
4434#endif
4435 target_ulong handler;
4436 target_ulong oldmask;
4437 target_ulong regs; /* struct pt_regs __user * */
4438 /* TODO: PPC64 includes extra bits here. */
4439};
4440
4441/* Indices for target_mcontext.mc_gregs, below.
4442 See arch/powerpc/include/asm/ptrace.h for details. */
4443enum {
4444 TARGET_PT_R0 = 0,
4445 TARGET_PT_R1 = 1,
4446 TARGET_PT_R2 = 2,
4447 TARGET_PT_R3 = 3,
4448 TARGET_PT_R4 = 4,
4449 TARGET_PT_R5 = 5,
4450 TARGET_PT_R6 = 6,
4451 TARGET_PT_R7 = 7,
4452 TARGET_PT_R8 = 8,
4453 TARGET_PT_R9 = 9,
4454 TARGET_PT_R10 = 10,
4455 TARGET_PT_R11 = 11,
4456 TARGET_PT_R12 = 12,
4457 TARGET_PT_R13 = 13,
4458 TARGET_PT_R14 = 14,
4459 TARGET_PT_R15 = 15,
4460 TARGET_PT_R16 = 16,
4461 TARGET_PT_R17 = 17,
4462 TARGET_PT_R18 = 18,
4463 TARGET_PT_R19 = 19,
4464 TARGET_PT_R20 = 20,
4465 TARGET_PT_R21 = 21,
4466 TARGET_PT_R22 = 22,
4467 TARGET_PT_R23 = 23,
4468 TARGET_PT_R24 = 24,
4469 TARGET_PT_R25 = 25,
4470 TARGET_PT_R26 = 26,
4471 TARGET_PT_R27 = 27,
4472 TARGET_PT_R28 = 28,
4473 TARGET_PT_R29 = 29,
4474 TARGET_PT_R30 = 30,
4475 TARGET_PT_R31 = 31,
4476 TARGET_PT_NIP = 32,
4477 TARGET_PT_MSR = 33,
4478 TARGET_PT_ORIG_R3 = 34,
4479 TARGET_PT_CTR = 35,
4480 TARGET_PT_LNK = 36,
4481 TARGET_PT_XER = 37,
4482 TARGET_PT_CCR = 38,
4483 /* Yes, there are two registers with #39. One is 64-bit only. */
4484 TARGET_PT_MQ = 39,
4485 TARGET_PT_SOFTE = 39,
4486 TARGET_PT_TRAP = 40,
4487 TARGET_PT_DAR = 41,
4488 TARGET_PT_DSISR = 42,
4489 TARGET_PT_RESULT = 43,
4490 TARGET_PT_REGS_COUNT = 44
4491};
4492
4493/* See arch/powerpc/include/asm/ucontext.h. Only used for 32-bit PPC;
4494 on 64-bit PPC, sigcontext and mcontext are one and the same. */
4495struct target_mcontext {
4496 target_ulong mc_gregs[48];
4497 /* Includes fpscr. */
4498 uint64_t mc_fregs[33];
4499 target_ulong mc_pad[2];
4500 /* We need to handle Altivec and SPE at the same time, which no
4501 kernel needs to do. Fortunately, the kernel defines this bit to
4502 be Altivec-register-large all the time, rather than trying to
4503 twiddle it based on the specific platform. */
4504 union {
4505 /* SPE vector registers. One extra for SPEFSCR. */
4506 uint32_t spe[33];
4507 /* Altivec vector registers. The packing of VSCR and VRSAVE
4508 varies depending on whether we're PPC64 or not: PPC64 splits
4509 them apart; PPC32 stuffs them together. */
4510#if defined(TARGET_PPC64)
malc3efa9a62009-07-18 13:10:12 +04004511#define QEMU_NVRREG 34
Nathan Froydbcd49332009-05-12 19:13:18 -07004512#else
malc3efa9a62009-07-18 13:10:12 +04004513#define QEMU_NVRREG 33
Nathan Froydbcd49332009-05-12 19:13:18 -07004514#endif
Anthony Liguoric227f092009-10-01 16:12:16 -05004515 ppc_avr_t altivec[QEMU_NVRREG];
malc3efa9a62009-07-18 13:10:12 +04004516#undef QEMU_NVRREG
Nathan Froydbcd49332009-05-12 19:13:18 -07004517 } mc_vregs __attribute__((__aligned__(16)));
4518};
4519
4520struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02004521 target_ulong tuc_flags;
4522 target_ulong tuc_link; /* struct ucontext __user * */
4523 struct target_sigaltstack tuc_stack;
Nathan Froydbcd49332009-05-12 19:13:18 -07004524#if !defined(TARGET_PPC64)
Aurelien Jarno60e99242010-03-29 02:12:51 +02004525 int32_t tuc_pad[7];
4526 target_ulong tuc_regs; /* struct mcontext __user *
Nathan Froydbcd49332009-05-12 19:13:18 -07004527 points to uc_mcontext field */
4528#endif
Aurelien Jarno60e99242010-03-29 02:12:51 +02004529 target_sigset_t tuc_sigmask;
Nathan Froydbcd49332009-05-12 19:13:18 -07004530#if defined(TARGET_PPC64)
Anthony Liguoric227f092009-10-01 16:12:16 -05004531 target_sigset_t unused[15]; /* Allow for uc_sigmask growth */
Aurelien Jarno60e99242010-03-29 02:12:51 +02004532 struct target_sigcontext tuc_mcontext;
Nathan Froydbcd49332009-05-12 19:13:18 -07004533#else
Aurelien Jarno60e99242010-03-29 02:12:51 +02004534 int32_t tuc_maskext[30];
4535 int32_t tuc_pad2[3];
4536 struct target_mcontext tuc_mcontext;
Nathan Froydbcd49332009-05-12 19:13:18 -07004537#endif
4538};
4539
4540/* See arch/powerpc/kernel/signal_32.c. */
4541struct target_sigframe {
4542 struct target_sigcontext sctx;
4543 struct target_mcontext mctx;
4544 int32_t abigap[56];
4545};
4546
4547struct target_rt_sigframe {
4548 struct target_siginfo info;
4549 struct target_ucontext uc;
4550 int32_t abigap[56];
4551};
4552
4553/* We use the mc_pad field for the signal return trampoline. */
4554#define tramp mc_pad
4555
4556/* See arch/powerpc/kernel/signal.c. */
4557static target_ulong get_sigframe(struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01004558 CPUPPCState *env,
Nathan Froydbcd49332009-05-12 19:13:18 -07004559 int frame_size)
4560{
4561 target_ulong oldsp, newsp;
4562
4563 oldsp = env->gpr[1];
4564
4565 if ((ka->sa_flags & TARGET_SA_ONSTACK) &&
Alex Barcelo32a20032012-02-09 23:55:46 +00004566 (sas_ss_flags(oldsp) == 0)) {
Nathan Froydbcd49332009-05-12 19:13:18 -07004567 oldsp = (target_sigaltstack_used.ss_sp
4568 + target_sigaltstack_used.ss_size);
4569 }
4570
4571 newsp = (oldsp - frame_size) & ~0xFUL;
4572
4573 return newsp;
4574}
4575
Andreas Färber05390242012-02-25 03:37:53 +01004576static int save_user_regs(CPUPPCState *env, struct target_mcontext *frame,
Nathan Froydbcd49332009-05-12 19:13:18 -07004577 int sigret)
4578{
4579 target_ulong msr = env->msr;
4580 int i;
4581 target_ulong ccr = 0;
4582
4583 /* In general, the kernel attempts to be intelligent about what it
4584 needs to save for Altivec/FP/SPE registers. We don't care that
4585 much, so we just go ahead and save everything. */
4586
4587 /* Save general registers. */
4588 for (i = 0; i < ARRAY_SIZE(env->gpr); i++) {
4589 if (__put_user(env->gpr[i], &frame->mc_gregs[i])) {
4590 return 1;
4591 }
4592 }
4593 if (__put_user(env->nip, &frame->mc_gregs[TARGET_PT_NIP])
4594 || __put_user(env->ctr, &frame->mc_gregs[TARGET_PT_CTR])
4595 || __put_user(env->lr, &frame->mc_gregs[TARGET_PT_LNK])
4596 || __put_user(env->xer, &frame->mc_gregs[TARGET_PT_XER]))
4597 return 1;
4598
4599 for (i = 0; i < ARRAY_SIZE(env->crf); i++) {
4600 ccr |= env->crf[i] << (32 - ((i + 1) * 4));
4601 }
4602 if (__put_user(ccr, &frame->mc_gregs[TARGET_PT_CCR]))
4603 return 1;
4604
4605 /* Save Altivec registers if necessary. */
4606 if (env->insns_flags & PPC_ALTIVEC) {
4607 for (i = 0; i < ARRAY_SIZE(env->avr); i++) {
Anthony Liguoric227f092009-10-01 16:12:16 -05004608 ppc_avr_t *avr = &env->avr[i];
4609 ppc_avr_t *vreg = &frame->mc_vregs.altivec[i];
Nathan Froydbcd49332009-05-12 19:13:18 -07004610
4611 if (__put_user(avr->u64[0], &vreg->u64[0]) ||
4612 __put_user(avr->u64[1], &vreg->u64[1])) {
4613 return 1;
4614 }
4615 }
4616 /* Set MSR_VR in the saved MSR value to indicate that
4617 frame->mc_vregs contains valid data. */
4618 msr |= MSR_VR;
4619 if (__put_user((uint32_t)env->spr[SPR_VRSAVE],
4620 &frame->mc_vregs.altivec[32].u32[3]))
4621 return 1;
4622 }
4623
4624 /* Save floating point registers. */
4625 if (env->insns_flags & PPC_FLOAT) {
4626 for (i = 0; i < ARRAY_SIZE(env->fpr); i++) {
4627 if (__put_user(env->fpr[i], &frame->mc_fregs[i])) {
4628 return 1;
4629 }
4630 }
4631 if (__put_user((uint64_t) env->fpscr, &frame->mc_fregs[32]))
4632 return 1;
4633 }
4634
4635 /* Save SPE registers. The kernel only saves the high half. */
4636 if (env->insns_flags & PPC_SPE) {
4637#if defined(TARGET_PPC64)
4638 for (i = 0; i < ARRAY_SIZE(env->gpr); i++) {
4639 if (__put_user(env->gpr[i] >> 32, &frame->mc_vregs.spe[i])) {
4640 return 1;
4641 }
4642 }
4643#else
4644 for (i = 0; i < ARRAY_SIZE(env->gprh); i++) {
4645 if (__put_user(env->gprh[i], &frame->mc_vregs.spe[i])) {
4646 return 1;
4647 }
4648 }
4649#endif
4650 /* Set MSR_SPE in the saved MSR value to indicate that
4651 frame->mc_vregs contains valid data. */
4652 msr |= MSR_SPE;
4653 if (__put_user(env->spe_fscr, &frame->mc_vregs.spe[32]))
4654 return 1;
4655 }
4656
4657 /* Store MSR. */
4658 if (__put_user(msr, &frame->mc_gregs[TARGET_PT_MSR]))
4659 return 1;
4660
4661 /* Set up the sigreturn trampoline: li r0,sigret; sc. */
4662 if (sigret) {
4663 if (__put_user(0x38000000UL | sigret, &frame->tramp[0]) ||
4664 __put_user(0x44000002UL, &frame->tramp[1])) {
4665 return 1;
4666 }
4667 }
4668
4669 return 0;
4670}
4671
Andreas Färber05390242012-02-25 03:37:53 +01004672static int restore_user_regs(CPUPPCState *env,
Nathan Froydbcd49332009-05-12 19:13:18 -07004673 struct target_mcontext *frame, int sig)
4674{
4675 target_ulong save_r2 = 0;
4676 target_ulong msr;
4677 target_ulong ccr;
4678
4679 int i;
4680
4681 if (!sig) {
4682 save_r2 = env->gpr[2];
4683 }
4684
4685 /* Restore general registers. */
4686 for (i = 0; i < ARRAY_SIZE(env->gpr); i++) {
4687 if (__get_user(env->gpr[i], &frame->mc_gregs[i])) {
4688 return 1;
4689 }
4690 }
4691 if (__get_user(env->nip, &frame->mc_gregs[TARGET_PT_NIP])
4692 || __get_user(env->ctr, &frame->mc_gregs[TARGET_PT_CTR])
4693 || __get_user(env->lr, &frame->mc_gregs[TARGET_PT_LNK])
4694 || __get_user(env->xer, &frame->mc_gregs[TARGET_PT_XER]))
4695 return 1;
4696 if (__get_user(ccr, &frame->mc_gregs[TARGET_PT_CCR]))
4697 return 1;
4698
4699 for (i = 0; i < ARRAY_SIZE(env->crf); i++) {
4700 env->crf[i] = (ccr >> (32 - ((i + 1) * 4))) & 0xf;
4701 }
4702
4703 if (!sig) {
4704 env->gpr[2] = save_r2;
4705 }
4706 /* Restore MSR. */
4707 if (__get_user(msr, &frame->mc_gregs[TARGET_PT_MSR]))
4708 return 1;
4709
4710 /* If doing signal return, restore the previous little-endian mode. */
4711 if (sig)
4712 env->msr = (env->msr & ~MSR_LE) | (msr & MSR_LE);
4713
4714 /* Restore Altivec registers if necessary. */
4715 if (env->insns_flags & PPC_ALTIVEC) {
4716 for (i = 0; i < ARRAY_SIZE(env->avr); i++) {
Anthony Liguoric227f092009-10-01 16:12:16 -05004717 ppc_avr_t *avr = &env->avr[i];
4718 ppc_avr_t *vreg = &frame->mc_vregs.altivec[i];
Nathan Froydbcd49332009-05-12 19:13:18 -07004719
4720 if (__get_user(avr->u64[0], &vreg->u64[0]) ||
4721 __get_user(avr->u64[1], &vreg->u64[1])) {
4722 return 1;
4723 }
4724 }
4725 /* Set MSR_VEC in the saved MSR value to indicate that
4726 frame->mc_vregs contains valid data. */
4727 if (__get_user(env->spr[SPR_VRSAVE],
4728 (target_ulong *)(&frame->mc_vregs.altivec[32].u32[3])))
4729 return 1;
4730 }
4731
4732 /* Restore floating point registers. */
4733 if (env->insns_flags & PPC_FLOAT) {
4734 uint64_t fpscr;
4735 for (i = 0; i < ARRAY_SIZE(env->fpr); i++) {
4736 if (__get_user(env->fpr[i], &frame->mc_fregs[i])) {
4737 return 1;
4738 }
4739 }
4740 if (__get_user(fpscr, &frame->mc_fregs[32]))
4741 return 1;
4742 env->fpscr = (uint32_t) fpscr;
4743 }
4744
4745 /* Save SPE registers. The kernel only saves the high half. */
4746 if (env->insns_flags & PPC_SPE) {
4747#if defined(TARGET_PPC64)
4748 for (i = 0; i < ARRAY_SIZE(env->gpr); i++) {
4749 uint32_t hi;
4750
4751 if (__get_user(hi, &frame->mc_vregs.spe[i])) {
4752 return 1;
4753 }
4754 env->gpr[i] = ((uint64_t)hi << 32) | ((uint32_t) env->gpr[i]);
4755 }
4756#else
4757 for (i = 0; i < ARRAY_SIZE(env->gprh); i++) {
4758 if (__get_user(env->gprh[i], &frame->mc_vregs.spe[i])) {
4759 return 1;
4760 }
4761 }
4762#endif
4763 if (__get_user(env->spe_fscr, &frame->mc_vregs.spe[32]))
4764 return 1;
4765 }
4766
4767 return 0;
4768}
4769
4770static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01004771 target_sigset_t *set, CPUPPCState *env)
Nathan Froydbcd49332009-05-12 19:13:18 -07004772{
4773 struct target_sigframe *frame;
4774 struct target_sigcontext *sc;
4775 target_ulong frame_addr, newsp;
4776 int err = 0;
4777 int signal;
4778
4779 frame_addr = get_sigframe(ka, env, sizeof(*frame));
4780 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 1))
4781 goto sigsegv;
4782 sc = &frame->sctx;
4783
4784 signal = current_exec_domain_sig(sig);
4785
Samuel Seaybeb526b2013-01-02 10:53:46 +00004786 err |= __put_user(ka->_sa_handler, &sc->handler);
Nathan Froydbcd49332009-05-12 19:13:18 -07004787 err |= __put_user(set->sig[0], &sc->oldmask);
4788#if defined(TARGET_PPC64)
4789 err |= __put_user(set->sig[0] >> 32, &sc->_unused[3]);
4790#else
4791 err |= __put_user(set->sig[1], &sc->_unused[3]);
4792#endif
4793 err |= __put_user(h2g(&frame->mctx), &sc->regs);
4794 err |= __put_user(sig, &sc->signal);
4795
4796 /* Save user regs. */
4797 err |= save_user_regs(env, &frame->mctx, TARGET_NR_sigreturn);
4798
4799 /* The kernel checks for the presence of a VDSO here. We don't
4800 emulate a vdso, so use a sigreturn system call. */
4801 env->lr = (target_ulong) h2g(frame->mctx.tramp);
4802
4803 /* Turn off all fp exceptions. */
4804 env->fpscr = 0;
4805
4806 /* Create a stack frame for the caller of the handler. */
4807 newsp = frame_addr - SIGNAL_FRAMESIZE;
Samuel Seaybeb526b2013-01-02 10:53:46 +00004808 err |= put_user(env->gpr[1], newsp, target_ulong);
Nathan Froydbcd49332009-05-12 19:13:18 -07004809
4810 if (err)
4811 goto sigsegv;
4812
4813 /* Set up registers for signal handler. */
4814 env->gpr[1] = newsp;
4815 env->gpr[3] = signal;
Samuel Seay61993a62013-01-04 14:35:48 +00004816 env->gpr[4] = frame_addr + offsetof(struct target_sigframe, sctx);
Nathan Froydbcd49332009-05-12 19:13:18 -07004817 env->nip = (target_ulong) ka->_sa_handler;
4818 /* Signal handlers are entered in big-endian mode. */
4819 env->msr &= ~MSR_LE;
4820
4821 unlock_user_struct(frame, frame_addr, 1);
4822 return;
4823
4824sigsegv:
4825 unlock_user_struct(frame, frame_addr, 1);
Blue Swirleeacee42012-06-03 16:35:32 +00004826 qemu_log("segfaulting from setup_frame\n");
Riku Voipio66393fb2009-12-04 15:16:32 +02004827 force_sig(TARGET_SIGSEGV);
Nathan Froydbcd49332009-05-12 19:13:18 -07004828}
4829
4830static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05004831 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01004832 target_sigset_t *set, CPUPPCState *env)
Nathan Froydbcd49332009-05-12 19:13:18 -07004833{
4834 struct target_rt_sigframe *rt_sf;
4835 struct target_mcontext *frame;
4836 target_ulong rt_sf_addr, newsp = 0;
4837 int i, err = 0;
4838 int signal;
4839
4840 rt_sf_addr = get_sigframe(ka, env, sizeof(*rt_sf));
4841 if (!lock_user_struct(VERIFY_WRITE, rt_sf, rt_sf_addr, 1))
4842 goto sigsegv;
4843
4844 signal = current_exec_domain_sig(sig);
4845
4846 err |= copy_siginfo_to_user(&rt_sf->info, info);
4847
Aurelien Jarno60e99242010-03-29 02:12:51 +02004848 err |= __put_user(0, &rt_sf->uc.tuc_flags);
4849 err |= __put_user(0, &rt_sf->uc.tuc_link);
Nathan Froydbcd49332009-05-12 19:13:18 -07004850 err |= __put_user((target_ulong)target_sigaltstack_used.ss_sp,
Aurelien Jarno60e99242010-03-29 02:12:51 +02004851 &rt_sf->uc.tuc_stack.ss_sp);
Nathan Froydbcd49332009-05-12 19:13:18 -07004852 err |= __put_user(sas_ss_flags(env->gpr[1]),
Aurelien Jarno60e99242010-03-29 02:12:51 +02004853 &rt_sf->uc.tuc_stack.ss_flags);
Nathan Froydbcd49332009-05-12 19:13:18 -07004854 err |= __put_user(target_sigaltstack_used.ss_size,
Aurelien Jarno60e99242010-03-29 02:12:51 +02004855 &rt_sf->uc.tuc_stack.ss_size);
4856 err |= __put_user(h2g (&rt_sf->uc.tuc_mcontext),
4857 &rt_sf->uc.tuc_regs);
Nathan Froydbcd49332009-05-12 19:13:18 -07004858 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
Aurelien Jarno60e99242010-03-29 02:12:51 +02004859 err |= __put_user(set->sig[i], &rt_sf->uc.tuc_sigmask.sig[i]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004860 }
4861
Aurelien Jarno60e99242010-03-29 02:12:51 +02004862 frame = &rt_sf->uc.tuc_mcontext;
Nathan Froydbcd49332009-05-12 19:13:18 -07004863 err |= save_user_regs(env, frame, TARGET_NR_rt_sigreturn);
4864
4865 /* The kernel checks for the presence of a VDSO here. We don't
4866 emulate a vdso, so use a sigreturn system call. */
4867 env->lr = (target_ulong) h2g(frame->tramp);
4868
4869 /* Turn off all fp exceptions. */
4870 env->fpscr = 0;
4871
4872 /* Create a stack frame for the caller of the handler. */
4873 newsp = rt_sf_addr - (SIGNAL_FRAMESIZE + 16);
4874 err |= __put_user(env->gpr[1], (target_ulong *)(uintptr_t) newsp);
4875
4876 if (err)
4877 goto sigsegv;
4878
4879 /* Set up registers for signal handler. */
4880 env->gpr[1] = newsp;
4881 env->gpr[3] = (target_ulong) signal;
4882 env->gpr[4] = (target_ulong) h2g(&rt_sf->info);
4883 env->gpr[5] = (target_ulong) h2g(&rt_sf->uc);
4884 env->gpr[6] = (target_ulong) h2g(rt_sf);
4885 env->nip = (target_ulong) ka->_sa_handler;
4886 /* Signal handlers are entered in big-endian mode. */
4887 env->msr &= ~MSR_LE;
4888
4889 unlock_user_struct(rt_sf, rt_sf_addr, 1);
4890 return;
4891
4892sigsegv:
4893 unlock_user_struct(rt_sf, rt_sf_addr, 1);
Blue Swirleeacee42012-06-03 16:35:32 +00004894 qemu_log("segfaulting from setup_rt_frame\n");
Riku Voipio66393fb2009-12-04 15:16:32 +02004895 force_sig(TARGET_SIGSEGV);
Nathan Froydbcd49332009-05-12 19:13:18 -07004896
4897}
4898
Andreas Färber05390242012-02-25 03:37:53 +01004899long do_sigreturn(CPUPPCState *env)
Nathan Froydbcd49332009-05-12 19:13:18 -07004900{
4901 struct target_sigcontext *sc = NULL;
4902 struct target_mcontext *sr = NULL;
Peter Maydellb04636f2013-07-29 12:00:31 +01004903 target_ulong sr_addr = 0, sc_addr;
Nathan Froydbcd49332009-05-12 19:13:18 -07004904 sigset_t blocked;
Anthony Liguoric227f092009-10-01 16:12:16 -05004905 target_sigset_t set;
Nathan Froydbcd49332009-05-12 19:13:18 -07004906
4907 sc_addr = env->gpr[1] + SIGNAL_FRAMESIZE;
4908 if (!lock_user_struct(VERIFY_READ, sc, sc_addr, 1))
4909 goto sigsegv;
4910
4911#if defined(TARGET_PPC64)
4912 set.sig[0] = sc->oldmask + ((long)(sc->_unused[3]) << 32);
4913#else
4914 if(__get_user(set.sig[0], &sc->oldmask) ||
4915 __get_user(set.sig[1], &sc->_unused[3]))
4916 goto sigsegv;
4917#endif
4918 target_to_host_sigset_internal(&blocked, &set);
Alex Barcelo1c275922014-03-14 14:36:55 +00004919 do_sigprocmask(SIG_SETMASK, &blocked, NULL);
Nathan Froydbcd49332009-05-12 19:13:18 -07004920
4921 if (__get_user(sr_addr, &sc->regs))
4922 goto sigsegv;
4923 if (!lock_user_struct(VERIFY_READ, sr, sr_addr, 1))
4924 goto sigsegv;
4925 if (restore_user_regs(env, sr, 1))
4926 goto sigsegv;
4927
4928 unlock_user_struct(sr, sr_addr, 1);
4929 unlock_user_struct(sc, sc_addr, 1);
4930 return -TARGET_QEMU_ESIGRETURN;
4931
4932sigsegv:
4933 unlock_user_struct(sr, sr_addr, 1);
4934 unlock_user_struct(sc, sc_addr, 1);
Blue Swirleeacee42012-06-03 16:35:32 +00004935 qemu_log("segfaulting from do_sigreturn\n");
Riku Voipio66393fb2009-12-04 15:16:32 +02004936 force_sig(TARGET_SIGSEGV);
Nathan Froydbcd49332009-05-12 19:13:18 -07004937 return 0;
4938}
4939
4940/* See arch/powerpc/kernel/signal_32.c. */
Andreas Färber05390242012-02-25 03:37:53 +01004941static int do_setcontext(struct target_ucontext *ucp, CPUPPCState *env, int sig)
Nathan Froydbcd49332009-05-12 19:13:18 -07004942{
4943 struct target_mcontext *mcp;
4944 target_ulong mcp_addr;
4945 sigset_t blocked;
Anthony Liguoric227f092009-10-01 16:12:16 -05004946 target_sigset_t set;
Nathan Froydbcd49332009-05-12 19:13:18 -07004947
Aurelien Jarno60e99242010-03-29 02:12:51 +02004948 if (copy_from_user(&set, h2g(ucp) + offsetof(struct target_ucontext, tuc_sigmask),
Nathan Froydbcd49332009-05-12 19:13:18 -07004949 sizeof (set)))
4950 return 1;
4951
4952#if defined(TARGET_PPC64)
4953 fprintf (stderr, "do_setcontext: not implemented\n");
4954 return 0;
4955#else
Aurelien Jarno60e99242010-03-29 02:12:51 +02004956 if (__get_user(mcp_addr, &ucp->tuc_regs))
Nathan Froydbcd49332009-05-12 19:13:18 -07004957 return 1;
4958
4959 if (!lock_user_struct(VERIFY_READ, mcp, mcp_addr, 1))
4960 return 1;
4961
4962 target_to_host_sigset_internal(&blocked, &set);
Alex Barcelo1c275922014-03-14 14:36:55 +00004963 do_sigprocmask(SIG_SETMASK, &blocked, NULL);
Nathan Froydbcd49332009-05-12 19:13:18 -07004964 if (restore_user_regs(env, mcp, sig))
4965 goto sigsegv;
4966
4967 unlock_user_struct(mcp, mcp_addr, 1);
4968 return 0;
4969
4970sigsegv:
4971 unlock_user_struct(mcp, mcp_addr, 1);
4972 return 1;
4973#endif
4974}
4975
Andreas Färber05390242012-02-25 03:37:53 +01004976long do_rt_sigreturn(CPUPPCState *env)
Nathan Froydbcd49332009-05-12 19:13:18 -07004977{
4978 struct target_rt_sigframe *rt_sf = NULL;
4979 target_ulong rt_sf_addr;
4980
4981 rt_sf_addr = env->gpr[1] + SIGNAL_FRAMESIZE + 16;
4982 if (!lock_user_struct(VERIFY_READ, rt_sf, rt_sf_addr, 1))
4983 goto sigsegv;
4984
4985 if (do_setcontext(&rt_sf->uc, env, 1))
4986 goto sigsegv;
4987
4988 do_sigaltstack(rt_sf_addr
Aurelien Jarno60e99242010-03-29 02:12:51 +02004989 + offsetof(struct target_rt_sigframe, uc.tuc_stack),
Nathan Froydbcd49332009-05-12 19:13:18 -07004990 0, env->gpr[1]);
4991
4992 unlock_user_struct(rt_sf, rt_sf_addr, 1);
4993 return -TARGET_QEMU_ESIGRETURN;
4994
4995sigsegv:
4996 unlock_user_struct(rt_sf, rt_sf_addr, 1);
Blue Swirleeacee42012-06-03 16:35:32 +00004997 qemu_log("segfaulting from do_rt_sigreturn\n");
Riku Voipio66393fb2009-12-04 15:16:32 +02004998 force_sig(TARGET_SIGSEGV);
Nathan Froydbcd49332009-05-12 19:13:18 -07004999 return 0;
5000}
5001
Laurent Vivier492a8742009-08-03 16:12:17 +02005002#elif defined(TARGET_M68K)
5003
5004struct target_sigcontext {
5005 abi_ulong sc_mask;
5006 abi_ulong sc_usp;
5007 abi_ulong sc_d0;
5008 abi_ulong sc_d1;
5009 abi_ulong sc_a0;
5010 abi_ulong sc_a1;
5011 unsigned short sc_sr;
5012 abi_ulong sc_pc;
5013};
5014
5015struct target_sigframe
5016{
5017 abi_ulong pretcode;
5018 int sig;
5019 int code;
5020 abi_ulong psc;
5021 char retcode[8];
5022 abi_ulong extramask[TARGET_NSIG_WORDS-1];
5023 struct target_sigcontext sc;
5024};
Laurent Vivier71811552009-08-03 16:12:18 +02005025
Anthony Liguoric227f092009-10-01 16:12:16 -05005026typedef int target_greg_t;
Laurent Vivier71811552009-08-03 16:12:18 +02005027#define TARGET_NGREG 18
Anthony Liguoric227f092009-10-01 16:12:16 -05005028typedef target_greg_t target_gregset_t[TARGET_NGREG];
Laurent Vivier71811552009-08-03 16:12:18 +02005029
5030typedef struct target_fpregset {
5031 int f_fpcntl[3];
5032 int f_fpregs[8*3];
Anthony Liguoric227f092009-10-01 16:12:16 -05005033} target_fpregset_t;
Laurent Vivier71811552009-08-03 16:12:18 +02005034
5035struct target_mcontext {
5036 int version;
Anthony Liguoric227f092009-10-01 16:12:16 -05005037 target_gregset_t gregs;
5038 target_fpregset_t fpregs;
Laurent Vivier71811552009-08-03 16:12:18 +02005039};
5040
5041#define TARGET_MCONTEXT_VERSION 2
5042
5043struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02005044 abi_ulong tuc_flags;
5045 abi_ulong tuc_link;
5046 target_stack_t tuc_stack;
5047 struct target_mcontext tuc_mcontext;
5048 abi_long tuc_filler[80];
5049 target_sigset_t tuc_sigmask;
Laurent Vivier71811552009-08-03 16:12:18 +02005050};
5051
5052struct target_rt_sigframe
5053{
5054 abi_ulong pretcode;
5055 int sig;
5056 abi_ulong pinfo;
5057 abi_ulong puc;
5058 char retcode[8];
5059 struct target_siginfo info;
5060 struct target_ucontext uc;
5061};
Laurent Vivier492a8742009-08-03 16:12:17 +02005062
5063static int
Andreas Färber05390242012-02-25 03:37:53 +01005064setup_sigcontext(struct target_sigcontext *sc, CPUM68KState *env,
5065 abi_ulong mask)
Laurent Vivier492a8742009-08-03 16:12:17 +02005066{
5067 int err = 0;
5068
5069 err |= __put_user(mask, &sc->sc_mask);
5070 err |= __put_user(env->aregs[7], &sc->sc_usp);
5071 err |= __put_user(env->dregs[0], &sc->sc_d0);
5072 err |= __put_user(env->dregs[1], &sc->sc_d1);
5073 err |= __put_user(env->aregs[0], &sc->sc_a0);
5074 err |= __put_user(env->aregs[1], &sc->sc_a1);
5075 err |= __put_user(env->sr, &sc->sc_sr);
5076 err |= __put_user(env->pc, &sc->sc_pc);
5077
5078 return err;
5079}
5080
5081static int
Andreas Färber05390242012-02-25 03:37:53 +01005082restore_sigcontext(CPUM68KState *env, struct target_sigcontext *sc, int *pd0)
Laurent Vivier492a8742009-08-03 16:12:17 +02005083{
5084 int err = 0;
5085 int temp;
5086
5087 err |= __get_user(env->aregs[7], &sc->sc_usp);
5088 err |= __get_user(env->dregs[1], &sc->sc_d1);
5089 err |= __get_user(env->aregs[0], &sc->sc_a0);
5090 err |= __get_user(env->aregs[1], &sc->sc_a1);
5091 err |= __get_user(env->pc, &sc->sc_pc);
5092 err |= __get_user(temp, &sc->sc_sr);
5093 env->sr = (env->sr & 0xff00) | (temp & 0xff);
5094
5095 *pd0 = tswapl(sc->sc_d0);
5096
5097 return err;
5098}
5099
5100/*
5101 * Determine which stack to use..
5102 */
5103static inline abi_ulong
Andreas Färber05390242012-02-25 03:37:53 +01005104get_sigframe(struct target_sigaction *ka, CPUM68KState *regs,
5105 size_t frame_size)
Laurent Vivier492a8742009-08-03 16:12:17 +02005106{
5107 unsigned long sp;
5108
5109 sp = regs->aregs[7];
5110
5111 /* This is the X/Open sanctioned signal stack switching. */
5112 if ((ka->sa_flags & TARGET_SA_ONSTACK) && (sas_ss_flags (sp) == 0)) {
5113 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
5114 }
5115
5116 return ((sp - frame_size) & -8UL);
5117}
5118
5119static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01005120 target_sigset_t *set, CPUM68KState *env)
Laurent Vivier492a8742009-08-03 16:12:17 +02005121{
5122 struct target_sigframe *frame;
5123 abi_ulong frame_addr;
5124 abi_ulong retcode_addr;
5125 abi_ulong sc_addr;
5126 int err = 0;
5127 int i;
5128
5129 frame_addr = get_sigframe(ka, env, sizeof *frame);
5130 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
5131 goto give_sigsegv;
5132
5133 err |= __put_user(sig, &frame->sig);
5134
5135 sc_addr = frame_addr + offsetof(struct target_sigframe, sc);
5136 err |= __put_user(sc_addr, &frame->psc);
5137
5138 err |= setup_sigcontext(&frame->sc, env, set->sig[0]);
5139 if (err)
5140 goto give_sigsegv;
5141
5142 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
5143 if (__put_user(set->sig[i], &frame->extramask[i - 1]))
5144 goto give_sigsegv;
5145 }
5146
5147 /* Set up to return from userspace. */
5148
5149 retcode_addr = frame_addr + offsetof(struct target_sigframe, retcode);
5150 err |= __put_user(retcode_addr, &frame->pretcode);
5151
5152 /* moveq #,d0; trap #0 */
5153
5154 err |= __put_user(0x70004e40 + (TARGET_NR_sigreturn << 16),
5155 (long *)(frame->retcode));
5156
5157 if (err)
5158 goto give_sigsegv;
5159
5160 /* Set up to return from userspace */
5161
5162 env->aregs[7] = frame_addr;
5163 env->pc = ka->_sa_handler;
5164
5165 unlock_user_struct(frame, frame_addr, 1);
5166 return;
5167
5168give_sigsegv:
5169 unlock_user_struct(frame, frame_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02005170 force_sig(TARGET_SIGSEGV);
Laurent Vivier492a8742009-08-03 16:12:17 +02005171}
5172
Laurent Vivier71811552009-08-03 16:12:18 +02005173static inline int target_rt_setup_ucontext(struct target_ucontext *uc,
Andreas Färber05390242012-02-25 03:37:53 +01005174 CPUM68KState *env)
Laurent Vivier71811552009-08-03 16:12:18 +02005175{
Aurelien Jarno60e99242010-03-29 02:12:51 +02005176 target_greg_t *gregs = uc->tuc_mcontext.gregs;
Laurent Vivier71811552009-08-03 16:12:18 +02005177 int err;
5178
Aurelien Jarno60e99242010-03-29 02:12:51 +02005179 err = __put_user(TARGET_MCONTEXT_VERSION, &uc->tuc_mcontext.version);
Laurent Vivier71811552009-08-03 16:12:18 +02005180 err |= __put_user(env->dregs[0], &gregs[0]);
5181 err |= __put_user(env->dregs[1], &gregs[1]);
5182 err |= __put_user(env->dregs[2], &gregs[2]);
5183 err |= __put_user(env->dregs[3], &gregs[3]);
5184 err |= __put_user(env->dregs[4], &gregs[4]);
5185 err |= __put_user(env->dregs[5], &gregs[5]);
5186 err |= __put_user(env->dregs[6], &gregs[6]);
5187 err |= __put_user(env->dregs[7], &gregs[7]);
5188 err |= __put_user(env->aregs[0], &gregs[8]);
5189 err |= __put_user(env->aregs[1], &gregs[9]);
5190 err |= __put_user(env->aregs[2], &gregs[10]);
5191 err |= __put_user(env->aregs[3], &gregs[11]);
5192 err |= __put_user(env->aregs[4], &gregs[12]);
5193 err |= __put_user(env->aregs[5], &gregs[13]);
5194 err |= __put_user(env->aregs[6], &gregs[14]);
5195 err |= __put_user(env->aregs[7], &gregs[15]);
5196 err |= __put_user(env->pc, &gregs[16]);
5197 err |= __put_user(env->sr, &gregs[17]);
5198
5199 return err;
5200}
5201
Andreas Färber05390242012-02-25 03:37:53 +01005202static inline int target_rt_restore_ucontext(CPUM68KState *env,
Laurent Vivier71811552009-08-03 16:12:18 +02005203 struct target_ucontext *uc,
5204 int *pd0)
5205{
5206 int temp;
5207 int err;
Aurelien Jarno60e99242010-03-29 02:12:51 +02005208 target_greg_t *gregs = uc->tuc_mcontext.gregs;
Laurent Vivier71811552009-08-03 16:12:18 +02005209
Aurelien Jarno60e99242010-03-29 02:12:51 +02005210 err = __get_user(temp, &uc->tuc_mcontext.version);
Laurent Vivier71811552009-08-03 16:12:18 +02005211 if (temp != TARGET_MCONTEXT_VERSION)
5212 goto badframe;
5213
5214 /* restore passed registers */
5215 err |= __get_user(env->dregs[0], &gregs[0]);
5216 err |= __get_user(env->dregs[1], &gregs[1]);
5217 err |= __get_user(env->dregs[2], &gregs[2]);
5218 err |= __get_user(env->dregs[3], &gregs[3]);
5219 err |= __get_user(env->dregs[4], &gregs[4]);
5220 err |= __get_user(env->dregs[5], &gregs[5]);
5221 err |= __get_user(env->dregs[6], &gregs[6]);
5222 err |= __get_user(env->dregs[7], &gregs[7]);
5223 err |= __get_user(env->aregs[0], &gregs[8]);
5224 err |= __get_user(env->aregs[1], &gregs[9]);
5225 err |= __get_user(env->aregs[2], &gregs[10]);
5226 err |= __get_user(env->aregs[3], &gregs[11]);
5227 err |= __get_user(env->aregs[4], &gregs[12]);
5228 err |= __get_user(env->aregs[5], &gregs[13]);
5229 err |= __get_user(env->aregs[6], &gregs[14]);
5230 err |= __get_user(env->aregs[7], &gregs[15]);
5231 err |= __get_user(env->pc, &gregs[16]);
5232 err |= __get_user(temp, &gregs[17]);
5233 env->sr = (env->sr & 0xff00) | (temp & 0xff);
5234
5235 *pd0 = env->dregs[0];
5236 return err;
5237
5238badframe:
5239 return 1;
5240}
5241
Laurent Vivier492a8742009-08-03 16:12:17 +02005242static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05005243 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01005244 target_sigset_t *set, CPUM68KState *env)
Laurent Vivier492a8742009-08-03 16:12:17 +02005245{
Laurent Vivier71811552009-08-03 16:12:18 +02005246 struct target_rt_sigframe *frame;
5247 abi_ulong frame_addr;
5248 abi_ulong retcode_addr;
5249 abi_ulong info_addr;
5250 abi_ulong uc_addr;
5251 int err = 0;
5252 int i;
5253
5254 frame_addr = get_sigframe(ka, env, sizeof *frame);
5255 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
5256 goto give_sigsegv;
5257
5258 err |= __put_user(sig, &frame->sig);
5259
5260 info_addr = frame_addr + offsetof(struct target_rt_sigframe, info);
5261 err |= __put_user(info_addr, &frame->pinfo);
5262
5263 uc_addr = frame_addr + offsetof(struct target_rt_sigframe, uc);
5264 err |= __put_user(uc_addr, &frame->puc);
5265
5266 err |= copy_siginfo_to_user(&frame->info, info);
5267
5268 /* Create the ucontext */
5269
Aurelien Jarno60e99242010-03-29 02:12:51 +02005270 err |= __put_user(0, &frame->uc.tuc_flags);
5271 err |= __put_user(0, &frame->uc.tuc_link);
Laurent Vivier71811552009-08-03 16:12:18 +02005272 err |= __put_user(target_sigaltstack_used.ss_sp,
Aurelien Jarno60e99242010-03-29 02:12:51 +02005273 &frame->uc.tuc_stack.ss_sp);
Laurent Vivier71811552009-08-03 16:12:18 +02005274 err |= __put_user(sas_ss_flags(env->aregs[7]),
Aurelien Jarno60e99242010-03-29 02:12:51 +02005275 &frame->uc.tuc_stack.ss_flags);
Laurent Vivier71811552009-08-03 16:12:18 +02005276 err |= __put_user(target_sigaltstack_used.ss_size,
Aurelien Jarno60e99242010-03-29 02:12:51 +02005277 &frame->uc.tuc_stack.ss_size);
Laurent Vivier71811552009-08-03 16:12:18 +02005278 err |= target_rt_setup_ucontext(&frame->uc, env);
5279
5280 if (err)
5281 goto give_sigsegv;
5282
5283 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
Aurelien Jarno60e99242010-03-29 02:12:51 +02005284 if (__put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]))
Laurent Vivier71811552009-08-03 16:12:18 +02005285 goto give_sigsegv;
5286 }
5287
5288 /* Set up to return from userspace. */
5289
5290 retcode_addr = frame_addr + offsetof(struct target_sigframe, retcode);
5291 err |= __put_user(retcode_addr, &frame->pretcode);
5292
5293 /* moveq #,d0; notb d0; trap #0 */
5294
5295 err |= __put_user(0x70004600 + ((TARGET_NR_rt_sigreturn ^ 0xff) << 16),
5296 (long *)(frame->retcode + 0));
5297 err |= __put_user(0x4e40, (short *)(frame->retcode + 4));
5298
5299 if (err)
5300 goto give_sigsegv;
5301
5302 /* Set up to return from userspace */
5303
5304 env->aregs[7] = frame_addr;
5305 env->pc = ka->_sa_handler;
5306
5307 unlock_user_struct(frame, frame_addr, 1);
5308 return;
5309
5310give_sigsegv:
5311 unlock_user_struct(frame, frame_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02005312 force_sig(TARGET_SIGSEGV);
Laurent Vivier492a8742009-08-03 16:12:17 +02005313}
5314
Andreas Färber05390242012-02-25 03:37:53 +01005315long do_sigreturn(CPUM68KState *env)
Laurent Vivier492a8742009-08-03 16:12:17 +02005316{
5317 struct target_sigframe *frame;
5318 abi_ulong frame_addr = env->aregs[7] - 4;
Anthony Liguoric227f092009-10-01 16:12:16 -05005319 target_sigset_t target_set;
Laurent Vivier492a8742009-08-03 16:12:17 +02005320 sigset_t set;
5321 int d0, i;
5322
5323 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
5324 goto badframe;
5325
5326 /* set blocked signals */
5327
5328 if (__get_user(target_set.sig[0], &frame->sc.sc_mask))
5329 goto badframe;
5330
5331 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
5332 if (__get_user(target_set.sig[i], &frame->extramask[i - 1]))
5333 goto badframe;
5334 }
5335
5336 target_to_host_sigset_internal(&set, &target_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00005337 do_sigprocmask(SIG_SETMASK, &set, NULL);
Laurent Vivier492a8742009-08-03 16:12:17 +02005338
5339 /* restore registers */
5340
5341 if (restore_sigcontext(env, &frame->sc, &d0))
5342 goto badframe;
5343
5344 unlock_user_struct(frame, frame_addr, 0);
5345 return d0;
5346
5347badframe:
5348 unlock_user_struct(frame, frame_addr, 0);
5349 force_sig(TARGET_SIGSEGV);
5350 return 0;
5351}
5352
Andreas Färber05390242012-02-25 03:37:53 +01005353long do_rt_sigreturn(CPUM68KState *env)
Laurent Vivier492a8742009-08-03 16:12:17 +02005354{
Laurent Vivier71811552009-08-03 16:12:18 +02005355 struct target_rt_sigframe *frame;
5356 abi_ulong frame_addr = env->aregs[7] - 4;
Anthony Liguoric227f092009-10-01 16:12:16 -05005357 target_sigset_t target_set;
Laurent Vivier71811552009-08-03 16:12:18 +02005358 sigset_t set;
5359 int d0;
5360
5361 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
5362 goto badframe;
5363
5364 target_to_host_sigset_internal(&set, &target_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00005365 do_sigprocmask(SIG_SETMASK, &set, NULL);
Laurent Vivier71811552009-08-03 16:12:18 +02005366
5367 /* restore registers */
5368
5369 if (target_rt_restore_ucontext(env, &frame->uc, &d0))
5370 goto badframe;
5371
5372 if (do_sigaltstack(frame_addr +
Aurelien Jarno60e99242010-03-29 02:12:51 +02005373 offsetof(struct target_rt_sigframe, uc.tuc_stack),
Laurent Vivier71811552009-08-03 16:12:18 +02005374 0, get_sp_from_cpustate(env)) == -EFAULT)
5375 goto badframe;
5376
5377 unlock_user_struct(frame, frame_addr, 0);
5378 return d0;
5379
5380badframe:
5381 unlock_user_struct(frame, frame_addr, 0);
5382 force_sig(TARGET_SIGSEGV);
5383 return 0;
Laurent Vivier492a8742009-08-03 16:12:17 +02005384}
5385
Richard Henderson6049f4f2009-12-27 18:30:03 -08005386#elif defined(TARGET_ALPHA)
5387
5388struct target_sigcontext {
5389 abi_long sc_onstack;
5390 abi_long sc_mask;
5391 abi_long sc_pc;
5392 abi_long sc_ps;
5393 abi_long sc_regs[32];
5394 abi_long sc_ownedfp;
5395 abi_long sc_fpregs[32];
5396 abi_ulong sc_fpcr;
5397 abi_ulong sc_fp_control;
5398 abi_ulong sc_reserved1;
5399 abi_ulong sc_reserved2;
5400 abi_ulong sc_ssize;
5401 abi_ulong sc_sbase;
5402 abi_ulong sc_traparg_a0;
5403 abi_ulong sc_traparg_a1;
5404 abi_ulong sc_traparg_a2;
5405 abi_ulong sc_fp_trap_pc;
5406 abi_ulong sc_fp_trigger_sum;
5407 abi_ulong sc_fp_trigger_inst;
5408};
5409
5410struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02005411 abi_ulong tuc_flags;
5412 abi_ulong tuc_link;
5413 abi_ulong tuc_osf_sigmask;
5414 target_stack_t tuc_stack;
5415 struct target_sigcontext tuc_mcontext;
5416 target_sigset_t tuc_sigmask;
Richard Henderson6049f4f2009-12-27 18:30:03 -08005417};
5418
5419struct target_sigframe {
5420 struct target_sigcontext sc;
5421 unsigned int retcode[3];
5422};
5423
5424struct target_rt_sigframe {
5425 target_siginfo_t info;
5426 struct target_ucontext uc;
5427 unsigned int retcode[3];
5428};
5429
5430#define INSN_MOV_R30_R16 0x47fe0410
5431#define INSN_LDI_R0 0x201f0000
5432#define INSN_CALLSYS 0x00000083
5433
Andreas Färber05390242012-02-25 03:37:53 +01005434static int setup_sigcontext(struct target_sigcontext *sc, CPUAlphaState *env,
Richard Henderson6049f4f2009-12-27 18:30:03 -08005435 abi_ulong frame_addr, target_sigset_t *set)
5436{
5437 int i, err = 0;
5438
5439 err |= __put_user(on_sig_stack(frame_addr), &sc->sc_onstack);
5440 err |= __put_user(set->sig[0], &sc->sc_mask);
5441 err |= __put_user(env->pc, &sc->sc_pc);
5442 err |= __put_user(8, &sc->sc_ps);
5443
5444 for (i = 0; i < 31; ++i) {
5445 err |= __put_user(env->ir[i], &sc->sc_regs[i]);
5446 }
5447 err |= __put_user(0, &sc->sc_regs[31]);
5448
5449 for (i = 0; i < 31; ++i) {
5450 err |= __put_user(env->fir[i], &sc->sc_fpregs[i]);
5451 }
5452 err |= __put_user(0, &sc->sc_fpregs[31]);
5453 err |= __put_user(cpu_alpha_load_fpcr(env), &sc->sc_fpcr);
5454
5455 err |= __put_user(0, &sc->sc_traparg_a0); /* FIXME */
5456 err |= __put_user(0, &sc->sc_traparg_a1); /* FIXME */
5457 err |= __put_user(0, &sc->sc_traparg_a2); /* FIXME */
5458
5459 return err;
5460}
5461
Andreas Färber05390242012-02-25 03:37:53 +01005462static int restore_sigcontext(CPUAlphaState *env,
5463 struct target_sigcontext *sc)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005464{
5465 uint64_t fpcr;
5466 int i, err = 0;
5467
5468 err |= __get_user(env->pc, &sc->sc_pc);
5469
5470 for (i = 0; i < 31; ++i) {
5471 err |= __get_user(env->ir[i], &sc->sc_regs[i]);
5472 }
5473 for (i = 0; i < 31; ++i) {
5474 err |= __get_user(env->fir[i], &sc->sc_fpregs[i]);
5475 }
5476
5477 err |= __get_user(fpcr, &sc->sc_fpcr);
5478 cpu_alpha_store_fpcr(env, fpcr);
5479
5480 return err;
5481}
5482
5483static inline abi_ulong get_sigframe(struct target_sigaction *sa,
Andreas Färber05390242012-02-25 03:37:53 +01005484 CPUAlphaState *env,
5485 unsigned long framesize)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005486{
5487 abi_ulong sp = env->ir[IR_SP];
5488
5489 /* This is the X/Open sanctioned signal stack switching. */
5490 if ((sa->sa_flags & TARGET_SA_ONSTACK) != 0 && !sas_ss_flags(sp)) {
5491 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
5492 }
5493 return (sp - framesize) & -32;
5494}
5495
5496static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01005497 target_sigset_t *set, CPUAlphaState *env)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005498{
5499 abi_ulong frame_addr, r26;
5500 struct target_sigframe *frame;
5501 int err = 0;
5502
5503 frame_addr = get_sigframe(ka, env, sizeof(*frame));
5504 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
5505 goto give_sigsegv;
5506 }
5507
5508 err |= setup_sigcontext(&frame->sc, env, frame_addr, set);
5509
5510 if (ka->sa_restorer) {
5511 r26 = ka->sa_restorer;
5512 } else {
5513 err |= __put_user(INSN_MOV_R30_R16, &frame->retcode[0]);
5514 err |= __put_user(INSN_LDI_R0 + TARGET_NR_sigreturn,
5515 &frame->retcode[1]);
5516 err |= __put_user(INSN_CALLSYS, &frame->retcode[2]);
5517 /* imb() */
5518 r26 = frame_addr;
5519 }
5520
5521 unlock_user_struct(frame, frame_addr, 1);
5522
5523 if (err) {
5524 give_sigsegv:
5525 if (sig == TARGET_SIGSEGV) {
5526 ka->_sa_handler = TARGET_SIG_DFL;
5527 }
5528 force_sig(TARGET_SIGSEGV);
5529 }
5530
5531 env->ir[IR_RA] = r26;
5532 env->ir[IR_PV] = env->pc = ka->_sa_handler;
5533 env->ir[IR_A0] = sig;
5534 env->ir[IR_A1] = 0;
5535 env->ir[IR_A2] = frame_addr + offsetof(struct target_sigframe, sc);
5536 env->ir[IR_SP] = frame_addr;
5537}
5538
5539static void setup_rt_frame(int sig, struct target_sigaction *ka,
5540 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01005541 target_sigset_t *set, CPUAlphaState *env)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005542{
5543 abi_ulong frame_addr, r26;
5544 struct target_rt_sigframe *frame;
5545 int i, err = 0;
5546
5547 frame_addr = get_sigframe(ka, env, sizeof(*frame));
5548 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
5549 goto give_sigsegv;
5550 }
5551
5552 err |= copy_siginfo_to_user(&frame->info, info);
5553
Aurelien Jarno60e99242010-03-29 02:12:51 +02005554 err |= __put_user(0, &frame->uc.tuc_flags);
5555 err |= __put_user(0, &frame->uc.tuc_link);
5556 err |= __put_user(set->sig[0], &frame->uc.tuc_osf_sigmask);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005557 err |= __put_user(target_sigaltstack_used.ss_sp,
Aurelien Jarno60e99242010-03-29 02:12:51 +02005558 &frame->uc.tuc_stack.ss_sp);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005559 err |= __put_user(sas_ss_flags(env->ir[IR_SP]),
Aurelien Jarno60e99242010-03-29 02:12:51 +02005560 &frame->uc.tuc_stack.ss_flags);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005561 err |= __put_user(target_sigaltstack_used.ss_size,
Aurelien Jarno60e99242010-03-29 02:12:51 +02005562 &frame->uc.tuc_stack.ss_size);
5563 err |= setup_sigcontext(&frame->uc.tuc_mcontext, env, frame_addr, set);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005564 for (i = 0; i < TARGET_NSIG_WORDS; ++i) {
Aurelien Jarno60e99242010-03-29 02:12:51 +02005565 err |= __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005566 }
5567
5568 if (ka->sa_restorer) {
5569 r26 = ka->sa_restorer;
5570 } else {
5571 err |= __put_user(INSN_MOV_R30_R16, &frame->retcode[0]);
5572 err |= __put_user(INSN_LDI_R0 + TARGET_NR_rt_sigreturn,
5573 &frame->retcode[1]);
5574 err |= __put_user(INSN_CALLSYS, &frame->retcode[2]);
5575 /* imb(); */
5576 r26 = frame_addr;
5577 }
5578
5579 if (err) {
5580 give_sigsegv:
5581 if (sig == TARGET_SIGSEGV) {
5582 ka->_sa_handler = TARGET_SIG_DFL;
5583 }
5584 force_sig(TARGET_SIGSEGV);
5585 }
5586
5587 env->ir[IR_RA] = r26;
5588 env->ir[IR_PV] = env->pc = ka->_sa_handler;
5589 env->ir[IR_A0] = sig;
5590 env->ir[IR_A1] = frame_addr + offsetof(struct target_rt_sigframe, info);
5591 env->ir[IR_A2] = frame_addr + offsetof(struct target_rt_sigframe, uc);
5592 env->ir[IR_SP] = frame_addr;
5593}
5594
Andreas Färber05390242012-02-25 03:37:53 +01005595long do_sigreturn(CPUAlphaState *env)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005596{
5597 struct target_sigcontext *sc;
5598 abi_ulong sc_addr = env->ir[IR_A0];
5599 target_sigset_t target_set;
5600 sigset_t set;
5601
5602 if (!lock_user_struct(VERIFY_READ, sc, sc_addr, 1)) {
5603 goto badframe;
5604 }
5605
5606 target_sigemptyset(&target_set);
5607 if (__get_user(target_set.sig[0], &sc->sc_mask)) {
5608 goto badframe;
5609 }
5610
5611 target_to_host_sigset_internal(&set, &target_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00005612 do_sigprocmask(SIG_SETMASK, &set, NULL);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005613
5614 if (restore_sigcontext(env, sc)) {
5615 goto badframe;
5616 }
5617 unlock_user_struct(sc, sc_addr, 0);
5618 return env->ir[IR_V0];
5619
5620 badframe:
5621 unlock_user_struct(sc, sc_addr, 0);
5622 force_sig(TARGET_SIGSEGV);
5623}
5624
Andreas Färber05390242012-02-25 03:37:53 +01005625long do_rt_sigreturn(CPUAlphaState *env)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005626{
5627 abi_ulong frame_addr = env->ir[IR_A0];
5628 struct target_rt_sigframe *frame;
5629 sigset_t set;
5630
5631 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
5632 goto badframe;
5633 }
Aurelien Jarno60e99242010-03-29 02:12:51 +02005634 target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
Alex Barcelo1c275922014-03-14 14:36:55 +00005635 do_sigprocmask(SIG_SETMASK, &set, NULL);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005636
Aurelien Jarno60e99242010-03-29 02:12:51 +02005637 if (restore_sigcontext(env, &frame->uc.tuc_mcontext)) {
Richard Henderson6049f4f2009-12-27 18:30:03 -08005638 goto badframe;
5639 }
5640 if (do_sigaltstack(frame_addr + offsetof(struct target_rt_sigframe,
Aurelien Jarno60e99242010-03-29 02:12:51 +02005641 uc.tuc_stack),
Richard Henderson6049f4f2009-12-27 18:30:03 -08005642 0, env->ir[IR_SP]) == -EFAULT) {
5643 goto badframe;
5644 }
5645
5646 unlock_user_struct(frame, frame_addr, 0);
5647 return env->ir[IR_V0];
5648
5649
5650 badframe:
5651 unlock_user_struct(frame, frame_addr, 0);
5652 force_sig(TARGET_SIGSEGV);
5653}
5654
bellardb346ff42003-06-15 20:05:50 +00005655#else
5656
pbrook624f7972008-05-31 16:11:38 +00005657static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber9349b4f2012-03-14 01:38:32 +01005658 target_sigset_t *set, CPUArchState *env)
bellardb346ff42003-06-15 20:05:50 +00005659{
5660 fprintf(stderr, "setup_frame: not implemented\n");
5661}
5662
pbrook624f7972008-05-31 16:11:38 +00005663static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05005664 target_siginfo_t *info,
Andreas Färber9349b4f2012-03-14 01:38:32 +01005665 target_sigset_t *set, CPUArchState *env)
bellardb346ff42003-06-15 20:05:50 +00005666{
5667 fprintf(stderr, "setup_rt_frame: not implemented\n");
5668}
5669
Andreas Färber9349b4f2012-03-14 01:38:32 +01005670long do_sigreturn(CPUArchState *env)
bellardb346ff42003-06-15 20:05:50 +00005671{
5672 fprintf(stderr, "do_sigreturn: not implemented\n");
bellardf8b0aa22007-11-11 23:03:42 +00005673 return -TARGET_ENOSYS;
bellardb346ff42003-06-15 20:05:50 +00005674}
5675
Andreas Färber9349b4f2012-03-14 01:38:32 +01005676long do_rt_sigreturn(CPUArchState *env)
bellardb346ff42003-06-15 20:05:50 +00005677{
5678 fprintf(stderr, "do_rt_sigreturn: not implemented\n");
bellardf8b0aa22007-11-11 23:03:42 +00005679 return -TARGET_ENOSYS;
bellardb346ff42003-06-15 20:05:50 +00005680}
5681
bellard66fb9762003-03-23 01:06:05 +00005682#endif
5683
Andreas Färber9349b4f2012-03-14 01:38:32 +01005684void process_pending_signals(CPUArchState *cpu_env)
bellard66fb9762003-03-23 01:06:05 +00005685{
Andreas Färberdb6b81d2013-06-27 19:49:31 +02005686 CPUState *cpu = ENV_GET_CPU(cpu_env);
bellard66fb9762003-03-23 01:06:05 +00005687 int sig;
blueswir1992f48a2007-10-14 16:27:31 +00005688 abi_ulong handler;
bellard9de5e442003-03-23 16:49:39 +00005689 sigset_t set, old_set;
Anthony Liguoric227f092009-10-01 16:12:16 -05005690 target_sigset_t target_old_set;
pbrook624f7972008-05-31 16:11:38 +00005691 struct emulated_sigtable *k;
5692 struct target_sigaction *sa;
bellard66fb9762003-03-23 01:06:05 +00005693 struct sigqueue *q;
Andreas Färber0429a972013-08-26 18:14:44 +02005694 TaskState *ts = cpu->opaque;
ths3b46e622007-09-17 08:09:54 +00005695
pbrook624f7972008-05-31 16:11:38 +00005696 if (!ts->signal_pending)
bellard31e31b82003-02-18 22:55:36 +00005697 return;
5698
pbrook624f7972008-05-31 16:11:38 +00005699 /* FIXME: This is not threadsafe. */
5700 k = ts->sigtab;
bellard66fb9762003-03-23 01:06:05 +00005701 for(sig = 1; sig <= TARGET_NSIG; sig++) {
5702 if (k->pending)
bellard31e31b82003-02-18 22:55:36 +00005703 goto handle_signal;
bellard66fb9762003-03-23 01:06:05 +00005704 k++;
bellard31e31b82003-02-18 22:55:36 +00005705 }
5706 /* if no signal is pending, just return */
pbrook624f7972008-05-31 16:11:38 +00005707 ts->signal_pending = 0;
bellard31e31b82003-02-18 22:55:36 +00005708 return;
bellard66fb9762003-03-23 01:06:05 +00005709
bellard31e31b82003-02-18 22:55:36 +00005710 handle_signal:
bellard66fb9762003-03-23 01:06:05 +00005711#ifdef DEBUG_SIGNAL
bellardbc8a22c2003-03-30 21:02:40 +00005712 fprintf(stderr, "qemu: process signal %d\n", sig);
bellard66fb9762003-03-23 01:06:05 +00005713#endif
5714 /* dequeue signal */
5715 q = k->first;
5716 k->first = q->next;
5717 if (!k->first)
5718 k->pending = 0;
ths3b46e622007-09-17 08:09:54 +00005719
Andreas Färberdb6b81d2013-06-27 19:49:31 +02005720 sig = gdb_handlesig(cpu, sig);
bellard1fddef42005-04-17 19:16:13 +00005721 if (!sig) {
aurel32ca587a82008-12-18 22:44:13 +00005722 sa = NULL;
5723 handler = TARGET_SIG_IGN;
5724 } else {
5725 sa = &sigact_table[sig - 1];
5726 handler = sa->_sa_handler;
bellard1fddef42005-04-17 19:16:13 +00005727 }
bellard66fb9762003-03-23 01:06:05 +00005728
bellard66fb9762003-03-23 01:06:05 +00005729 if (handler == TARGET_SIG_DFL) {
aurel32ca587a82008-12-18 22:44:13 +00005730 /* default handler : ignore some signal. The other are job control or fatal */
5731 if (sig == TARGET_SIGTSTP || sig == TARGET_SIGTTIN || sig == TARGET_SIGTTOU) {
5732 kill(getpid(),SIGSTOP);
5733 } else if (sig != TARGET_SIGCHLD &&
5734 sig != TARGET_SIGURG &&
5735 sig != TARGET_SIGWINCH &&
5736 sig != TARGET_SIGCONT) {
bellard66fb9762003-03-23 01:06:05 +00005737 force_sig(sig);
5738 }
5739 } else if (handler == TARGET_SIG_IGN) {
5740 /* ignore sig */
5741 } else if (handler == TARGET_SIG_ERR) {
5742 force_sig(sig);
5743 } else {
bellard9de5e442003-03-23 16:49:39 +00005744 /* compute the blocked signals during the handler execution */
pbrook624f7972008-05-31 16:11:38 +00005745 target_to_host_sigset(&set, &sa->sa_mask);
bellard9de5e442003-03-23 16:49:39 +00005746 /* SA_NODEFER indicates that the current signal should not be
5747 blocked during the handler */
pbrook624f7972008-05-31 16:11:38 +00005748 if (!(sa->sa_flags & TARGET_SA_NODEFER))
bellard9de5e442003-03-23 16:49:39 +00005749 sigaddset(&set, target_to_host_signal(sig));
ths3b46e622007-09-17 08:09:54 +00005750
bellard9de5e442003-03-23 16:49:39 +00005751 /* block signals in the handler using Linux */
Alex Barcelo1c275922014-03-14 14:36:55 +00005752 do_sigprocmask(SIG_BLOCK, &set, &old_set);
bellard9de5e442003-03-23 16:49:39 +00005753 /* save the previous blocked signal state to restore it at the
5754 end of the signal execution (see do_sigreturn) */
bellard92319442004-06-19 16:58:13 +00005755 host_to_target_sigset_internal(&target_old_set, &old_set);
bellard9de5e442003-03-23 16:49:39 +00005756
bellardbc8a22c2003-03-30 21:02:40 +00005757 /* if the CPU is in VM86 mode, we restore the 32 bit values */
j_mayer84409dd2007-04-06 08:56:50 +00005758#if defined(TARGET_I386) && !defined(TARGET_X86_64)
bellardbc8a22c2003-03-30 21:02:40 +00005759 {
5760 CPUX86State *env = cpu_env;
5761 if (env->eflags & VM_MASK)
5762 save_v86_state(env);
5763 }
5764#endif
bellard9de5e442003-03-23 16:49:39 +00005765 /* prepare the stack frame of the virtual CPU */
Richard Hendersonff970902013-02-10 10:30:42 -08005766#if defined(TARGET_ABI_MIPSN32) || defined(TARGET_ABI_MIPSN64)
5767 /* These targets do not have traditional signals. */
5768 setup_rt_frame(sig, sa, &q->info, &target_old_set, cpu_env);
5769#else
pbrook624f7972008-05-31 16:11:38 +00005770 if (sa->sa_flags & TARGET_SA_SIGINFO)
5771 setup_rt_frame(sig, sa, &q->info, &target_old_set, cpu_env);
bellard66fb9762003-03-23 01:06:05 +00005772 else
pbrook624f7972008-05-31 16:11:38 +00005773 setup_frame(sig, sa, &target_old_set, cpu_env);
Richard Hendersonff970902013-02-10 10:30:42 -08005774#endif
pbrook624f7972008-05-31 16:11:38 +00005775 if (sa->sa_flags & TARGET_SA_RESETHAND)
5776 sa->_sa_handler = TARGET_SIG_DFL;
bellard31e31b82003-02-18 22:55:36 +00005777 }
bellard66fb9762003-03-23 01:06:05 +00005778 if (q != &k->info)
pbrook624f7972008-05-31 16:11:38 +00005779 free_sigqueue(cpu_env, q);
bellard31e31b82003-02-18 22:55:36 +00005780}