blob: a89853d4ebfa2509e4b6060f56f80b4063498d3c [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 */
Peter Maydelld39594e2016-01-26 18:17:02 +000019#include "qemu/osdep.h"
bellard31e31b82003-02-18 22:55:36 +000020#include <sys/ucontext.h>
Mika Westerbergedf8e2a2009-04-07 09:57:11 +030021#include <sys/resource.h>
bellard31e31b82003-02-18 22:55:36 +000022
bellard3ef693a2003-03-23 20:17:16 +000023#include "qemu.h"
blueswir17d99a002009-01-14 19:00:36 +000024#include "qemu-common.h"
blueswir1992f48a2007-10-14 16:27:31 +000025#include "target_signal.h"
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +010026#include "trace.h"
bellard66fb9762003-03-23 01:06:05 +000027
blueswir1249c4c32008-10-05 11:09:37 +000028static struct target_sigaltstack target_sigaltstack_used = {
thsa04e1342007-09-27 13:57:58 +000029 .ss_sp = 0,
30 .ss_size = 0,
31 .ss_flags = TARGET_SS_DISABLE,
32};
33
pbrook624f7972008-05-31 16:11:38 +000034static struct target_sigaction sigact_table[TARGET_NSIG];
bellard31e31b82003-02-18 22:55:36 +000035
ths5fafdf22007-09-16 21:08:06 +000036static void host_signal_handler(int host_signum, siginfo_t *info,
bellard66fb9762003-03-23 01:06:05 +000037 void *puc);
38
Arnaud Patard3ca05582009-03-30 01:18:20 +020039static uint8_t host_to_target_signal_table[_NSIG] = {
bellard9e5f5282003-07-13 17:33:54 +000040 [SIGHUP] = TARGET_SIGHUP,
41 [SIGINT] = TARGET_SIGINT,
42 [SIGQUIT] = TARGET_SIGQUIT,
43 [SIGILL] = TARGET_SIGILL,
44 [SIGTRAP] = TARGET_SIGTRAP,
45 [SIGABRT] = TARGET_SIGABRT,
bellard01e3b762003-09-30 21:10:14 +000046/* [SIGIOT] = TARGET_SIGIOT,*/
bellard9e5f5282003-07-13 17:33:54 +000047 [SIGBUS] = TARGET_SIGBUS,
48 [SIGFPE] = TARGET_SIGFPE,
49 [SIGKILL] = TARGET_SIGKILL,
50 [SIGUSR1] = TARGET_SIGUSR1,
51 [SIGSEGV] = TARGET_SIGSEGV,
52 [SIGUSR2] = TARGET_SIGUSR2,
53 [SIGPIPE] = TARGET_SIGPIPE,
54 [SIGALRM] = TARGET_SIGALRM,
55 [SIGTERM] = TARGET_SIGTERM,
56#ifdef SIGSTKFLT
57 [SIGSTKFLT] = TARGET_SIGSTKFLT,
58#endif
59 [SIGCHLD] = TARGET_SIGCHLD,
60 [SIGCONT] = TARGET_SIGCONT,
61 [SIGSTOP] = TARGET_SIGSTOP,
62 [SIGTSTP] = TARGET_SIGTSTP,
63 [SIGTTIN] = TARGET_SIGTTIN,
64 [SIGTTOU] = TARGET_SIGTTOU,
65 [SIGURG] = TARGET_SIGURG,
66 [SIGXCPU] = TARGET_SIGXCPU,
67 [SIGXFSZ] = TARGET_SIGXFSZ,
68 [SIGVTALRM] = TARGET_SIGVTALRM,
69 [SIGPROF] = TARGET_SIGPROF,
70 [SIGWINCH] = TARGET_SIGWINCH,
71 [SIGIO] = TARGET_SIGIO,
72 [SIGPWR] = TARGET_SIGPWR,
73 [SIGSYS] = TARGET_SIGSYS,
74 /* next signals stay the same */
pbrook624f7972008-05-31 16:11:38 +000075 /* Nasty hack: Reverse SIGRTMIN and SIGRTMAX to avoid overlap with
Dong Xu Wangb4916d72011-11-22 18:06:17 +080076 host libpthread signals. This assumes no one actually uses SIGRTMAX :-/
pbrook624f7972008-05-31 16:11:38 +000077 To fix this properly we need to do manual signal delivery multiplexed
78 over a single host signal. */
79 [__SIGRTMIN] = __SIGRTMAX,
80 [__SIGRTMAX] = __SIGRTMIN,
bellard9e5f5282003-07-13 17:33:54 +000081};
Arnaud Patard3ca05582009-03-30 01:18:20 +020082static uint8_t target_to_host_signal_table[_NSIG];
bellard9e5f5282003-07-13 17:33:54 +000083
thsa04e1342007-09-27 13:57:58 +000084static inline int on_sig_stack(unsigned long sp)
85{
86 return (sp - target_sigaltstack_used.ss_sp
87 < target_sigaltstack_used.ss_size);
88}
89
90static inline int sas_ss_flags(unsigned long sp)
91{
92 return (target_sigaltstack_used.ss_size == 0 ? SS_DISABLE
93 : on_sig_stack(sp) ? SS_ONSTACK : 0);
94}
95
pbrook1d9d8b52009-04-16 15:17:02 +000096int host_to_target_signal(int sig)
bellard31e31b82003-02-18 22:55:36 +000097{
Andreas Schwab167c50d2013-07-02 14:04:12 +010098 if (sig < 0 || sig >= _NSIG)
pbrook4cb05962008-05-30 18:05:19 +000099 return sig;
bellard9e5f5282003-07-13 17:33:54 +0000100 return host_to_target_signal_table[sig];
bellard31e31b82003-02-18 22:55:36 +0000101}
102
pbrook4cb05962008-05-30 18:05:19 +0000103int target_to_host_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 target_to_host_signal_table[sig];
bellard31e31b82003-02-18 22:55:36 +0000108}
109
Anthony Liguoric227f092009-10-01 16:12:16 -0500110static inline void target_sigemptyset(target_sigset_t *set)
pbrookf5545b52008-05-30 22:37:07 +0000111{
112 memset(set, 0, sizeof(*set));
113}
114
Anthony Liguoric227f092009-10-01 16:12:16 -0500115static inline void target_sigaddset(target_sigset_t *set, int signum)
pbrookf5545b52008-05-30 22:37:07 +0000116{
117 signum--;
118 abi_ulong mask = (abi_ulong)1 << (signum % TARGET_NSIG_BPW);
119 set->sig[signum / TARGET_NSIG_BPW] |= mask;
120}
121
Anthony Liguoric227f092009-10-01 16:12:16 -0500122static inline int target_sigismember(const 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 return ((set->sig[signum / TARGET_NSIG_BPW] & mask) != 0);
127}
128
Anthony Liguoric227f092009-10-01 16:12:16 -0500129static void host_to_target_sigset_internal(target_sigset_t *d,
bellard92319442004-06-19 16:58:13 +0000130 const sigset_t *s)
bellard66fb9762003-03-23 01:06:05 +0000131{
132 int i;
pbrookf5545b52008-05-30 22:37:07 +0000133 target_sigemptyset(d);
134 for (i = 1; i <= TARGET_NSIG; i++) {
135 if (sigismember(s, i)) {
136 target_sigaddset(d, host_to_target_signal(i));
137 }
bellard9e5f5282003-07-13 17:33:54 +0000138 }
bellard66fb9762003-03-23 01:06:05 +0000139}
140
Anthony Liguoric227f092009-10-01 16:12:16 -0500141void host_to_target_sigset(target_sigset_t *d, const sigset_t *s)
bellard92319442004-06-19 16:58:13 +0000142{
Anthony Liguoric227f092009-10-01 16:12:16 -0500143 target_sigset_t d1;
bellard92319442004-06-19 16:58:13 +0000144 int i;
145
146 host_to_target_sigset_internal(&d1, s);
147 for(i = 0;i < TARGET_NSIG_WORDS; i++)
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200148 d->sig[i] = tswapal(d1.sig[i]);
bellard92319442004-06-19 16:58:13 +0000149}
150
blueswir18fcd3692008-08-17 20:26:25 +0000151static void target_to_host_sigset_internal(sigset_t *d,
Anthony Liguoric227f092009-10-01 16:12:16 -0500152 const target_sigset_t *s)
bellard66fb9762003-03-23 01:06:05 +0000153{
154 int i;
pbrookf5545b52008-05-30 22:37:07 +0000155 sigemptyset(d);
156 for (i = 1; i <= TARGET_NSIG; i++) {
157 if (target_sigismember(s, i)) {
158 sigaddset(d, target_to_host_signal(i));
159 }
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100160 }
bellard66fb9762003-03-23 01:06:05 +0000161}
162
Anthony Liguoric227f092009-10-01 16:12:16 -0500163void target_to_host_sigset(sigset_t *d, const target_sigset_t *s)
bellard92319442004-06-19 16:58:13 +0000164{
Anthony Liguoric227f092009-10-01 16:12:16 -0500165 target_sigset_t s1;
bellard92319442004-06-19 16:58:13 +0000166 int i;
167
168 for(i = 0;i < TARGET_NSIG_WORDS; i++)
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200169 s1.sig[i] = tswapal(s->sig[i]);
bellard92319442004-06-19 16:58:13 +0000170 target_to_host_sigset_internal(d, &s1);
171}
ths3b46e622007-09-17 08:09:54 +0000172
blueswir1992f48a2007-10-14 16:27:31 +0000173void host_to_target_old_sigset(abi_ulong *old_sigset,
bellard66fb9762003-03-23 01:06:05 +0000174 const sigset_t *sigset)
175{
Anthony Liguoric227f092009-10-01 16:12:16 -0500176 target_sigset_t d;
bellard9e5f5282003-07-13 17:33:54 +0000177 host_to_target_sigset(&d, sigset);
178 *old_sigset = d.sig[0];
bellard66fb9762003-03-23 01:06:05 +0000179}
180
ths5fafdf22007-09-16 21:08:06 +0000181void target_to_host_old_sigset(sigset_t *sigset,
blueswir1992f48a2007-10-14 16:27:31 +0000182 const abi_ulong *old_sigset)
bellard66fb9762003-03-23 01:06:05 +0000183{
Anthony Liguoric227f092009-10-01 16:12:16 -0500184 target_sigset_t d;
bellard9e5f5282003-07-13 17:33:54 +0000185 int i;
186
187 d.sig[0] = *old_sigset;
188 for(i = 1;i < TARGET_NSIG_WORDS; i++)
189 d.sig[i] = 0;
190 target_to_host_sigset(sigset, &d);
bellard66fb9762003-03-23 01:06:05 +0000191}
192
Peter Maydell3d3efba2016-05-27 15:51:49 +0100193int block_signals(void)
194{
195 TaskState *ts = (TaskState *)thread_cpu->opaque;
196 sigset_t set;
197 int pending;
198
199 /* It's OK to block everything including SIGSEGV, because we won't
200 * run any further guest code before unblocking signals in
201 * process_pending_signals().
202 */
203 sigfillset(&set);
204 sigprocmask(SIG_SETMASK, &set, 0);
205
206 pending = atomic_xchg(&ts->signal_pending, 1);
207
208 return pending;
209}
210
Alex Barcelo1c275922014-03-14 14:36:55 +0000211/* Wrapper for sigprocmask function
212 * Emulates a sigprocmask in a safe way for the guest. Note that set and oldset
Peter Maydell3d3efba2016-05-27 15:51:49 +0100213 * are host signal set, not guest ones. Returns -TARGET_ERESTARTSYS if
214 * a signal was already pending and the syscall must be restarted, or
215 * 0 on success.
216 * If set is NULL, this is guaranteed not to fail.
Alex Barcelo1c275922014-03-14 14:36:55 +0000217 */
218int do_sigprocmask(int how, const sigset_t *set, sigset_t *oldset)
219{
Peter Maydell3d3efba2016-05-27 15:51:49 +0100220 TaskState *ts = (TaskState *)thread_cpu->opaque;
221
222 if (oldset) {
223 *oldset = ts->signal_mask;
224 }
Peter Maydella7ec0f92014-03-14 14:36:56 +0000225
226 if (set) {
Peter Maydell3d3efba2016-05-27 15:51:49 +0100227 int i;
Peter Maydella7ec0f92014-03-14 14:36:56 +0000228
Peter Maydell3d3efba2016-05-27 15:51:49 +0100229 if (block_signals()) {
230 return -TARGET_ERESTARTSYS;
231 }
Peter Maydella7ec0f92014-03-14 14:36:56 +0000232
233 switch (how) {
234 case SIG_BLOCK:
Peter Maydell3d3efba2016-05-27 15:51:49 +0100235 sigorset(&ts->signal_mask, &ts->signal_mask, set);
Peter Maydella7ec0f92014-03-14 14:36:56 +0000236 break;
237 case SIG_UNBLOCK:
Peter Maydell3d3efba2016-05-27 15:51:49 +0100238 for (i = 1; i <= NSIG; ++i) {
239 if (sigismember(set, i)) {
240 sigdelset(&ts->signal_mask, i);
241 }
Peter Maydella7ec0f92014-03-14 14:36:56 +0000242 }
243 break;
244 case SIG_SETMASK:
Peter Maydell3d3efba2016-05-27 15:51:49 +0100245 ts->signal_mask = *set;
Peter Maydella7ec0f92014-03-14 14:36:56 +0000246 break;
247 default:
248 g_assert_not_reached();
249 }
Peter Maydell3d3efba2016-05-27 15:51:49 +0100250
251 /* Silently ignore attempts to change blocking status of KILL or STOP */
252 sigdelset(&ts->signal_mask, SIGKILL);
253 sigdelset(&ts->signal_mask, SIGSTOP);
Peter Maydella7ec0f92014-03-14 14:36:56 +0000254 }
Peter Maydell3d3efba2016-05-27 15:51:49 +0100255 return 0;
Alex Barcelo1c275922014-03-14 14:36:55 +0000256}
257
Peter Maydell9eede5b2016-05-27 15:51:46 +0100258#if !defined(TARGET_OPENRISC) && !defined(TARGET_UNICORE32) && \
259 !defined(TARGET_X86_64)
Peter Maydell3d3efba2016-05-27 15:51:49 +0100260/* Just set the guest's signal mask to the specified value; the
261 * caller is assumed to have called block_signals() already.
262 */
Peter Maydell9eede5b2016-05-27 15:51:46 +0100263static void set_sigmask(const sigset_t *set)
264{
Peter Maydell3d3efba2016-05-27 15:51:49 +0100265 TaskState *ts = (TaskState *)thread_cpu->opaque;
266
267 ts->signal_mask = *set;
Peter Maydell9eede5b2016-05-27 15:51:46 +0100268}
269#endif
270
bellard9de5e442003-03-23 16:49:39 +0000271/* siginfo conversion */
272
Anthony Liguoric227f092009-10-01 16:12:16 -0500273static inline void host_to_target_siginfo_noswap(target_siginfo_t *tinfo,
bellard9de5e442003-03-23 16:49:39 +0000274 const siginfo_t *info)
bellard66fb9762003-03-23 01:06:05 +0000275{
Richard Hendersona05c6402012-09-15 11:34:20 -0700276 int sig = host_to_target_signal(info->si_signo);
bellard9de5e442003-03-23 16:49:39 +0000277 tinfo->si_signo = sig;
278 tinfo->si_errno = 0;
pbrookafd7cd92008-05-31 12:14:21 +0000279 tinfo->si_code = info->si_code;
Richard Hendersona05c6402012-09-15 11:34:20 -0700280
281 if (sig == TARGET_SIGILL || sig == TARGET_SIGFPE || sig == TARGET_SIGSEGV
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100282 || sig == TARGET_SIGBUS || sig == TARGET_SIGTRAP) {
Richard Hendersona05c6402012-09-15 11:34:20 -0700283 /* Should never come here, but who knows. The information for
284 the target is irrelevant. */
bellard9de5e442003-03-23 16:49:39 +0000285 tinfo->_sifields._sigfault._addr = 0;
Richard Hendersona05c6402012-09-15 11:34:20 -0700286 } else if (sig == TARGET_SIGIO) {
287 tinfo->_sifields._sigpoll._band = info->si_band;
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100288 tinfo->_sifields._sigpoll._fd = info->si_fd;
Richard Hendersona05c6402012-09-15 11:34:20 -0700289 } else if (sig == TARGET_SIGCHLD) {
290 tinfo->_sifields._sigchld._pid = info->si_pid;
291 tinfo->_sifields._sigchld._uid = info->si_uid;
292 tinfo->_sifields._sigchld._status
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100293 = host_to_target_waitstatus(info->si_status);
Richard Hendersona05c6402012-09-15 11:34:20 -0700294 tinfo->_sifields._sigchld._utime = info->si_utime;
295 tinfo->_sifields._sigchld._stime = info->si_stime;
bellard9de5e442003-03-23 16:49:39 +0000296 } else if (sig >= TARGET_SIGRTMIN) {
297 tinfo->_sifields._rt._pid = info->si_pid;
298 tinfo->_sifields._rt._uid = info->si_uid;
299 /* XXX: potential problem if 64 bit */
Richard Hendersona05c6402012-09-15 11:34:20 -0700300 tinfo->_sifields._rt._sigval.sival_ptr
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100301 = (abi_ulong)(unsigned long)info->si_value.sival_ptr;
bellard9de5e442003-03-23 16:49:39 +0000302 }
bellard66fb9762003-03-23 01:06:05 +0000303}
304
Anthony Liguoric227f092009-10-01 16:12:16 -0500305static void tswap_siginfo(target_siginfo_t *tinfo,
306 const target_siginfo_t *info)
bellard9de5e442003-03-23 16:49:39 +0000307{
Richard Hendersona05c6402012-09-15 11:34:20 -0700308 int sig = info->si_signo;
bellard9de5e442003-03-23 16:49:39 +0000309 tinfo->si_signo = tswap32(sig);
310 tinfo->si_errno = tswap32(info->si_errno);
311 tinfo->si_code = tswap32(info->si_code);
Richard Hendersona05c6402012-09-15 11:34:20 -0700312
313 if (sig == TARGET_SIGILL || sig == TARGET_SIGFPE || sig == TARGET_SIGSEGV
314 || sig == TARGET_SIGBUS || sig == TARGET_SIGTRAP) {
315 tinfo->_sifields._sigfault._addr
316 = tswapal(info->_sifields._sigfault._addr);
317 } else if (sig == TARGET_SIGIO) {
318 tinfo->_sifields._sigpoll._band
319 = tswap32(info->_sifields._sigpoll._band);
320 tinfo->_sifields._sigpoll._fd = tswap32(info->_sifields._sigpoll._fd);
321 } else if (sig == TARGET_SIGCHLD) {
322 tinfo->_sifields._sigchld._pid
323 = tswap32(info->_sifields._sigchld._pid);
324 tinfo->_sifields._sigchld._uid
325 = tswap32(info->_sifields._sigchld._uid);
326 tinfo->_sifields._sigchld._status
327 = tswap32(info->_sifields._sigchld._status);
328 tinfo->_sifields._sigchld._utime
329 = tswapal(info->_sifields._sigchld._utime);
330 tinfo->_sifields._sigchld._stime
331 = tswapal(info->_sifields._sigchld._stime);
bellard9de5e442003-03-23 16:49:39 +0000332 } else if (sig >= TARGET_SIGRTMIN) {
333 tinfo->_sifields._rt._pid = tswap32(info->_sifields._rt._pid);
334 tinfo->_sifields._rt._uid = tswap32(info->_sifields._rt._uid);
Richard Hendersona05c6402012-09-15 11:34:20 -0700335 tinfo->_sifields._rt._sigval.sival_ptr
336 = tswapal(info->_sifields._rt._sigval.sival_ptr);
bellard9de5e442003-03-23 16:49:39 +0000337 }
338}
339
340
Anthony Liguoric227f092009-10-01 16:12:16 -0500341void host_to_target_siginfo(target_siginfo_t *tinfo, const siginfo_t *info)
bellard9de5e442003-03-23 16:49:39 +0000342{
343 host_to_target_siginfo_noswap(tinfo, info);
344 tswap_siginfo(tinfo, tinfo);
345}
346
347/* XXX: we support only POSIX RT signals are used. */
thsaa1f17c2007-07-11 22:48:58 +0000348/* XXX: find a solution for 64 bit (additional malloced data is needed) */
Anthony Liguoric227f092009-10-01 16:12:16 -0500349void target_to_host_siginfo(siginfo_t *info, const target_siginfo_t *tinfo)
bellard66fb9762003-03-23 01:06:05 +0000350{
351 info->si_signo = tswap32(tinfo->si_signo);
352 info->si_errno = tswap32(tinfo->si_errno);
353 info->si_code = tswap32(tinfo->si_code);
bellard9de5e442003-03-23 16:49:39 +0000354 info->si_pid = tswap32(tinfo->_sifields._rt._pid);
355 info->si_uid = tswap32(tinfo->_sifields._rt._uid);
ths5fafdf22007-09-16 21:08:06 +0000356 info->si_value.sival_ptr =
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200357 (void *)(long)tswapal(tinfo->_sifields._rt._sigval.sival_ptr);
bellard66fb9762003-03-23 01:06:05 +0000358}
359
aurel32ca587a82008-12-18 22:44:13 +0000360static int fatal_signal (int sig)
361{
362 switch (sig) {
363 case TARGET_SIGCHLD:
364 case TARGET_SIGURG:
365 case TARGET_SIGWINCH:
366 /* Ignored by default. */
367 return 0;
368 case TARGET_SIGCONT:
369 case TARGET_SIGSTOP:
370 case TARGET_SIGTSTP:
371 case TARGET_SIGTTIN:
372 case TARGET_SIGTTOU:
373 /* Job control signals. */
374 return 0;
375 default:
376 return 1;
377 }
378}
379
Mika Westerbergedf8e2a2009-04-07 09:57:11 +0300380/* returns 1 if given signal should dump core if not handled */
381static int core_dump_signal(int sig)
382{
383 switch (sig) {
384 case TARGET_SIGABRT:
385 case TARGET_SIGFPE:
386 case TARGET_SIGILL:
387 case TARGET_SIGQUIT:
388 case TARGET_SIGSEGV:
389 case TARGET_SIGTRAP:
390 case TARGET_SIGBUS:
391 return (1);
392 default:
393 return (0);
394 }
395}
396
bellard31e31b82003-02-18 22:55:36 +0000397void signal_init(void)
398{
Peter Maydell3d3efba2016-05-27 15:51:49 +0100399 TaskState *ts = (TaskState *)thread_cpu->opaque;
bellard31e31b82003-02-18 22:55:36 +0000400 struct sigaction act;
pbrook624f7972008-05-31 16:11:38 +0000401 struct sigaction oact;
bellard9e5f5282003-07-13 17:33:54 +0000402 int i, j;
pbrook624f7972008-05-31 16:11:38 +0000403 int host_sig;
bellard31e31b82003-02-18 22:55:36 +0000404
bellard9e5f5282003-07-13 17:33:54 +0000405 /* generate signal conversion tables */
Arnaud Patard3ca05582009-03-30 01:18:20 +0200406 for(i = 1; i < _NSIG; i++) {
bellard9e5f5282003-07-13 17:33:54 +0000407 if (host_to_target_signal_table[i] == 0)
408 host_to_target_signal_table[i] = i;
409 }
Arnaud Patard3ca05582009-03-30 01:18:20 +0200410 for(i = 1; i < _NSIG; i++) {
bellard9e5f5282003-07-13 17:33:54 +0000411 j = host_to_target_signal_table[i];
412 target_to_host_signal_table[j] = i;
413 }
ths3b46e622007-09-17 08:09:54 +0000414
Peter Maydell3d3efba2016-05-27 15:51:49 +0100415 /* Set the signal mask from the host mask. */
416 sigprocmask(0, 0, &ts->signal_mask);
417
bellard9de5e442003-03-23 16:49:39 +0000418 /* set all host signal handlers. ALL signals are blocked during
419 the handlers to serialize them. */
pbrook624f7972008-05-31 16:11:38 +0000420 memset(sigact_table, 0, sizeof(sigact_table));
421
bellard9de5e442003-03-23 16:49:39 +0000422 sigfillset(&act.sa_mask);
bellard31e31b82003-02-18 22:55:36 +0000423 act.sa_flags = SA_SIGINFO;
424 act.sa_sigaction = host_signal_handler;
pbrook624f7972008-05-31 16:11:38 +0000425 for(i = 1; i <= TARGET_NSIG; i++) {
426 host_sig = target_to_host_signal(i);
427 sigaction(host_sig, NULL, &oact);
428 if (oact.sa_sigaction == (void *)SIG_IGN) {
429 sigact_table[i - 1]._sa_handler = TARGET_SIG_IGN;
430 } else if (oact.sa_sigaction == (void *)SIG_DFL) {
431 sigact_table[i - 1]._sa_handler = TARGET_SIG_DFL;
432 }
433 /* If there's already a handler installed then something has
434 gone horribly wrong, so don't even try to handle that case. */
aurel32ca587a82008-12-18 22:44:13 +0000435 /* Install some handlers for our own use. We need at least
436 SIGSEGV and SIGBUS, to detect exceptions. We can not just
437 trap all signals because it affects syscall interrupt
438 behavior. But do trap all default-fatal signals. */
439 if (fatal_signal (i))
pbrook624f7972008-05-31 16:11:38 +0000440 sigaction(host_sig, &act, NULL);
bellard31e31b82003-02-18 22:55:36 +0000441 }
bellard31e31b82003-02-18 22:55:36 +0000442}
443
bellard66fb9762003-03-23 01:06:05 +0000444/* signal queue handling */
445
Andreas Färber9349b4f2012-03-14 01:38:32 +0100446static inline struct sigqueue *alloc_sigqueue(CPUArchState *env)
bellard66fb9762003-03-23 01:06:05 +0000447{
Andreas Färber0429a972013-08-26 18:14:44 +0200448 CPUState *cpu = ENV_GET_CPU(env);
449 TaskState *ts = cpu->opaque;
pbrook624f7972008-05-31 16:11:38 +0000450 struct sigqueue *q = ts->first_free;
bellard66fb9762003-03-23 01:06:05 +0000451 if (!q)
452 return NULL;
pbrook624f7972008-05-31 16:11:38 +0000453 ts->first_free = q->next;
bellard66fb9762003-03-23 01:06:05 +0000454 return q;
455}
456
Andreas Färber9349b4f2012-03-14 01:38:32 +0100457static inline void free_sigqueue(CPUArchState *env, struct sigqueue *q)
bellard66fb9762003-03-23 01:06:05 +0000458{
Andreas Färber0429a972013-08-26 18:14:44 +0200459 CPUState *cpu = ENV_GET_CPU(env);
460 TaskState *ts = cpu->opaque;
461
pbrook624f7972008-05-31 16:11:38 +0000462 q->next = ts->first_free;
463 ts->first_free = q;
bellard66fb9762003-03-23 01:06:05 +0000464}
465
bellard9de5e442003-03-23 16:49:39 +0000466/* abort execution with signal */
Riku Voipio66393fb2009-12-04 15:16:32 +0200467static void QEMU_NORETURN force_sig(int target_sig)
bellard66fb9762003-03-23 01:06:05 +0000468{
Andreas Färber0429a972013-08-26 18:14:44 +0200469 CPUState *cpu = thread_cpu;
470 CPUArchState *env = cpu->env_ptr;
471 TaskState *ts = (TaskState *)cpu->opaque;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +0300472 int host_sig, core_dumped = 0;
aurel32603e4fd2009-04-15 16:18:38 +0000473 struct sigaction act;
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +0100474
Riku Voipio66393fb2009-12-04 15:16:32 +0200475 host_sig = target_to_host_signal(target_sig);
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +0100476 trace_user_force_sig(env, target_sig, host_sig);
Andreas Färbera2247f82013-06-09 19:47:04 +0200477 gdb_signalled(env, target_sig);
aurel32603e4fd2009-04-15 16:18:38 +0000478
Mika Westerbergedf8e2a2009-04-07 09:57:11 +0300479 /* dump core if supported by target binary format */
Riku Voipio66393fb2009-12-04 15:16:32 +0200480 if (core_dump_signal(target_sig) && (ts->bprm->core_dump != NULL)) {
Mika Westerbergedf8e2a2009-04-07 09:57:11 +0300481 stop_all_tasks();
482 core_dumped =
Andreas Färbera2247f82013-06-09 19:47:04 +0200483 ((*ts->bprm->core_dump)(target_sig, env) == 0);
Mika Westerbergedf8e2a2009-04-07 09:57:11 +0300484 }
485 if (core_dumped) {
486 /* we already dumped the core of target process, we don't want
487 * a coredump of qemu itself */
488 struct rlimit nodump;
489 getrlimit(RLIMIT_CORE, &nodump);
490 nodump.rlim_cur=0;
491 setrlimit(RLIMIT_CORE, &nodump);
492 (void) fprintf(stderr, "qemu: uncaught target signal %d (%s) - %s\n",
Riku Voipio66393fb2009-12-04 15:16:32 +0200493 target_sig, strsignal(host_sig), "core dumped" );
Mika Westerbergedf8e2a2009-04-07 09:57:11 +0300494 }
495
Stefan Weil0c587512011-04-28 17:20:32 +0200496 /* The proper exit code for dying from an uncaught signal is
aurel32603e4fd2009-04-15 16:18:38 +0000497 * -<signal>. The kernel doesn't allow exit() or _exit() to pass
498 * a negative value. To get the proper exit code we need to
499 * actually die from an uncaught signal. Here the default signal
500 * handler is installed, we send ourself a signal and we wait for
501 * it to arrive. */
502 sigfillset(&act.sa_mask);
503 act.sa_handler = SIG_DFL;
Peter Maydell3a5d30b2014-02-17 18:55:32 +0000504 act.sa_flags = 0;
aurel32603e4fd2009-04-15 16:18:38 +0000505 sigaction(host_sig, &act, NULL);
506
507 /* For some reason raise(host_sig) doesn't send the signal when
508 * statically linked on x86-64. */
509 kill(getpid(), host_sig);
510
511 /* Make sure the signal isn't masked (just reuse the mask inside
512 of act) */
513 sigdelset(&act.sa_mask, host_sig);
514 sigsuspend(&act.sa_mask);
515
516 /* unreachable */
Blue Swirla6c6f762010-03-13 14:18:50 +0000517 abort();
bellard66fb9762003-03-23 01:06:05 +0000518}
519
bellard9de5e442003-03-23 16:49:39 +0000520/* queue a signal so that it will be send to the virtual CPU as soon
521 as possible */
Andreas Färber9349b4f2012-03-14 01:38:32 +0100522int queue_signal(CPUArchState *env, int sig, target_siginfo_t *info)
bellard31e31b82003-02-18 22:55:36 +0000523{
Andreas Färber0429a972013-08-26 18:14:44 +0200524 CPUState *cpu = ENV_GET_CPU(env);
525 TaskState *ts = cpu->opaque;
pbrook624f7972008-05-31 16:11:38 +0000526 struct emulated_sigtable *k;
bellard9de5e442003-03-23 16:49:39 +0000527 struct sigqueue *q, **pq;
blueswir1992f48a2007-10-14 16:27:31 +0000528 abi_ulong handler;
aurel32ca587a82008-12-18 22:44:13 +0000529 int queue;
bellard66fb9762003-03-23 01:06:05 +0000530
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +0100531 trace_user_queue_signal(env, sig);
pbrook624f7972008-05-31 16:11:38 +0000532 k = &ts->sigtab[sig - 1];
aurel32ca587a82008-12-18 22:44:13 +0000533 queue = gdb_queuesig ();
pbrook624f7972008-05-31 16:11:38 +0000534 handler = sigact_table[sig - 1]._sa_handler;
Peter Maydella7ec0f92014-03-14 14:36:56 +0000535
Peter Maydell3d3efba2016-05-27 15:51:49 +0100536 if (sig == TARGET_SIGSEGV && sigismember(&ts->signal_mask, SIGSEGV)) {
Peter Maydella7ec0f92014-03-14 14:36:56 +0000537 /* Guest has blocked SIGSEGV but we got one anyway. Assume this
538 * is a forced SIGSEGV (ie one the kernel handles via force_sig_info
539 * because it got a real MMU fault). A blocked SIGSEGV in that
540 * situation is treated as if using the default handler. This is
541 * not correct if some other process has randomly sent us a SIGSEGV
542 * via kill(), but that is not easy to distinguish at this point,
543 * so we assume it doesn't happen.
544 */
545 handler = TARGET_SIG_DFL;
546 }
547
aurel32ca587a82008-12-18 22:44:13 +0000548 if (!queue && handler == TARGET_SIG_DFL) {
ths60b19692008-11-27 15:47:15 +0000549 if (sig == TARGET_SIGTSTP || sig == TARGET_SIGTTIN || sig == TARGET_SIGTTOU) {
550 kill(getpid(),SIGSTOP);
551 return 0;
552 } else
bellard66fb9762003-03-23 01:06:05 +0000553 /* default handler : ignore some signal. The other are fatal */
ths5fafdf22007-09-16 21:08:06 +0000554 if (sig != TARGET_SIGCHLD &&
555 sig != TARGET_SIGURG &&
ths60b19692008-11-27 15:47:15 +0000556 sig != TARGET_SIGWINCH &&
557 sig != TARGET_SIGCONT) {
bellard66fb9762003-03-23 01:06:05 +0000558 force_sig(sig);
bellard9de5e442003-03-23 16:49:39 +0000559 } else {
560 return 0; /* indicate ignored */
bellard66fb9762003-03-23 01:06:05 +0000561 }
aurel32ca587a82008-12-18 22:44:13 +0000562 } else if (!queue && handler == TARGET_SIG_IGN) {
bellard66fb9762003-03-23 01:06:05 +0000563 /* ignore signal */
bellard9de5e442003-03-23 16:49:39 +0000564 return 0;
aurel32ca587a82008-12-18 22:44:13 +0000565 } else if (!queue && handler == TARGET_SIG_ERR) {
bellard66fb9762003-03-23 01:06:05 +0000566 force_sig(sig);
567 } else {
bellard9de5e442003-03-23 16:49:39 +0000568 pq = &k->first;
569 if (sig < TARGET_SIGRTMIN) {
570 /* if non real time signal, we queue exactly one signal */
571 if (!k->pending)
572 q = &k->info;
573 else
574 return 0;
575 } else {
576 if (!k->pending) {
577 /* first signal */
578 q = &k->info;
579 } else {
pbrook624f7972008-05-31 16:11:38 +0000580 q = alloc_sigqueue(env);
bellard9de5e442003-03-23 16:49:39 +0000581 if (!q)
582 return -EAGAIN;
583 while (*pq != NULL)
584 pq = &(*pq)->next;
585 }
586 }
587 *pq = q;
588 q->info = *info;
589 q->next = NULL;
590 k->pending = 1;
591 /* signal that a new signal is pending */
Peter Maydell3d3efba2016-05-27 15:51:49 +0100592 atomic_set(&ts->signal_pending, 1);
bellard9de5e442003-03-23 16:49:39 +0000593 return 1; /* indicates that the signal was queued */
594 }
595}
596
Timothy E Baldwin4d330ce2016-05-12 18:47:46 +0100597#ifndef HAVE_SAFE_SYSCALL
598static inline void rewind_if_in_safe_syscall(void *puc)
599{
600 /* Default version: never rewind */
601}
602#endif
603
ths5fafdf22007-09-16 21:08:06 +0000604static void host_signal_handler(int host_signum, siginfo_t *info,
bellard9de5e442003-03-23 16:49:39 +0000605 void *puc)
606{
Andreas Färbera2247f82013-06-09 19:47:04 +0200607 CPUArchState *env = thread_cpu->env_ptr;
bellard9de5e442003-03-23 16:49:39 +0000608 int sig;
Anthony Liguoric227f092009-10-01 16:12:16 -0500609 target_siginfo_t tinfo;
Peter Maydell3d3efba2016-05-27 15:51:49 +0100610 ucontext_t *uc = puc;
bellard9de5e442003-03-23 16:49:39 +0000611
612 /* the CPU emulator uses some host signals to detect exceptions,
aurel32eaa449b2009-01-03 13:14:52 +0000613 we forward to it some signals */
aurel32ca587a82008-12-18 22:44:13 +0000614 if ((host_signum == SIGSEGV || host_signum == SIGBUS)
aurel32eaa449b2009-01-03 13:14:52 +0000615 && info->si_code > 0) {
bellardb346ff42003-06-15 20:05:50 +0000616 if (cpu_signal_handler(host_signum, info, puc))
bellard9de5e442003-03-23 16:49:39 +0000617 return;
618 }
619
620 /* get target signal number */
621 sig = host_to_target_signal(host_signum);
622 if (sig < 1 || sig > TARGET_NSIG)
623 return;
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +0100624 trace_user_host_signal(env, host_signum, sig);
Timothy E Baldwin4d330ce2016-05-12 18:47:46 +0100625
626 rewind_if_in_safe_syscall(puc);
627
bellard9de5e442003-03-23 16:49:39 +0000628 host_to_target_siginfo_noswap(&tinfo, info);
Andreas Färbera2247f82013-06-09 19:47:04 +0200629 if (queue_signal(env, sig, &tinfo) == 1) {
Peter Maydell3d3efba2016-05-27 15:51:49 +0100630 /* Block host signals until target signal handler entered. We
631 * can't block SIGSEGV or SIGBUS while we're executing guest
632 * code in case the guest code provokes one in the window between
633 * now and it getting out to the main loop. Signals will be
634 * unblocked again in process_pending_signals().
635 */
636 sigfillset(&uc->uc_sigmask);
637 sigdelset(&uc->uc_sigmask, SIGSEGV);
638 sigdelset(&uc->uc_sigmask, SIGBUS);
639
bellard9de5e442003-03-23 16:49:39 +0000640 /* interrupt the virtual CPU as soon as possible */
Andreas Färbera2247f82013-06-09 19:47:04 +0200641 cpu_exit(thread_cpu);
bellard66fb9762003-03-23 01:06:05 +0000642 }
bellard31e31b82003-02-18 22:55:36 +0000643}
644
ths0da46a62007-10-20 20:23:07 +0000645/* do_sigaltstack() returns target values and errnos. */
bellard579a97f2007-11-11 14:26:47 +0000646/* compare linux/kernel/signal.c:do_sigaltstack() */
647abi_long do_sigaltstack(abi_ulong uss_addr, abi_ulong uoss_addr, abi_ulong sp)
thsa04e1342007-09-27 13:57:58 +0000648{
649 int ret;
650 struct target_sigaltstack oss;
651
652 /* XXX: test errors */
bellard579a97f2007-11-11 14:26:47 +0000653 if(uoss_addr)
thsa04e1342007-09-27 13:57:58 +0000654 {
655 __put_user(target_sigaltstack_used.ss_sp, &oss.ss_sp);
656 __put_user(target_sigaltstack_used.ss_size, &oss.ss_size);
657 __put_user(sas_ss_flags(sp), &oss.ss_flags);
658 }
659
bellard579a97f2007-11-11 14:26:47 +0000660 if(uss_addr)
thsa04e1342007-09-27 13:57:58 +0000661 {
bellard579a97f2007-11-11 14:26:47 +0000662 struct target_sigaltstack *uss;
663 struct target_sigaltstack ss;
Tom Musta0903c8b2014-08-12 13:53:40 -0500664 size_t minstacksize = TARGET_MINSIGSTKSZ;
665
666#if defined(TARGET_PPC64)
667 /* ELF V2 for PPC64 has a 4K minimum stack size for signal handlers */
668 struct image_info *image = ((TaskState *)thread_cpu->opaque)->info;
669 if (get_ppc64_abi(image) > 1) {
670 minstacksize = 4096;
671 }
672#endif
thsa04e1342007-09-27 13:57:58 +0000673
ths0da46a62007-10-20 20:23:07 +0000674 ret = -TARGET_EFAULT;
Riku Voipio9eeb8302014-04-23 11:26:34 +0300675 if (!lock_user_struct(VERIFY_READ, uss, uss_addr, 1)) {
thsa04e1342007-09-27 13:57:58 +0000676 goto out;
Riku Voipio9eeb8302014-04-23 11:26:34 +0300677 }
678 __get_user(ss.ss_sp, &uss->ss_sp);
679 __get_user(ss.ss_size, &uss->ss_size);
680 __get_user(ss.ss_flags, &uss->ss_flags);
bellard579a97f2007-11-11 14:26:47 +0000681 unlock_user_struct(uss, uss_addr, 0);
thsa04e1342007-09-27 13:57:58 +0000682
ths0da46a62007-10-20 20:23:07 +0000683 ret = -TARGET_EPERM;
thsa04e1342007-09-27 13:57:58 +0000684 if (on_sig_stack(sp))
685 goto out;
686
ths0da46a62007-10-20 20:23:07 +0000687 ret = -TARGET_EINVAL;
thsa04e1342007-09-27 13:57:58 +0000688 if (ss.ss_flags != TARGET_SS_DISABLE
689 && ss.ss_flags != TARGET_SS_ONSTACK
690 && ss.ss_flags != 0)
691 goto out;
692
693 if (ss.ss_flags == TARGET_SS_DISABLE) {
694 ss.ss_size = 0;
695 ss.ss_sp = 0;
696 } else {
ths0da46a62007-10-20 20:23:07 +0000697 ret = -TARGET_ENOMEM;
Tom Musta0903c8b2014-08-12 13:53:40 -0500698 if (ss.ss_size < minstacksize) {
thsa04e1342007-09-27 13:57:58 +0000699 goto out;
Tom Musta0903c8b2014-08-12 13:53:40 -0500700 }
thsa04e1342007-09-27 13:57:58 +0000701 }
702
703 target_sigaltstack_used.ss_sp = ss.ss_sp;
704 target_sigaltstack_used.ss_size = ss.ss_size;
705 }
706
bellard579a97f2007-11-11 14:26:47 +0000707 if (uoss_addr) {
ths0da46a62007-10-20 20:23:07 +0000708 ret = -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +0000709 if (copy_to_user(uoss_addr, &oss, sizeof(oss)))
thsa04e1342007-09-27 13:57:58 +0000710 goto out;
thsa04e1342007-09-27 13:57:58 +0000711 }
712
713 ret = 0;
714out:
715 return ret;
716}
717
ths0da46a62007-10-20 20:23:07 +0000718/* do_sigaction() return host values and errnos */
bellard66fb9762003-03-23 01:06:05 +0000719int do_sigaction(int sig, const struct target_sigaction *act,
720 struct target_sigaction *oact)
bellard31e31b82003-02-18 22:55:36 +0000721{
pbrook624f7972008-05-31 16:11:38 +0000722 struct target_sigaction *k;
bellard773b93e2004-01-04 17:15:59 +0000723 struct sigaction act1;
724 int host_sig;
ths0da46a62007-10-20 20:23:07 +0000725 int ret = 0;
bellard31e31b82003-02-18 22:55:36 +0000726
ths2a913eb2008-11-27 15:46:25 +0000727 if (sig < 1 || sig > TARGET_NSIG || sig == TARGET_SIGKILL || sig == TARGET_SIGSTOP)
bellard66fb9762003-03-23 01:06:05 +0000728 return -EINVAL;
729 k = &sigact_table[sig - 1];
bellard66fb9762003-03-23 01:06:05 +0000730 if (oact) {
Richard Hendersond2565872013-01-04 16:39:32 -0800731 __put_user(k->_sa_handler, &oact->_sa_handler);
732 __put_user(k->sa_flags, &oact->sa_flags);
ths388bb212007-05-13 13:58:00 +0000733#if !defined(TARGET_MIPS)
Richard Hendersond2565872013-01-04 16:39:32 -0800734 __put_user(k->sa_restorer, &oact->sa_restorer);
ths388bb212007-05-13 13:58:00 +0000735#endif
Richard Hendersond2565872013-01-04 16:39:32 -0800736 /* Not swapped. */
pbrook624f7972008-05-31 16:11:38 +0000737 oact->sa_mask = k->sa_mask;
bellard66fb9762003-03-23 01:06:05 +0000738 }
739 if (act) {
pbrook624f7972008-05-31 16:11:38 +0000740 /* FIXME: This is not threadsafe. */
Richard Hendersond2565872013-01-04 16:39:32 -0800741 __get_user(k->_sa_handler, &act->_sa_handler);
742 __get_user(k->sa_flags, &act->sa_flags);
ths388bb212007-05-13 13:58:00 +0000743#if !defined(TARGET_MIPS)
Richard Hendersond2565872013-01-04 16:39:32 -0800744 __get_user(k->sa_restorer, &act->sa_restorer);
ths388bb212007-05-13 13:58:00 +0000745#endif
Richard Hendersond2565872013-01-04 16:39:32 -0800746 /* To be swapped in target_to_host_sigset. */
pbrook624f7972008-05-31 16:11:38 +0000747 k->sa_mask = act->sa_mask;
bellard773b93e2004-01-04 17:15:59 +0000748
749 /* we update the host linux signal state */
750 host_sig = target_to_host_signal(sig);
751 if (host_sig != SIGSEGV && host_sig != SIGBUS) {
752 sigfillset(&act1.sa_mask);
753 act1.sa_flags = SA_SIGINFO;
pbrook624f7972008-05-31 16:11:38 +0000754 if (k->sa_flags & TARGET_SA_RESTART)
bellard773b93e2004-01-04 17:15:59 +0000755 act1.sa_flags |= SA_RESTART;
756 /* NOTE: it is important to update the host kernel signal
757 ignore state to avoid getting unexpected interrupted
758 syscalls */
pbrook624f7972008-05-31 16:11:38 +0000759 if (k->_sa_handler == TARGET_SIG_IGN) {
bellard773b93e2004-01-04 17:15:59 +0000760 act1.sa_sigaction = (void *)SIG_IGN;
pbrook624f7972008-05-31 16:11:38 +0000761 } else if (k->_sa_handler == TARGET_SIG_DFL) {
aurel32ca587a82008-12-18 22:44:13 +0000762 if (fatal_signal (sig))
763 act1.sa_sigaction = host_signal_handler;
764 else
765 act1.sa_sigaction = (void *)SIG_DFL;
bellard773b93e2004-01-04 17:15:59 +0000766 } else {
767 act1.sa_sigaction = host_signal_handler;
768 }
ths0da46a62007-10-20 20:23:07 +0000769 ret = sigaction(host_sig, &act1, NULL);
bellard773b93e2004-01-04 17:15:59 +0000770 }
bellard66fb9762003-03-23 01:06:05 +0000771 }
ths0da46a62007-10-20 20:23:07 +0000772 return ret;
bellard66fb9762003-03-23 01:06:05 +0000773}
bellard31e31b82003-02-18 22:55:36 +0000774
bellard459a4012007-11-11 19:45:10 +0000775#if defined(TARGET_I386) && TARGET_ABI_BITS == 32
bellard66fb9762003-03-23 01:06:05 +0000776
777/* from the Linux kernel */
778
779struct target_fpreg {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100780 uint16_t significand[4];
781 uint16_t exponent;
bellard66fb9762003-03-23 01:06:05 +0000782};
783
784struct target_fpxreg {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100785 uint16_t significand[4];
786 uint16_t exponent;
787 uint16_t padding[3];
bellard66fb9762003-03-23 01:06:05 +0000788};
789
790struct target_xmmreg {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100791 abi_ulong element[4];
bellard66fb9762003-03-23 01:06:05 +0000792};
793
794struct target_fpstate {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100795 /* Regular FPU environment */
796 abi_ulong cw;
797 abi_ulong sw;
798 abi_ulong tag;
799 abi_ulong ipoff;
800 abi_ulong cssel;
801 abi_ulong dataoff;
802 abi_ulong datasel;
803 struct target_fpreg _st[8];
804 uint16_t status;
805 uint16_t magic; /* 0xffff = regular FPU data only */
bellard66fb9762003-03-23 01:06:05 +0000806
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100807 /* FXSR FPU environment */
808 abi_ulong _fxsr_env[6]; /* FXSR FPU env is ignored */
809 abi_ulong mxcsr;
810 abi_ulong reserved;
811 struct target_fpxreg _fxsr_st[8]; /* FXSR FPU reg data is ignored */
812 struct target_xmmreg _xmm[8];
813 abi_ulong padding[56];
bellard66fb9762003-03-23 01:06:05 +0000814};
815
816#define X86_FXSR_MAGIC 0x0000
817
818struct target_sigcontext {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100819 uint16_t gs, __gsh;
820 uint16_t fs, __fsh;
821 uint16_t es, __esh;
822 uint16_t ds, __dsh;
823 abi_ulong edi;
824 abi_ulong esi;
825 abi_ulong ebp;
826 abi_ulong esp;
827 abi_ulong ebx;
828 abi_ulong edx;
829 abi_ulong ecx;
830 abi_ulong eax;
831 abi_ulong trapno;
832 abi_ulong err;
833 abi_ulong eip;
834 uint16_t cs, __csh;
835 abi_ulong eflags;
836 abi_ulong esp_at_signal;
837 uint16_t ss, __ssh;
838 abi_ulong fpstate; /* pointer */
839 abi_ulong oldmask;
840 abi_ulong cr2;
bellard66fb9762003-03-23 01:06:05 +0000841};
842
bellard66fb9762003-03-23 01:06:05 +0000843struct target_ucontext {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100844 abi_ulong tuc_flags;
845 abi_ulong tuc_link;
846 target_stack_t tuc_stack;
847 struct target_sigcontext tuc_mcontext;
848 target_sigset_t tuc_sigmask; /* mask last for extensibility */
bellard66fb9762003-03-23 01:06:05 +0000849};
850
851struct sigframe
852{
blueswir1992f48a2007-10-14 16:27:31 +0000853 abi_ulong pretcode;
bellard66fb9762003-03-23 01:06:05 +0000854 int sig;
855 struct target_sigcontext sc;
856 struct target_fpstate fpstate;
blueswir1992f48a2007-10-14 16:27:31 +0000857 abi_ulong extramask[TARGET_NSIG_WORDS-1];
bellard66fb9762003-03-23 01:06:05 +0000858 char retcode[8];
859};
860
861struct rt_sigframe
862{
blueswir1992f48a2007-10-14 16:27:31 +0000863 abi_ulong pretcode;
bellard66fb9762003-03-23 01:06:05 +0000864 int sig;
blueswir1992f48a2007-10-14 16:27:31 +0000865 abi_ulong pinfo;
866 abi_ulong puc;
bellard66fb9762003-03-23 01:06:05 +0000867 struct target_siginfo info;
868 struct target_ucontext uc;
869 struct target_fpstate fpstate;
870 char retcode[8];
871};
872
873/*
874 * Set up a signal frame.
875 */
876
bellard66fb9762003-03-23 01:06:05 +0000877/* XXX: save x87 state */
Riku Voipio41ecc722014-04-23 11:01:00 +0300878static void setup_sigcontext(struct target_sigcontext *sc,
879 struct target_fpstate *fpstate, CPUX86State *env, abi_ulong mask,
880 abi_ulong fpstate_addr)
bellard66fb9762003-03-23 01:06:05 +0000881{
Andreas Färber27103422013-08-26 08:31:06 +0200882 CPUState *cs = CPU(x86_env_get_cpu(env));
Andreas Färber27103422013-08-26 08:31:06 +0200883 uint16_t magic;
bellard66fb9762003-03-23 01:06:05 +0000884
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100885 /* already locked in setup_frame() */
Riku Voipio1d8b5122014-04-23 10:26:05 +0300886 __put_user(env->segs[R_GS].selector, (unsigned int *)&sc->gs);
887 __put_user(env->segs[R_FS].selector, (unsigned int *)&sc->fs);
888 __put_user(env->segs[R_ES].selector, (unsigned int *)&sc->es);
889 __put_user(env->segs[R_DS].selector, (unsigned int *)&sc->ds);
890 __put_user(env->regs[R_EDI], &sc->edi);
891 __put_user(env->regs[R_ESI], &sc->esi);
892 __put_user(env->regs[R_EBP], &sc->ebp);
893 __put_user(env->regs[R_ESP], &sc->esp);
894 __put_user(env->regs[R_EBX], &sc->ebx);
895 __put_user(env->regs[R_EDX], &sc->edx);
896 __put_user(env->regs[R_ECX], &sc->ecx);
897 __put_user(env->regs[R_EAX], &sc->eax);
898 __put_user(cs->exception_index, &sc->trapno);
899 __put_user(env->error_code, &sc->err);
900 __put_user(env->eip, &sc->eip);
901 __put_user(env->segs[R_CS].selector, (unsigned int *)&sc->cs);
902 __put_user(env->eflags, &sc->eflags);
903 __put_user(env->regs[R_ESP], &sc->esp_at_signal);
904 __put_user(env->segs[R_SS].selector, (unsigned int *)&sc->ss);
bellarded2dcdf2003-05-29 20:06:27 +0000905
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100906 cpu_x86_fsave(env, fpstate_addr, 1);
907 fpstate->status = fpstate->sw;
908 magic = 0xffff;
Riku Voipio1d8b5122014-04-23 10:26:05 +0300909 __put_user(magic, &fpstate->magic);
910 __put_user(fpstate_addr, &sc->fpstate);
bellarded2dcdf2003-05-29 20:06:27 +0000911
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100912 /* non-iBCS2 extensions.. */
Riku Voipio1d8b5122014-04-23 10:26:05 +0300913 __put_user(mask, &sc->oldmask);
914 __put_user(env->cr[2], &sc->cr2);
bellard66fb9762003-03-23 01:06:05 +0000915}
916
917/*
918 * Determine which stack to use..
919 */
920
bellard579a97f2007-11-11 14:26:47 +0000921static inline abi_ulong
pbrook624f7972008-05-31 16:11:38 +0000922get_sigframe(struct target_sigaction *ka, CPUX86State *env, size_t frame_size)
bellard66fb9762003-03-23 01:06:05 +0000923{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100924 unsigned long esp;
bellard66fb9762003-03-23 01:06:05 +0000925
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100926 /* Default to using normal stack */
927 esp = env->regs[R_ESP];
928 /* This is the X/Open sanctioned signal stack switching. */
929 if (ka->sa_flags & TARGET_SA_ONSTACK) {
930 if (sas_ss_flags(esp) == 0) {
931 esp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
thsa04e1342007-09-27 13:57:58 +0000932 }
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100933 } else {
bellard66fb9762003-03-23 01:06:05 +0000934
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100935 /* This is the legacy signal stack switching. */
bellarda52c7572003-06-21 13:14:12 +0000936 if ((env->segs[R_SS].selector & 0xffff) != __USER_DS &&
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100937 !(ka->sa_flags & TARGET_SA_RESTORER) &&
938 ka->sa_restorer) {
pbrook624f7972008-05-31 16:11:38 +0000939 esp = (unsigned long) ka->sa_restorer;
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100940 }
941 }
942 return (esp - frame_size) & -8ul;
bellard66fb9762003-03-23 01:06:05 +0000943}
944
bellard579a97f2007-11-11 14:26:47 +0000945/* compare linux/arch/i386/kernel/signal.c:setup_frame() */
pbrook624f7972008-05-31 16:11:38 +0000946static void setup_frame(int sig, struct target_sigaction *ka,
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100947 target_sigset_t *set, CPUX86State *env)
bellard66fb9762003-03-23 01:06:05 +0000948{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100949 abi_ulong frame_addr;
950 struct sigframe *frame;
951 int i;
bellard66fb9762003-03-23 01:06:05 +0000952
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100953 frame_addr = get_sigframe(ka, env, sizeof(*frame));
954 trace_user_setup_frame(env, frame_addr);
bellard66fb9762003-03-23 01:06:05 +0000955
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100956 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
957 goto give_sigsegv;
bellard579a97f2007-11-11 14:26:47 +0000958
Peter Maydellb6e2c932015-01-08 12:19:43 +0000959 __put_user(sig, &frame->sig);
bellard66fb9762003-03-23 01:06:05 +0000960
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100961 setup_sigcontext(&frame->sc, &frame->fpstate, env, set->sig[0],
962 frame_addr + offsetof(struct sigframe, fpstate));
bellard66fb9762003-03-23 01:06:05 +0000963
Riku Voipio7df2fa32014-04-23 10:34:53 +0300964 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
965 __put_user(set->sig[i], &frame->extramask[i - 1]);
966 }
bellard66fb9762003-03-23 01:06:05 +0000967
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100968 /* Set up to return from userspace. If provided, use a stub
969 already in userspace. */
970 if (ka->sa_flags & TARGET_SA_RESTORER) {
Riku Voipio1d8b5122014-04-23 10:26:05 +0300971 __put_user(ka->sa_restorer, &frame->pretcode);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100972 } else {
973 uint16_t val16;
974 abi_ulong retcode_addr;
975 retcode_addr = frame_addr + offsetof(struct sigframe, retcode);
Riku Voipio1d8b5122014-04-23 10:26:05 +0300976 __put_user(retcode_addr, &frame->pretcode);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100977 /* This is popl %eax ; movl $,%eax ; int $0x80 */
978 val16 = 0xb858;
Riku Voipio1d8b5122014-04-23 10:26:05 +0300979 __put_user(val16, (uint16_t *)(frame->retcode+0));
980 __put_user(TARGET_NR_sigreturn, (int *)(frame->retcode+2));
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100981 val16 = 0x80cd;
Riku Voipio1d8b5122014-04-23 10:26:05 +0300982 __put_user(val16, (uint16_t *)(frame->retcode+6));
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100983 }
bellard66fb9762003-03-23 01:06:05 +0000984
bellard66fb9762003-03-23 01:06:05 +0000985
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100986 /* Set up registers for signal handler */
987 env->regs[R_ESP] = frame_addr;
988 env->eip = ka->_sa_handler;
bellard66fb9762003-03-23 01:06:05 +0000989
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100990 cpu_x86_load_seg(env, R_DS, __USER_DS);
991 cpu_x86_load_seg(env, R_ES, __USER_DS);
992 cpu_x86_load_seg(env, R_SS, __USER_DS);
993 cpu_x86_load_seg(env, R_CS, __USER_CS);
994 env->eflags &= ~TF_MASK;
bellard66fb9762003-03-23 01:06:05 +0000995
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100996 unlock_user_struct(frame, frame_addr, 1);
bellard579a97f2007-11-11 14:26:47 +0000997
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100998 return;
bellard66fb9762003-03-23 01:06:05 +0000999
1000give_sigsegv:
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001001 if (sig == TARGET_SIGSEGV) {
1002 ka->_sa_handler = TARGET_SIG_DFL;
1003 }
1004 force_sig(TARGET_SIGSEGV /* , current */);
bellard66fb9762003-03-23 01:06:05 +00001005}
1006
bellard579a97f2007-11-11 14:26:47 +00001007/* compare linux/arch/i386/kernel/signal.c:setup_rt_frame() */
pbrook624f7972008-05-31 16:11:38 +00001008static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05001009 target_siginfo_t *info,
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001010 target_sigset_t *set, CPUX86State *env)
bellard66fb9762003-03-23 01:06:05 +00001011{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001012 abi_ulong frame_addr, addr;
1013 struct rt_sigframe *frame;
1014 int i;
bellard66fb9762003-03-23 01:06:05 +00001015
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001016 frame_addr = get_sigframe(ka, env, sizeof(*frame));
1017 trace_user_setup_rt_frame(env, frame_addr);
bellard66fb9762003-03-23 01:06:05 +00001018
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001019 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
1020 goto give_sigsegv;
bellard66fb9762003-03-23 01:06:05 +00001021
Peter Maydellb6e2c932015-01-08 12:19:43 +00001022 __put_user(sig, &frame->sig);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001023 addr = frame_addr + offsetof(struct rt_sigframe, info);
Riku Voipio1d8b5122014-04-23 10:26:05 +03001024 __put_user(addr, &frame->pinfo);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001025 addr = frame_addr + offsetof(struct rt_sigframe, uc);
Riku Voipio1d8b5122014-04-23 10:26:05 +03001026 __put_user(addr, &frame->puc);
Peter Maydellf6c7a052015-01-08 12:19:48 +00001027 tswap_siginfo(&frame->info, info);
bellard66fb9762003-03-23 01:06:05 +00001028
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001029 /* Create the ucontext. */
Riku Voipio1d8b5122014-04-23 10:26:05 +03001030 __put_user(0, &frame->uc.tuc_flags);
1031 __put_user(0, &frame->uc.tuc_link);
1032 __put_user(target_sigaltstack_used.ss_sp, &frame->uc.tuc_stack.ss_sp);
1033 __put_user(sas_ss_flags(get_sp_from_cpustate(env)),
1034 &frame->uc.tuc_stack.ss_flags);
1035 __put_user(target_sigaltstack_used.ss_size,
1036 &frame->uc.tuc_stack.ss_size);
Riku Voipio41ecc722014-04-23 11:01:00 +03001037 setup_sigcontext(&frame->uc.tuc_mcontext, &frame->fpstate, env,
1038 set->sig[0], frame_addr + offsetof(struct rt_sigframe, fpstate));
1039
Riku Voipio0188fad2014-04-23 13:34:15 +03001040 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
1041 __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
1042 }
bellard66fb9762003-03-23 01:06:05 +00001043
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001044 /* Set up to return from userspace. If provided, use a stub
1045 already in userspace. */
1046 if (ka->sa_flags & TARGET_SA_RESTORER) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03001047 __put_user(ka->sa_restorer, &frame->pretcode);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001048 } else {
1049 uint16_t val16;
1050 addr = frame_addr + offsetof(struct rt_sigframe, retcode);
Riku Voipio1d8b5122014-04-23 10:26:05 +03001051 __put_user(addr, &frame->pretcode);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001052 /* This is movl $,%eax ; int $0x80 */
Riku Voipio1d8b5122014-04-23 10:26:05 +03001053 __put_user(0xb8, (char *)(frame->retcode+0));
1054 __put_user(TARGET_NR_rt_sigreturn, (int *)(frame->retcode+1));
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001055 val16 = 0x80cd;
Riku Voipio1d8b5122014-04-23 10:26:05 +03001056 __put_user(val16, (uint16_t *)(frame->retcode+5));
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001057 }
bellard66fb9762003-03-23 01:06:05 +00001058
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001059 /* Set up registers for signal handler */
1060 env->regs[R_ESP] = frame_addr;
1061 env->eip = ka->_sa_handler;
bellard66fb9762003-03-23 01:06:05 +00001062
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001063 cpu_x86_load_seg(env, R_DS, __USER_DS);
1064 cpu_x86_load_seg(env, R_ES, __USER_DS);
1065 cpu_x86_load_seg(env, R_SS, __USER_DS);
1066 cpu_x86_load_seg(env, R_CS, __USER_CS);
1067 env->eflags &= ~TF_MASK;
bellard66fb9762003-03-23 01:06:05 +00001068
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001069 unlock_user_struct(frame, frame_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00001070
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001071 return;
bellard66fb9762003-03-23 01:06:05 +00001072
1073give_sigsegv:
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001074 if (sig == TARGET_SIGSEGV) {
1075 ka->_sa_handler = TARGET_SIG_DFL;
1076 }
1077 force_sig(TARGET_SIGSEGV /* , current */);
bellard66fb9762003-03-23 01:06:05 +00001078}
1079
1080static int
Timothy E Baldwin0284b032016-05-12 18:47:30 +01001081restore_sigcontext(CPUX86State *env, struct target_sigcontext *sc)
bellard66fb9762003-03-23 01:06:05 +00001082{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001083 unsigned int err = 0;
1084 abi_ulong fpstate_addr;
1085 unsigned int tmpflags;
bellard66fb9762003-03-23 01:06:05 +00001086
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001087 cpu_x86_load_seg(env, R_GS, tswap16(sc->gs));
1088 cpu_x86_load_seg(env, R_FS, tswap16(sc->fs));
1089 cpu_x86_load_seg(env, R_ES, tswap16(sc->es));
1090 cpu_x86_load_seg(env, R_DS, tswap16(sc->ds));
bellard66fb9762003-03-23 01:06:05 +00001091
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001092 env->regs[R_EDI] = tswapl(sc->edi);
1093 env->regs[R_ESI] = tswapl(sc->esi);
1094 env->regs[R_EBP] = tswapl(sc->ebp);
1095 env->regs[R_ESP] = tswapl(sc->esp);
1096 env->regs[R_EBX] = tswapl(sc->ebx);
1097 env->regs[R_EDX] = tswapl(sc->edx);
1098 env->regs[R_ECX] = tswapl(sc->ecx);
Timothy E Baldwin0284b032016-05-12 18:47:30 +01001099 env->regs[R_EAX] = tswapl(sc->eax);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001100 env->eip = tswapl(sc->eip);
bellard66fb9762003-03-23 01:06:05 +00001101
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001102 cpu_x86_load_seg(env, R_CS, lduw_p(&sc->cs) | 3);
1103 cpu_x86_load_seg(env, R_SS, lduw_p(&sc->ss) | 3);
ths5fafdf22007-09-16 21:08:06 +00001104
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001105 tmpflags = tswapl(sc->eflags);
1106 env->eflags = (env->eflags & ~0x40DD5) | (tmpflags & 0x40DD5);
1107 // regs->orig_eax = -1; /* disable syscall checks */
bellard28be6232007-11-11 22:23:38 +00001108
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001109 fpstate_addr = tswapl(sc->fpstate);
1110 if (fpstate_addr != 0) {
1111 if (!access_ok(VERIFY_READ, fpstate_addr,
1112 sizeof(struct target_fpstate)))
1113 goto badframe;
1114 cpu_x86_frstor(env, fpstate_addr, 1);
1115 }
bellard66fb9762003-03-23 01:06:05 +00001116
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001117 return err;
bellard66fb9762003-03-23 01:06:05 +00001118badframe:
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001119 return 1;
bellard66fb9762003-03-23 01:06:05 +00001120}
1121
1122long do_sigreturn(CPUX86State *env)
1123{
bellard579a97f2007-11-11 14:26:47 +00001124 struct sigframe *frame;
1125 abi_ulong frame_addr = env->regs[R_ESP] - 8;
Anthony Liguoric227f092009-10-01 16:12:16 -05001126 target_sigset_t target_set;
bellard66fb9762003-03-23 01:06:05 +00001127 sigset_t set;
Timothy E Baldwin0284b032016-05-12 18:47:30 +01001128 int i;
bellard66fb9762003-03-23 01:06:05 +00001129
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01001130 trace_user_do_sigreturn(env, frame_addr);
bellard579a97f2007-11-11 14:26:47 +00001131 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
1132 goto badframe;
bellard66fb9762003-03-23 01:06:05 +00001133 /* set blocked signals */
Riku Voipiof5f601a2014-04-23 13:00:17 +03001134 __get_user(target_set.sig[0], &frame->sc.oldmask);
bellard92319442004-06-19 16:58:13 +00001135 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
Riku Voipiof5f601a2014-04-23 13:00:17 +03001136 __get_user(target_set.sig[i], &frame->extramask[i - 1]);
bellard92319442004-06-19 16:58:13 +00001137 }
bellard66fb9762003-03-23 01:06:05 +00001138
bellard92319442004-06-19 16:58:13 +00001139 target_to_host_sigset_internal(&set, &target_set);
Peter Maydell9eede5b2016-05-27 15:51:46 +01001140 set_sigmask(&set);
ths3b46e622007-09-17 08:09:54 +00001141
bellard66fb9762003-03-23 01:06:05 +00001142 /* restore registers */
Timothy E Baldwin0284b032016-05-12 18:47:30 +01001143 if (restore_sigcontext(env, &frame->sc))
bellard66fb9762003-03-23 01:06:05 +00001144 goto badframe;
bellard579a97f2007-11-11 14:26:47 +00001145 unlock_user_struct(frame, frame_addr, 0);
Timothy E Baldwin0284b032016-05-12 18:47:30 +01001146 return -TARGET_QEMU_ESIGRETURN;
bellard66fb9762003-03-23 01:06:05 +00001147
1148badframe:
bellard579a97f2007-11-11 14:26:47 +00001149 unlock_user_struct(frame, frame_addr, 0);
bellard66fb9762003-03-23 01:06:05 +00001150 force_sig(TARGET_SIGSEGV);
1151 return 0;
1152}
1153
1154long do_rt_sigreturn(CPUX86State *env)
1155{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001156 abi_ulong frame_addr;
1157 struct rt_sigframe *frame;
1158 sigset_t set;
bellard66fb9762003-03-23 01:06:05 +00001159
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001160 frame_addr = env->regs[R_ESP] - 4;
1161 trace_user_do_rt_sigreturn(env, frame_addr);
1162 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
1163 goto badframe;
1164 target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
Peter Maydell9eede5b2016-05-27 15:51:46 +01001165 set_sigmask(&set);
ths5fafdf22007-09-16 21:08:06 +00001166
Timothy E Baldwin0284b032016-05-12 18:47:30 +01001167 if (restore_sigcontext(env, &frame->uc.tuc_mcontext)) {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001168 goto badframe;
1169 }
bellard66fb9762003-03-23 01:06:05 +00001170
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001171 if (do_sigaltstack(frame_addr + offsetof(struct rt_sigframe, uc.tuc_stack), 0,
1172 get_sp_from_cpustate(env)) == -EFAULT) {
1173 goto badframe;
1174 }
thsa04e1342007-09-27 13:57:58 +00001175
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001176 unlock_user_struct(frame, frame_addr, 0);
Timothy E Baldwin0284b032016-05-12 18:47:30 +01001177 return -TARGET_QEMU_ESIGRETURN;
bellard66fb9762003-03-23 01:06:05 +00001178
1179badframe:
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001180 unlock_user_struct(frame, frame_addr, 0);
1181 force_sig(TARGET_SIGSEGV);
1182 return 0;
bellard66fb9762003-03-23 01:06:05 +00001183}
1184
Andreas Schwab1744aea2013-09-03 20:12:16 +01001185#elif defined(TARGET_AARCH64)
1186
1187struct target_sigcontext {
1188 uint64_t fault_address;
1189 /* AArch64 registers */
1190 uint64_t regs[31];
1191 uint64_t sp;
1192 uint64_t pc;
1193 uint64_t pstate;
1194 /* 4K reserved for FP/SIMD state and future expansion */
1195 char __reserved[4096] __attribute__((__aligned__(16)));
1196};
1197
1198struct target_ucontext {
1199 abi_ulong tuc_flags;
1200 abi_ulong tuc_link;
1201 target_stack_t tuc_stack;
1202 target_sigset_t tuc_sigmask;
1203 /* glibc uses a 1024-bit sigset_t */
1204 char __unused[1024 / 8 - sizeof(target_sigset_t)];
1205 /* last for future expansion */
1206 struct target_sigcontext tuc_mcontext;
1207};
1208
1209/*
1210 * Header to be used at the beginning of structures extending the user
1211 * context. Such structures must be placed after the rt_sigframe on the stack
1212 * and be 16-byte aligned. The last structure must be a dummy one with the
1213 * magic and size set to 0.
1214 */
1215struct target_aarch64_ctx {
1216 uint32_t magic;
1217 uint32_t size;
1218};
1219
1220#define TARGET_FPSIMD_MAGIC 0x46508001
1221
1222struct target_fpsimd_context {
1223 struct target_aarch64_ctx head;
1224 uint32_t fpsr;
1225 uint32_t fpcr;
1226 uint64_t vregs[32 * 2]; /* really uint128_t vregs[32] */
1227};
1228
1229/*
1230 * Auxiliary context saved in the sigcontext.__reserved array. Not exported to
1231 * user space as it will change with the addition of new context. User space
1232 * should check the magic/size information.
1233 */
1234struct target_aux_context {
1235 struct target_fpsimd_context fpsimd;
1236 /* additional context to be added before "end" */
1237 struct target_aarch64_ctx end;
1238};
1239
1240struct target_rt_sigframe {
1241 struct target_siginfo info;
1242 struct target_ucontext uc;
1243 uint64_t fp;
1244 uint64_t lr;
1245 uint32_t tramp[2];
1246};
1247
1248static int target_setup_sigframe(struct target_rt_sigframe *sf,
1249 CPUARMState *env, target_sigset_t *set)
1250{
1251 int i;
1252 struct target_aux_context *aux =
1253 (struct target_aux_context *)sf->uc.tuc_mcontext.__reserved;
1254
1255 /* set up the stack frame for unwinding */
1256 __put_user(env->xregs[29], &sf->fp);
1257 __put_user(env->xregs[30], &sf->lr);
1258
1259 for (i = 0; i < 31; i++) {
1260 __put_user(env->xregs[i], &sf->uc.tuc_mcontext.regs[i]);
1261 }
1262 __put_user(env->xregs[31], &sf->uc.tuc_mcontext.sp);
1263 __put_user(env->pc, &sf->uc.tuc_mcontext.pc);
Peter Maydelld3563122013-12-17 19:42:30 +00001264 __put_user(pstate_read(env), &sf->uc.tuc_mcontext.pstate);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001265
Peter Maydell7af03922014-05-01 18:36:17 +01001266 __put_user(env->exception.vaddress, &sf->uc.tuc_mcontext.fault_address);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001267
1268 for (i = 0; i < TARGET_NSIG_WORDS; i++) {
1269 __put_user(set->sig[i], &sf->uc.tuc_sigmask.sig[i]);
1270 }
1271
1272 for (i = 0; i < 32; i++) {
1273#ifdef TARGET_WORDS_BIGENDIAN
1274 __put_user(env->vfp.regs[i * 2], &aux->fpsimd.vregs[i * 2 + 1]);
1275 __put_user(env->vfp.regs[i * 2 + 1], &aux->fpsimd.vregs[i * 2]);
1276#else
1277 __put_user(env->vfp.regs[i * 2], &aux->fpsimd.vregs[i * 2]);
1278 __put_user(env->vfp.regs[i * 2 + 1], &aux->fpsimd.vregs[i * 2 + 1]);
1279#endif
1280 }
Will Newtone0ee1382014-01-04 22:15:48 +00001281 __put_user(vfp_get_fpsr(env), &aux->fpsimd.fpsr);
1282 __put_user(vfp_get_fpcr(env), &aux->fpsimd.fpcr);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001283 __put_user(TARGET_FPSIMD_MAGIC, &aux->fpsimd.head.magic);
1284 __put_user(sizeof(struct target_fpsimd_context),
1285 &aux->fpsimd.head.size);
1286
1287 /* set the "end" magic */
1288 __put_user(0, &aux->end.magic);
1289 __put_user(0, &aux->end.size);
1290
1291 return 0;
1292}
1293
1294static int target_restore_sigframe(CPUARMState *env,
1295 struct target_rt_sigframe *sf)
1296{
1297 sigset_t set;
1298 int i;
1299 struct target_aux_context *aux =
1300 (struct target_aux_context *)sf->uc.tuc_mcontext.__reserved;
Will Newtone0ee1382014-01-04 22:15:48 +00001301 uint32_t magic, size, fpsr, fpcr;
Peter Maydelld3563122013-12-17 19:42:30 +00001302 uint64_t pstate;
Andreas Schwab1744aea2013-09-03 20:12:16 +01001303
1304 target_to_host_sigset(&set, &sf->uc.tuc_sigmask);
Peter Maydell9eede5b2016-05-27 15:51:46 +01001305 set_sigmask(&set);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001306
1307 for (i = 0; i < 31; i++) {
1308 __get_user(env->xregs[i], &sf->uc.tuc_mcontext.regs[i]);
1309 }
1310
1311 __get_user(env->xregs[31], &sf->uc.tuc_mcontext.sp);
1312 __get_user(env->pc, &sf->uc.tuc_mcontext.pc);
Peter Maydelld3563122013-12-17 19:42:30 +00001313 __get_user(pstate, &sf->uc.tuc_mcontext.pstate);
1314 pstate_write(env, pstate);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001315
1316 __get_user(magic, &aux->fpsimd.head.magic);
1317 __get_user(size, &aux->fpsimd.head.size);
1318
1319 if (magic != TARGET_FPSIMD_MAGIC
1320 || size != sizeof(struct target_fpsimd_context)) {
1321 return 1;
1322 }
1323
Peter Maydell4cf23482014-03-02 19:36:38 +00001324 for (i = 0; i < 32; i++) {
1325#ifdef TARGET_WORDS_BIGENDIAN
1326 __get_user(env->vfp.regs[i * 2], &aux->fpsimd.vregs[i * 2 + 1]);
1327 __get_user(env->vfp.regs[i * 2 + 1], &aux->fpsimd.vregs[i * 2]);
1328#else
1329 __get_user(env->vfp.regs[i * 2], &aux->fpsimd.vregs[i * 2]);
1330 __get_user(env->vfp.regs[i * 2 + 1], &aux->fpsimd.vregs[i * 2 + 1]);
1331#endif
Andreas Schwab1744aea2013-09-03 20:12:16 +01001332 }
Will Newtone0ee1382014-01-04 22:15:48 +00001333 __get_user(fpsr, &aux->fpsimd.fpsr);
1334 vfp_set_fpsr(env, fpsr);
1335 __get_user(fpcr, &aux->fpsimd.fpcr);
1336 vfp_set_fpcr(env, fpcr);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001337
1338 return 0;
1339}
1340
1341static abi_ulong get_sigframe(struct target_sigaction *ka, CPUARMState *env)
1342{
1343 abi_ulong sp;
1344
1345 sp = env->xregs[31];
1346
1347 /*
1348 * This is the X/Open sanctioned signal stack switching.
1349 */
Riku Voipiob545f632014-07-15 17:01:55 +03001350 if ((ka->sa_flags & TARGET_SA_ONSTACK) && !sas_ss_flags(sp)) {
Andreas Schwab1744aea2013-09-03 20:12:16 +01001351 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
1352 }
1353
1354 sp = (sp - sizeof(struct target_rt_sigframe)) & ~15;
1355
1356 return sp;
1357}
1358
1359static void target_setup_frame(int usig, struct target_sigaction *ka,
1360 target_siginfo_t *info, target_sigset_t *set,
1361 CPUARMState *env)
1362{
1363 struct target_rt_sigframe *frame;
Michael Matz8a3ae912014-03-02 19:36:39 +00001364 abi_ulong frame_addr, return_addr;
Andreas Schwab1744aea2013-09-03 20:12:16 +01001365
1366 frame_addr = get_sigframe(ka, env);
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01001367 trace_user_setup_frame(env, frame_addr);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001368 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
1369 goto give_sigsegv;
1370 }
1371
1372 __put_user(0, &frame->uc.tuc_flags);
1373 __put_user(0, &frame->uc.tuc_link);
1374
1375 __put_user(target_sigaltstack_used.ss_sp,
1376 &frame->uc.tuc_stack.ss_sp);
1377 __put_user(sas_ss_flags(env->xregs[31]),
1378 &frame->uc.tuc_stack.ss_flags);
1379 __put_user(target_sigaltstack_used.ss_size,
1380 &frame->uc.tuc_stack.ss_size);
1381 target_setup_sigframe(frame, env, set);
Michael Matz8a3ae912014-03-02 19:36:39 +00001382 if (ka->sa_flags & TARGET_SA_RESTORER) {
1383 return_addr = ka->sa_restorer;
1384 } else {
1385 /* mov x8,#__NR_rt_sigreturn; svc #0 */
1386 __put_user(0xd2801168, &frame->tramp[0]);
1387 __put_user(0xd4000001, &frame->tramp[1]);
1388 return_addr = frame_addr + offsetof(struct target_rt_sigframe, tramp);
1389 }
Andreas Schwab1744aea2013-09-03 20:12:16 +01001390 env->xregs[0] = usig;
1391 env->xregs[31] = frame_addr;
1392 env->xregs[29] = env->xregs[31] + offsetof(struct target_rt_sigframe, fp);
1393 env->pc = ka->_sa_handler;
Michael Matz8a3ae912014-03-02 19:36:39 +00001394 env->xregs[30] = return_addr;
Andreas Schwab1744aea2013-09-03 20:12:16 +01001395 if (info) {
Peter Maydellf6c7a052015-01-08 12:19:48 +00001396 tswap_siginfo(&frame->info, info);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001397 env->xregs[1] = frame_addr + offsetof(struct target_rt_sigframe, info);
1398 env->xregs[2] = frame_addr + offsetof(struct target_rt_sigframe, uc);
1399 }
1400
1401 unlock_user_struct(frame, frame_addr, 1);
1402 return;
1403
1404 give_sigsegv:
1405 unlock_user_struct(frame, frame_addr, 1);
1406 force_sig(TARGET_SIGSEGV);
1407}
1408
1409static void setup_rt_frame(int sig, struct target_sigaction *ka,
1410 target_siginfo_t *info, target_sigset_t *set,
1411 CPUARMState *env)
1412{
1413 target_setup_frame(sig, ka, info, set, env);
1414}
1415
1416static void setup_frame(int sig, struct target_sigaction *ka,
1417 target_sigset_t *set, CPUARMState *env)
1418{
1419 target_setup_frame(sig, ka, 0, set, env);
1420}
1421
1422long do_rt_sigreturn(CPUARMState *env)
1423{
Peter Maydell7f72cd22014-03-12 13:06:00 +00001424 struct target_rt_sigframe *frame = NULL;
Andreas Schwab1744aea2013-09-03 20:12:16 +01001425 abi_ulong frame_addr = env->xregs[31];
1426
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01001427 trace_user_do_rt_sigreturn(env, frame_addr);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001428 if (frame_addr & 15) {
1429 goto badframe;
1430 }
1431
1432 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
1433 goto badframe;
1434 }
1435
1436 if (target_restore_sigframe(env, frame)) {
1437 goto badframe;
1438 }
1439
1440 if (do_sigaltstack(frame_addr +
1441 offsetof(struct target_rt_sigframe, uc.tuc_stack),
1442 0, get_sp_from_cpustate(env)) == -EFAULT) {
1443 goto badframe;
1444 }
1445
1446 unlock_user_struct(frame, frame_addr, 0);
Timothy E Baldwinf0267ef2016-05-12 18:47:31 +01001447 return -TARGET_QEMU_ESIGRETURN;
Andreas Schwab1744aea2013-09-03 20:12:16 +01001448
1449 badframe:
1450 unlock_user_struct(frame, frame_addr, 0);
1451 force_sig(TARGET_SIGSEGV);
1452 return 0;
1453}
1454
1455long do_sigreturn(CPUARMState *env)
1456{
1457 return do_rt_sigreturn(env);
1458}
1459
bellard43fff232003-07-09 19:31:39 +00001460#elif defined(TARGET_ARM)
1461
1462struct target_sigcontext {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001463 abi_ulong trap_no;
1464 abi_ulong error_code;
1465 abi_ulong oldmask;
1466 abi_ulong arm_r0;
1467 abi_ulong arm_r1;
1468 abi_ulong arm_r2;
1469 abi_ulong arm_r3;
1470 abi_ulong arm_r4;
1471 abi_ulong arm_r5;
1472 abi_ulong arm_r6;
1473 abi_ulong arm_r7;
1474 abi_ulong arm_r8;
1475 abi_ulong arm_r9;
1476 abi_ulong arm_r10;
1477 abi_ulong arm_fp;
1478 abi_ulong arm_ip;
1479 abi_ulong arm_sp;
1480 abi_ulong arm_lr;
1481 abi_ulong arm_pc;
1482 abi_ulong arm_cpsr;
1483 abi_ulong fault_address;
bellard43fff232003-07-09 19:31:39 +00001484};
1485
pbrooka745ec62008-05-06 15:36:17 +00001486struct target_ucontext_v1 {
blueswir1992f48a2007-10-14 16:27:31 +00001487 abi_ulong tuc_flags;
1488 abi_ulong tuc_link;
Anthony Liguoric227f092009-10-01 16:12:16 -05001489 target_stack_t tuc_stack;
bellardb8076a72005-04-07 22:20:31 +00001490 struct target_sigcontext tuc_mcontext;
Anthony Liguoric227f092009-10-01 16:12:16 -05001491 target_sigset_t tuc_sigmask; /* mask last for extensibility */
bellard43fff232003-07-09 19:31:39 +00001492};
1493
pbrooka745ec62008-05-06 15:36:17 +00001494struct target_ucontext_v2 {
1495 abi_ulong tuc_flags;
1496 abi_ulong tuc_link;
Anthony Liguoric227f092009-10-01 16:12:16 -05001497 target_stack_t tuc_stack;
pbrooka745ec62008-05-06 15:36:17 +00001498 struct target_sigcontext tuc_mcontext;
Anthony Liguoric227f092009-10-01 16:12:16 -05001499 target_sigset_t tuc_sigmask; /* mask last for extensibility */
Peter Maydell5f0b7c82010-11-24 15:20:03 +00001500 char __unused[128 - sizeof(target_sigset_t)];
pbrooka745ec62008-05-06 15:36:17 +00001501 abi_ulong tuc_regspace[128] __attribute__((__aligned__(8)));
1502};
1503
Peter Maydell0d871bd2010-11-24 15:20:05 +00001504struct target_user_vfp {
1505 uint64_t fpregs[32];
1506 abi_ulong fpscr;
1507};
1508
1509struct target_user_vfp_exc {
1510 abi_ulong fpexc;
1511 abi_ulong fpinst;
1512 abi_ulong fpinst2;
1513};
1514
1515struct target_vfp_sigframe {
1516 abi_ulong magic;
1517 abi_ulong size;
1518 struct target_user_vfp ufp;
1519 struct target_user_vfp_exc ufp_exc;
1520} __attribute__((__aligned__(8)));
1521
Peter Maydell08e11252010-11-24 15:20:07 +00001522struct target_iwmmxt_sigframe {
1523 abi_ulong magic;
1524 abi_ulong size;
1525 uint64_t regs[16];
1526 /* Note that not all the coprocessor control registers are stored here */
1527 uint32_t wcssf;
1528 uint32_t wcasf;
1529 uint32_t wcgr0;
1530 uint32_t wcgr1;
1531 uint32_t wcgr2;
1532 uint32_t wcgr3;
1533} __attribute__((__aligned__(8)));
1534
Peter Maydell0d871bd2010-11-24 15:20:05 +00001535#define TARGET_VFP_MAGIC 0x56465001
Peter Maydell08e11252010-11-24 15:20:07 +00001536#define TARGET_IWMMXT_MAGIC 0x12ef842a
Peter Maydell0d871bd2010-11-24 15:20:05 +00001537
pbrooka8c33202008-05-07 23:22:46 +00001538struct sigframe_v1
bellard43fff232003-07-09 19:31:39 +00001539{
1540 struct target_sigcontext sc;
blueswir1992f48a2007-10-14 16:27:31 +00001541 abi_ulong extramask[TARGET_NSIG_WORDS-1];
1542 abi_ulong retcode;
bellard43fff232003-07-09 19:31:39 +00001543};
1544
pbrooka8c33202008-05-07 23:22:46 +00001545struct sigframe_v2
1546{
1547 struct target_ucontext_v2 uc;
1548 abi_ulong retcode;
1549};
1550
pbrooka745ec62008-05-06 15:36:17 +00001551struct rt_sigframe_v1
bellard43fff232003-07-09 19:31:39 +00001552{
bellardf8b0aa22007-11-11 23:03:42 +00001553 abi_ulong pinfo;
1554 abi_ulong puc;
bellard43fff232003-07-09 19:31:39 +00001555 struct target_siginfo info;
pbrooka745ec62008-05-06 15:36:17 +00001556 struct target_ucontext_v1 uc;
1557 abi_ulong retcode;
1558};
1559
1560struct rt_sigframe_v2
1561{
1562 struct target_siginfo info;
1563 struct target_ucontext_v2 uc;
blueswir1992f48a2007-10-14 16:27:31 +00001564 abi_ulong retcode;
bellard43fff232003-07-09 19:31:39 +00001565};
1566
1567#define TARGET_CONFIG_CPU_32 1
1568
1569/*
1570 * For ARM syscalls, we encode the syscall number into the instruction.
1571 */
1572#define SWI_SYS_SIGRETURN (0xef000000|(TARGET_NR_sigreturn + ARM_SYSCALL_BASE))
1573#define SWI_SYS_RT_SIGRETURN (0xef000000|(TARGET_NR_rt_sigreturn + ARM_SYSCALL_BASE))
1574
1575/*
1576 * For Thumb syscalls, we pass the syscall number via r7. We therefore
1577 * need two 16-bit instructions.
1578 */
1579#define SWI_THUMB_SIGRETURN (0xdf00 << 16 | 0x2700 | (TARGET_NR_sigreturn))
1580#define SWI_THUMB_RT_SIGRETURN (0xdf00 << 16 | 0x2700 | (TARGET_NR_rt_sigreturn))
1581
blueswir1992f48a2007-10-14 16:27:31 +00001582static const abi_ulong retcodes[4] = {
bellard43fff232003-07-09 19:31:39 +00001583 SWI_SYS_SIGRETURN, SWI_THUMB_SIGRETURN,
1584 SWI_SYS_RT_SIGRETURN, SWI_THUMB_RT_SIGRETURN
1585};
1586
1587
Andreas Färber05390242012-02-25 03:37:53 +01001588static inline int valid_user_regs(CPUARMState *regs)
bellard43fff232003-07-09 19:31:39 +00001589{
1590 return 1;
1591}
1592
pbrooka8c33202008-05-07 23:22:46 +00001593static void
bellard43fff232003-07-09 19:31:39 +00001594setup_sigcontext(struct target_sigcontext *sc, /*struct _fpstate *fpstate,*/
Andreas Färber05390242012-02-25 03:37:53 +01001595 CPUARMState *env, abi_ulong mask)
bellard43fff232003-07-09 19:31:39 +00001596{
Paolo Bonzinia0e1e6d2016-03-04 11:30:18 +00001597 __put_user(env->regs[0], &sc->arm_r0);
1598 __put_user(env->regs[1], &sc->arm_r1);
1599 __put_user(env->regs[2], &sc->arm_r2);
1600 __put_user(env->regs[3], &sc->arm_r3);
1601 __put_user(env->regs[4], &sc->arm_r4);
1602 __put_user(env->regs[5], &sc->arm_r5);
1603 __put_user(env->regs[6], &sc->arm_r6);
1604 __put_user(env->regs[7], &sc->arm_r7);
1605 __put_user(env->regs[8], &sc->arm_r8);
1606 __put_user(env->regs[9], &sc->arm_r9);
1607 __put_user(env->regs[10], &sc->arm_r10);
1608 __put_user(env->regs[11], &sc->arm_fp);
1609 __put_user(env->regs[12], &sc->arm_ip);
1610 __put_user(env->regs[13], &sc->arm_sp);
1611 __put_user(env->regs[14], &sc->arm_lr);
1612 __put_user(env->regs[15], &sc->arm_pc);
bellard43fff232003-07-09 19:31:39 +00001613#ifdef TARGET_CONFIG_CPU_32
Paolo Bonzinia0e1e6d2016-03-04 11:30:18 +00001614 __put_user(cpsr_read(env), &sc->arm_cpsr);
bellard43fff232003-07-09 19:31:39 +00001615#endif
1616
Paolo Bonzinia0e1e6d2016-03-04 11:30:18 +00001617 __put_user(/* current->thread.trap_no */ 0, &sc->trap_no);
1618 __put_user(/* current->thread.error_code */ 0, &sc->error_code);
1619 __put_user(/* current->thread.address */ 0, &sc->fault_address);
1620 __put_user(mask, &sc->oldmask);
bellard43fff232003-07-09 19:31:39 +00001621}
1622
bellard579a97f2007-11-11 14:26:47 +00001623static inline abi_ulong
Andreas Färber05390242012-02-25 03:37:53 +01001624get_sigframe(struct target_sigaction *ka, CPUARMState *regs, int framesize)
bellard43fff232003-07-09 19:31:39 +00001625{
Paolo Bonzinia0e1e6d2016-03-04 11:30:18 +00001626 unsigned long sp = regs->regs[13];
bellard43fff232003-07-09 19:31:39 +00001627
Paolo Bonzinia0e1e6d2016-03-04 11:30:18 +00001628 /*
1629 * This is the X/Open sanctioned signal stack switching.
1630 */
1631 if ((ka->sa_flags & TARGET_SA_ONSTACK) && !sas_ss_flags(sp)) {
1632 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
1633 }
1634 /*
1635 * ATPCS B01 mandates 8-byte alignment
1636 */
1637 return (sp - framesize) & ~7;
bellard43fff232003-07-09 19:31:39 +00001638}
1639
Riku Voipio0188fad2014-04-23 13:34:15 +03001640static void
Andreas Färber05390242012-02-25 03:37:53 +01001641setup_return(CPUARMState *env, struct target_sigaction *ka,
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001642 abi_ulong *rc, abi_ulong frame_addr, int usig, abi_ulong rc_addr)
bellard43fff232003-07-09 19:31:39 +00001643{
Paolo Bonzinia0e1e6d2016-03-04 11:30:18 +00001644 abi_ulong handler = ka->_sa_handler;
1645 abi_ulong retcode;
1646 int thumb = handler & 1;
1647 uint32_t cpsr = cpsr_read(env);
Peter Maydell964413d2011-01-14 20:39:19 +01001648
Paolo Bonzinia0e1e6d2016-03-04 11:30:18 +00001649 cpsr &= ~CPSR_IT;
1650 if (thumb) {
1651 cpsr |= CPSR_T;
1652 } else {
1653 cpsr &= ~CPSR_T;
1654 }
bellard43fff232003-07-09 19:31:39 +00001655
Paolo Bonzinia0e1e6d2016-03-04 11:30:18 +00001656 if (ka->sa_flags & TARGET_SA_RESTORER) {
1657 retcode = ka->sa_restorer;
1658 } else {
1659 unsigned int idx = thumb;
bellard43fff232003-07-09 19:31:39 +00001660
Paolo Bonzinia0e1e6d2016-03-04 11:30:18 +00001661 if (ka->sa_flags & TARGET_SA_SIGINFO) {
1662 idx += 2;
1663 }
bellard43fff232003-07-09 19:31:39 +00001664
Riku Voipio0188fad2014-04-23 13:34:15 +03001665 __put_user(retcodes[idx], rc);
Stefan Weilca8a2772011-10-03 22:43:19 +02001666
Paolo Bonzinia0e1e6d2016-03-04 11:30:18 +00001667 retcode = rc_addr + thumb;
1668 }
bellard43fff232003-07-09 19:31:39 +00001669
Paolo Bonzinia0e1e6d2016-03-04 11:30:18 +00001670 env->regs[0] = usig;
1671 env->regs[13] = frame_addr;
1672 env->regs[14] = retcode;
1673 env->regs[15] = handler & (thumb ? ~1 : ~3);
1674 cpsr_write(env, cpsr, CPSR_IT | CPSR_T, CPSRWriteByInstr);
bellard43fff232003-07-09 19:31:39 +00001675}
1676
Andreas Färber05390242012-02-25 03:37:53 +01001677static abi_ulong *setup_sigframe_v2_vfp(abi_ulong *regspace, CPUARMState *env)
Peter Maydell0d871bd2010-11-24 15:20:05 +00001678{
1679 int i;
1680 struct target_vfp_sigframe *vfpframe;
1681 vfpframe = (struct target_vfp_sigframe *)regspace;
1682 __put_user(TARGET_VFP_MAGIC, &vfpframe->magic);
1683 __put_user(sizeof(*vfpframe), &vfpframe->size);
1684 for (i = 0; i < 32; i++) {
Peter Maydell005e1a02011-02-10 13:59:35 +00001685 __put_user(float64_val(env->vfp.regs[i]), &vfpframe->ufp.fpregs[i]);
Peter Maydell0d871bd2010-11-24 15:20:05 +00001686 }
1687 __put_user(vfp_get_fpscr(env), &vfpframe->ufp.fpscr);
1688 __put_user(env->vfp.xregs[ARM_VFP_FPEXC], &vfpframe->ufp_exc.fpexc);
1689 __put_user(env->vfp.xregs[ARM_VFP_FPINST], &vfpframe->ufp_exc.fpinst);
1690 __put_user(env->vfp.xregs[ARM_VFP_FPINST2], &vfpframe->ufp_exc.fpinst2);
1691 return (abi_ulong*)(vfpframe+1);
1692}
1693
Andreas Färber05390242012-02-25 03:37:53 +01001694static abi_ulong *setup_sigframe_v2_iwmmxt(abi_ulong *regspace,
1695 CPUARMState *env)
Peter Maydell08e11252010-11-24 15:20:07 +00001696{
1697 int i;
1698 struct target_iwmmxt_sigframe *iwmmxtframe;
1699 iwmmxtframe = (struct target_iwmmxt_sigframe *)regspace;
1700 __put_user(TARGET_IWMMXT_MAGIC, &iwmmxtframe->magic);
1701 __put_user(sizeof(*iwmmxtframe), &iwmmxtframe->size);
1702 for (i = 0; i < 16; i++) {
1703 __put_user(env->iwmmxt.regs[i], &iwmmxtframe->regs[i]);
1704 }
1705 __put_user(env->vfp.xregs[ARM_IWMMXT_wCSSF], &iwmmxtframe->wcssf);
1706 __put_user(env->vfp.xregs[ARM_IWMMXT_wCASF], &iwmmxtframe->wcssf);
1707 __put_user(env->vfp.xregs[ARM_IWMMXT_wCGR0], &iwmmxtframe->wcgr0);
1708 __put_user(env->vfp.xregs[ARM_IWMMXT_wCGR1], &iwmmxtframe->wcgr1);
1709 __put_user(env->vfp.xregs[ARM_IWMMXT_wCGR2], &iwmmxtframe->wcgr2);
1710 __put_user(env->vfp.xregs[ARM_IWMMXT_wCGR3], &iwmmxtframe->wcgr3);
1711 return (abi_ulong*)(iwmmxtframe+1);
1712}
1713
pbrooka8c33202008-05-07 23:22:46 +00001714static void setup_sigframe_v2(struct target_ucontext_v2 *uc,
Andreas Färber05390242012-02-25 03:37:53 +01001715 target_sigset_t *set, CPUARMState *env)
bellard43fff232003-07-09 19:31:39 +00001716{
pbrooka8c33202008-05-07 23:22:46 +00001717 struct target_sigaltstack stack;
1718 int i;
Peter Maydell0d871bd2010-11-24 15:20:05 +00001719 abi_ulong *regspace;
pbrooka8c33202008-05-07 23:22:46 +00001720
1721 /* Clear all the bits of the ucontext we don't use. */
1722 memset(uc, 0, offsetof(struct target_ucontext_v2, tuc_mcontext));
1723
1724 memset(&stack, 0, sizeof(stack));
1725 __put_user(target_sigaltstack_used.ss_sp, &stack.ss_sp);
1726 __put_user(target_sigaltstack_used.ss_size, &stack.ss_size);
1727 __put_user(sas_ss_flags(get_sp_from_cpustate(env)), &stack.ss_flags);
1728 memcpy(&uc->tuc_stack, &stack, sizeof(stack));
1729
1730 setup_sigcontext(&uc->tuc_mcontext, env, set->sig[0]);
Peter Maydell0d871bd2010-11-24 15:20:05 +00001731 /* Save coprocessor signal frame. */
1732 regspace = uc->tuc_regspace;
1733 if (arm_feature(env, ARM_FEATURE_VFP)) {
1734 regspace = setup_sigframe_v2_vfp(regspace, env);
1735 }
Peter Maydell08e11252010-11-24 15:20:07 +00001736 if (arm_feature(env, ARM_FEATURE_IWMMXT)) {
1737 regspace = setup_sigframe_v2_iwmmxt(regspace, env);
1738 }
1739
Peter Maydell0d871bd2010-11-24 15:20:05 +00001740 /* Write terminating magic word */
1741 __put_user(0, regspace);
1742
pbrooka8c33202008-05-07 23:22:46 +00001743 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
1744 __put_user(set->sig[i], &uc->tuc_sigmask.sig[i]);
1745 }
1746}
1747
1748/* compare linux/arch/arm/kernel/signal.c:setup_frame() */
pbrook624f7972008-05-31 16:11:38 +00001749static void setup_frame_v1(int usig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01001750 target_sigset_t *set, CPUARMState *regs)
pbrooka8c33202008-05-07 23:22:46 +00001751{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001752 struct sigframe_v1 *frame;
1753 abi_ulong frame_addr = get_sigframe(ka, regs, sizeof(*frame));
1754 int i;
bellard43fff232003-07-09 19:31:39 +00001755
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001756 trace_user_setup_frame(regs, frame_addr);
1757 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
1758 return;
1759 }
bellard579a97f2007-11-11 14:26:47 +00001760
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001761 setup_sigcontext(&frame->sc, regs, set->sig[0]);
bellard43fff232003-07-09 19:31:39 +00001762
Riku Voipio0188fad2014-04-23 13:34:15 +03001763 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
1764 __put_user(set->sig[i], &frame->extramask[i - 1]);
1765 }
bellard43fff232003-07-09 19:31:39 +00001766
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001767 setup_return(regs, ka, &frame->retcode, frame_addr, usig,
1768 frame_addr + offsetof(struct sigframe_v1, retcode));
bellard579a97f2007-11-11 14:26:47 +00001769
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001770 unlock_user_struct(frame, frame_addr, 1);
pbrooka8c33202008-05-07 23:22:46 +00001771}
1772
pbrook624f7972008-05-31 16:11:38 +00001773static void setup_frame_v2(int usig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01001774 target_sigset_t *set, CPUARMState *regs)
pbrooka8c33202008-05-07 23:22:46 +00001775{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001776 struct sigframe_v2 *frame;
1777 abi_ulong frame_addr = get_sigframe(ka, regs, sizeof(*frame));
pbrooka8c33202008-05-07 23:22:46 +00001778
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001779 trace_user_setup_frame(regs, frame_addr);
1780 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
1781 return;
1782 }
pbrooka8c33202008-05-07 23:22:46 +00001783
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001784 setup_sigframe_v2(&frame->uc, set, regs);
pbrooka8c33202008-05-07 23:22:46 +00001785
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001786 setup_return(regs, ka, &frame->retcode, frame_addr, usig,
1787 frame_addr + offsetof(struct sigframe_v2, retcode));
pbrooka8c33202008-05-07 23:22:46 +00001788
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001789 unlock_user_struct(frame, frame_addr, 1);
pbrooka8c33202008-05-07 23:22:46 +00001790}
1791
pbrook624f7972008-05-31 16:11:38 +00001792static void setup_frame(int usig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01001793 target_sigset_t *set, CPUARMState *regs)
pbrooka8c33202008-05-07 23:22:46 +00001794{
1795 if (get_osversion() >= 0x020612) {
1796 setup_frame_v2(usig, ka, set, regs);
1797 } else {
1798 setup_frame_v1(usig, ka, set, regs);
1799 }
bellard43fff232003-07-09 19:31:39 +00001800}
1801
bellard579a97f2007-11-11 14:26:47 +00001802/* compare linux/arch/arm/kernel/signal.c:setup_rt_frame() */
pbrook624f7972008-05-31 16:11:38 +00001803static void setup_rt_frame_v1(int usig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05001804 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01001805 target_sigset_t *set, CPUARMState *env)
bellard43fff232003-07-09 19:31:39 +00001806{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001807 struct rt_sigframe_v1 *frame;
1808 abi_ulong frame_addr = get_sigframe(ka, env, sizeof(*frame));
1809 struct target_sigaltstack stack;
1810 int i;
1811 abi_ulong info_addr, uc_addr;
bellard43fff232003-07-09 19:31:39 +00001812
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001813 trace_user_setup_rt_frame(env, frame_addr);
1814 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
1815 return /* 1 */;
1816 }
bellardedf779f2004-02-22 13:40:13 +00001817
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001818 info_addr = frame_addr + offsetof(struct rt_sigframe_v1, info);
1819 __put_user(info_addr, &frame->pinfo);
1820 uc_addr = frame_addr + offsetof(struct rt_sigframe_v1, uc);
1821 __put_user(uc_addr, &frame->puc);
1822 tswap_siginfo(&frame->info, info);
bellard43fff232003-07-09 19:31:39 +00001823
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001824 /* Clear all the bits of the ucontext we don't use. */
1825 memset(&frame->uc, 0, offsetof(struct target_ucontext_v1, tuc_mcontext));
bellard43fff232003-07-09 19:31:39 +00001826
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001827 memset(&stack, 0, sizeof(stack));
1828 __put_user(target_sigaltstack_used.ss_sp, &stack.ss_sp);
1829 __put_user(target_sigaltstack_used.ss_size, &stack.ss_size);
1830 __put_user(sas_ss_flags(get_sp_from_cpustate(env)), &stack.ss_flags);
1831 memcpy(&frame->uc.tuc_stack, &stack, sizeof(stack));
thsa04e1342007-09-27 13:57:58 +00001832
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001833 setup_sigcontext(&frame->uc.tuc_mcontext, env, set->sig[0]);
1834 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
1835 __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
1836 }
bellard43fff232003-07-09 19:31:39 +00001837
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001838 setup_return(env, ka, &frame->retcode, frame_addr, usig,
1839 frame_addr + offsetof(struct rt_sigframe_v1, retcode));
pbrooka745ec62008-05-06 15:36:17 +00001840
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001841 env->regs[1] = info_addr;
1842 env->regs[2] = uc_addr;
pbrooka745ec62008-05-06 15:36:17 +00001843
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001844 unlock_user_struct(frame, frame_addr, 1);
pbrooka745ec62008-05-06 15:36:17 +00001845}
1846
pbrook624f7972008-05-31 16:11:38 +00001847static void setup_rt_frame_v2(int usig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05001848 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01001849 target_sigset_t *set, CPUARMState *env)
pbrooka745ec62008-05-06 15:36:17 +00001850{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001851 struct rt_sigframe_v2 *frame;
1852 abi_ulong frame_addr = get_sigframe(ka, env, sizeof(*frame));
1853 abi_ulong info_addr, uc_addr;
pbrooka745ec62008-05-06 15:36:17 +00001854
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001855 trace_user_setup_rt_frame(env, frame_addr);
1856 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
1857 return /* 1 */;
1858 }
pbrooka745ec62008-05-06 15:36:17 +00001859
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001860 info_addr = frame_addr + offsetof(struct rt_sigframe_v2, info);
1861 uc_addr = frame_addr + offsetof(struct rt_sigframe_v2, uc);
1862 tswap_siginfo(&frame->info, info);
pbrooka745ec62008-05-06 15:36:17 +00001863
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001864 setup_sigframe_v2(&frame->uc, set, env);
pbrooka745ec62008-05-06 15:36:17 +00001865
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001866 setup_return(env, ka, &frame->retcode, frame_addr, usig,
1867 frame_addr + offsetof(struct rt_sigframe_v2, retcode));
pbrooka745ec62008-05-06 15:36:17 +00001868
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001869 env->regs[1] = info_addr;
1870 env->regs[2] = uc_addr;
pbrooka745ec62008-05-06 15:36:17 +00001871
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001872 unlock_user_struct(frame, frame_addr, 1);
bellard43fff232003-07-09 19:31:39 +00001873}
1874
pbrook624f7972008-05-31 16:11:38 +00001875static void setup_rt_frame(int usig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05001876 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01001877 target_sigset_t *set, CPUARMState *env)
pbrooka745ec62008-05-06 15:36:17 +00001878{
1879 if (get_osversion() >= 0x020612) {
1880 setup_rt_frame_v2(usig, ka, info, set, env);
1881 } else {
1882 setup_rt_frame_v1(usig, ka, info, set, env);
1883 }
1884}
1885
bellard43fff232003-07-09 19:31:39 +00001886static int
Andreas Färber05390242012-02-25 03:37:53 +01001887restore_sigcontext(CPUARMState *env, struct target_sigcontext *sc)
bellard43fff232003-07-09 19:31:39 +00001888{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001889 int err = 0;
1890 uint32_t cpsr;
bellard43fff232003-07-09 19:31:39 +00001891
Riku Voipio1d8b5122014-04-23 10:26:05 +03001892 __get_user(env->regs[0], &sc->arm_r0);
1893 __get_user(env->regs[1], &sc->arm_r1);
1894 __get_user(env->regs[2], &sc->arm_r2);
1895 __get_user(env->regs[3], &sc->arm_r3);
1896 __get_user(env->regs[4], &sc->arm_r4);
1897 __get_user(env->regs[5], &sc->arm_r5);
1898 __get_user(env->regs[6], &sc->arm_r6);
1899 __get_user(env->regs[7], &sc->arm_r7);
1900 __get_user(env->regs[8], &sc->arm_r8);
1901 __get_user(env->regs[9], &sc->arm_r9);
1902 __get_user(env->regs[10], &sc->arm_r10);
1903 __get_user(env->regs[11], &sc->arm_fp);
1904 __get_user(env->regs[12], &sc->arm_ip);
1905 __get_user(env->regs[13], &sc->arm_sp);
1906 __get_user(env->regs[14], &sc->arm_lr);
1907 __get_user(env->regs[15], &sc->arm_pc);
bellard43fff232003-07-09 19:31:39 +00001908#ifdef TARGET_CONFIG_CPU_32
Riku Voipio1d8b5122014-04-23 10:26:05 +03001909 __get_user(cpsr, &sc->arm_cpsr);
Peter Maydell50866ba2016-02-23 15:36:43 +00001910 cpsr_write(env, cpsr, CPSR_USER | CPSR_EXEC, CPSRWriteByInstr);
bellard43fff232003-07-09 19:31:39 +00001911#endif
1912
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001913 err |= !valid_user_regs(env);
bellard43fff232003-07-09 19:31:39 +00001914
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001915 return err;
bellard43fff232003-07-09 19:31:39 +00001916}
1917
Andreas Färber05390242012-02-25 03:37:53 +01001918static long do_sigreturn_v1(CPUARMState *env)
bellard43fff232003-07-09 19:31:39 +00001919{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001920 abi_ulong frame_addr;
1921 struct sigframe_v1 *frame = NULL;
1922 target_sigset_t set;
1923 sigset_t host_set;
1924 int i;
bellard43fff232003-07-09 19:31:39 +00001925
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001926 /*
1927 * Since we stacked the signal on a 64-bit boundary,
1928 * then 'sp' should be word aligned here. If it's
1929 * not, then the user is trying to mess with us.
1930 */
1931 frame_addr = env->regs[13];
1932 trace_user_do_sigreturn(env, frame_addr);
1933 if (frame_addr & 7) {
1934 goto badframe;
1935 }
Peter Maydell978fae92013-07-29 12:00:32 +01001936
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001937 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
1938 goto badframe;
1939 }
bellard43fff232003-07-09 19:31:39 +00001940
Riku Voipiof5f601a2014-04-23 13:00:17 +03001941 __get_user(set.sig[0], &frame->sc.oldmask);
1942 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
1943 __get_user(set.sig[i], &frame->extramask[i - 1]);
1944 }
bellard43fff232003-07-09 19:31:39 +00001945
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001946 target_to_host_sigset_internal(&host_set, &set);
Peter Maydell9eede5b2016-05-27 15:51:46 +01001947 set_sigmask(&host_set);
bellard43fff232003-07-09 19:31:39 +00001948
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001949 if (restore_sigcontext(env, &frame->sc)) {
1950 goto badframe;
1951 }
bellard43fff232003-07-09 19:31:39 +00001952
1953#if 0
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001954 /* Send SIGTRAP if we're single-stepping */
1955 if (ptrace_cancel_bpt(current))
1956 send_sig(SIGTRAP, current, 1);
bellard43fff232003-07-09 19:31:39 +00001957#endif
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001958 unlock_user_struct(frame, frame_addr, 0);
Timothy E Baldwinf0267ef2016-05-12 18:47:31 +01001959 return -TARGET_QEMU_ESIGRETURN;
bellard43fff232003-07-09 19:31:39 +00001960
1961badframe:
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001962 force_sig(TARGET_SIGSEGV /* , current */);
1963 return 0;
bellard43fff232003-07-09 19:31:39 +00001964}
1965
Andreas Färber05390242012-02-25 03:37:53 +01001966static abi_ulong *restore_sigframe_v2_vfp(CPUARMState *env, abi_ulong *regspace)
Peter Maydell5f9099d2010-11-24 15:20:06 +00001967{
1968 int i;
1969 abi_ulong magic, sz;
1970 uint32_t fpscr, fpexc;
1971 struct target_vfp_sigframe *vfpframe;
1972 vfpframe = (struct target_vfp_sigframe *)regspace;
1973
1974 __get_user(magic, &vfpframe->magic);
1975 __get_user(sz, &vfpframe->size);
1976 if (magic != TARGET_VFP_MAGIC || sz != sizeof(*vfpframe)) {
1977 return 0;
1978 }
1979 for (i = 0; i < 32; i++) {
Peter Maydell005e1a02011-02-10 13:59:35 +00001980 __get_user(float64_val(env->vfp.regs[i]), &vfpframe->ufp.fpregs[i]);
Peter Maydell5f9099d2010-11-24 15:20:06 +00001981 }
1982 __get_user(fpscr, &vfpframe->ufp.fpscr);
1983 vfp_set_fpscr(env, fpscr);
1984 __get_user(fpexc, &vfpframe->ufp_exc.fpexc);
1985 /* Sanitise FPEXC: ensure VFP is enabled, FPINST2 is invalid
1986 * and the exception flag is cleared
1987 */
1988 fpexc |= (1 << 30);
1989 fpexc &= ~((1 << 31) | (1 << 28));
1990 env->vfp.xregs[ARM_VFP_FPEXC] = fpexc;
1991 __get_user(env->vfp.xregs[ARM_VFP_FPINST], &vfpframe->ufp_exc.fpinst);
1992 __get_user(env->vfp.xregs[ARM_VFP_FPINST2], &vfpframe->ufp_exc.fpinst2);
1993 return (abi_ulong*)(vfpframe + 1);
1994}
1995
Andreas Färber05390242012-02-25 03:37:53 +01001996static abi_ulong *restore_sigframe_v2_iwmmxt(CPUARMState *env,
1997 abi_ulong *regspace)
Peter Maydella59d69d2010-11-24 15:20:08 +00001998{
1999 int i;
2000 abi_ulong magic, sz;
2001 struct target_iwmmxt_sigframe *iwmmxtframe;
2002 iwmmxtframe = (struct target_iwmmxt_sigframe *)regspace;
2003
2004 __get_user(magic, &iwmmxtframe->magic);
2005 __get_user(sz, &iwmmxtframe->size);
2006 if (magic != TARGET_IWMMXT_MAGIC || sz != sizeof(*iwmmxtframe)) {
2007 return 0;
2008 }
2009 for (i = 0; i < 16; i++) {
2010 __get_user(env->iwmmxt.regs[i], &iwmmxtframe->regs[i]);
2011 }
2012 __get_user(env->vfp.xregs[ARM_IWMMXT_wCSSF], &iwmmxtframe->wcssf);
2013 __get_user(env->vfp.xregs[ARM_IWMMXT_wCASF], &iwmmxtframe->wcssf);
2014 __get_user(env->vfp.xregs[ARM_IWMMXT_wCGR0], &iwmmxtframe->wcgr0);
2015 __get_user(env->vfp.xregs[ARM_IWMMXT_wCGR1], &iwmmxtframe->wcgr1);
2016 __get_user(env->vfp.xregs[ARM_IWMMXT_wCGR2], &iwmmxtframe->wcgr2);
2017 __get_user(env->vfp.xregs[ARM_IWMMXT_wCGR3], &iwmmxtframe->wcgr3);
2018 return (abi_ulong*)(iwmmxtframe + 1);
2019}
2020
Andreas Färber05390242012-02-25 03:37:53 +01002021static int do_sigframe_return_v2(CPUARMState *env, target_ulong frame_addr,
pbrooka8c33202008-05-07 23:22:46 +00002022 struct target_ucontext_v2 *uc)
2023{
2024 sigset_t host_set;
Peter Maydell5f9099d2010-11-24 15:20:06 +00002025 abi_ulong *regspace;
pbrooka8c33202008-05-07 23:22:46 +00002026
2027 target_to_host_sigset(&host_set, &uc->tuc_sigmask);
Peter Maydell9eede5b2016-05-27 15:51:46 +01002028 set_sigmask(&host_set);
pbrooka8c33202008-05-07 23:22:46 +00002029
2030 if (restore_sigcontext(env, &uc->tuc_mcontext))
2031 return 1;
2032
Peter Maydell5f9099d2010-11-24 15:20:06 +00002033 /* Restore coprocessor signal frame */
2034 regspace = uc->tuc_regspace;
2035 if (arm_feature(env, ARM_FEATURE_VFP)) {
2036 regspace = restore_sigframe_v2_vfp(env, regspace);
2037 if (!regspace) {
2038 return 1;
2039 }
2040 }
Peter Maydella59d69d2010-11-24 15:20:08 +00002041 if (arm_feature(env, ARM_FEATURE_IWMMXT)) {
2042 regspace = restore_sigframe_v2_iwmmxt(env, regspace);
2043 if (!regspace) {
2044 return 1;
2045 }
2046 }
Peter Maydell5f9099d2010-11-24 15:20:06 +00002047
pbrooka8c33202008-05-07 23:22:46 +00002048 if (do_sigaltstack(frame_addr + offsetof(struct target_ucontext_v2, tuc_stack), 0, get_sp_from_cpustate(env)) == -EFAULT)
2049 return 1;
2050
2051#if 0
2052 /* Send SIGTRAP if we're single-stepping */
2053 if (ptrace_cancel_bpt(current))
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002054 send_sig(SIGTRAP, current, 1);
pbrooka8c33202008-05-07 23:22:46 +00002055#endif
2056
2057 return 0;
2058}
2059
Andreas Färber05390242012-02-25 03:37:53 +01002060static long do_sigreturn_v2(CPUARMState *env)
pbrooka8c33202008-05-07 23:22:46 +00002061{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002062 abi_ulong frame_addr;
2063 struct sigframe_v2 *frame = NULL;
pbrooka8c33202008-05-07 23:22:46 +00002064
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002065 /*
2066 * Since we stacked the signal on a 64-bit boundary,
2067 * then 'sp' should be word aligned here. If it's
2068 * not, then the user is trying to mess with us.
2069 */
2070 frame_addr = env->regs[13];
2071 trace_user_do_sigreturn(env, frame_addr);
2072 if (frame_addr & 7) {
2073 goto badframe;
2074 }
Peter Maydell978fae92013-07-29 12:00:32 +01002075
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002076 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
2077 goto badframe;
2078 }
pbrooka8c33202008-05-07 23:22:46 +00002079
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002080 if (do_sigframe_return_v2(env, frame_addr, &frame->uc)) {
2081 goto badframe;
2082 }
pbrooka8c33202008-05-07 23:22:46 +00002083
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002084 unlock_user_struct(frame, frame_addr, 0);
Timothy E Baldwinf0267ef2016-05-12 18:47:31 +01002085 return -TARGET_QEMU_ESIGRETURN;
pbrooka8c33202008-05-07 23:22:46 +00002086
2087badframe:
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002088 unlock_user_struct(frame, frame_addr, 0);
2089 force_sig(TARGET_SIGSEGV /* , current */);
2090 return 0;
pbrooka8c33202008-05-07 23:22:46 +00002091}
2092
Andreas Färber05390242012-02-25 03:37:53 +01002093long do_sigreturn(CPUARMState *env)
pbrooka8c33202008-05-07 23:22:46 +00002094{
2095 if (get_osversion() >= 0x020612) {
2096 return do_sigreturn_v2(env);
2097 } else {
2098 return do_sigreturn_v1(env);
2099 }
2100}
2101
Andreas Färber05390242012-02-25 03:37:53 +01002102static long do_rt_sigreturn_v1(CPUARMState *env)
bellard43fff232003-07-09 19:31:39 +00002103{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002104 abi_ulong frame_addr;
2105 struct rt_sigframe_v1 *frame = NULL;
2106 sigset_t host_set;
bellard43fff232003-07-09 19:31:39 +00002107
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002108 /*
2109 * Since we stacked the signal on a 64-bit boundary,
2110 * then 'sp' should be word aligned here. If it's
2111 * not, then the user is trying to mess with us.
2112 */
2113 frame_addr = env->regs[13];
2114 trace_user_do_rt_sigreturn(env, frame_addr);
2115 if (frame_addr & 7) {
2116 goto badframe;
2117 }
Peter Maydell978fae92013-07-29 12:00:32 +01002118
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002119 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
2120 goto badframe;
2121 }
bellard43fff232003-07-09 19:31:39 +00002122
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002123 target_to_host_sigset(&host_set, &frame->uc.tuc_sigmask);
Peter Maydell9eede5b2016-05-27 15:51:46 +01002124 set_sigmask(&host_set);
bellard43fff232003-07-09 19:31:39 +00002125
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002126 if (restore_sigcontext(env, &frame->uc.tuc_mcontext)) {
2127 goto badframe;
2128 }
bellard43fff232003-07-09 19:31:39 +00002129
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002130 if (do_sigaltstack(frame_addr + offsetof(struct rt_sigframe_v1, uc.tuc_stack), 0, get_sp_from_cpustate(env)) == -EFAULT)
2131 goto badframe;
thsa04e1342007-09-27 13:57:58 +00002132
bellard43fff232003-07-09 19:31:39 +00002133#if 0
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002134 /* Send SIGTRAP if we're single-stepping */
2135 if (ptrace_cancel_bpt(current))
2136 send_sig(SIGTRAP, current, 1);
bellard43fff232003-07-09 19:31:39 +00002137#endif
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002138 unlock_user_struct(frame, frame_addr, 0);
Timothy E Baldwinf0267ef2016-05-12 18:47:31 +01002139 return -TARGET_QEMU_ESIGRETURN;
bellard43fff232003-07-09 19:31:39 +00002140
2141badframe:
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002142 unlock_user_struct(frame, frame_addr, 0);
2143 force_sig(TARGET_SIGSEGV /* , current */);
2144 return 0;
bellard43fff232003-07-09 19:31:39 +00002145}
2146
Andreas Färber05390242012-02-25 03:37:53 +01002147static long do_rt_sigreturn_v2(CPUARMState *env)
pbrooka745ec62008-05-06 15:36:17 +00002148{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002149 abi_ulong frame_addr;
2150 struct rt_sigframe_v2 *frame = NULL;
pbrooka745ec62008-05-06 15:36:17 +00002151
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002152 /*
2153 * Since we stacked the signal on a 64-bit boundary,
2154 * then 'sp' should be word aligned here. If it's
2155 * not, then the user is trying to mess with us.
2156 */
2157 frame_addr = env->regs[13];
2158 trace_user_do_rt_sigreturn(env, frame_addr);
2159 if (frame_addr & 7) {
2160 goto badframe;
2161 }
Peter Maydell978fae92013-07-29 12:00:32 +01002162
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002163 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
2164 goto badframe;
2165 }
pbrooka745ec62008-05-06 15:36:17 +00002166
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002167 if (do_sigframe_return_v2(env, frame_addr, &frame->uc)) {
2168 goto badframe;
2169 }
pbrooka745ec62008-05-06 15:36:17 +00002170
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002171 unlock_user_struct(frame, frame_addr, 0);
Timothy E Baldwinf0267ef2016-05-12 18:47:31 +01002172 return -TARGET_QEMU_ESIGRETURN;
pbrooka745ec62008-05-06 15:36:17 +00002173
2174badframe:
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002175 unlock_user_struct(frame, frame_addr, 0);
2176 force_sig(TARGET_SIGSEGV /* , current */);
2177 return 0;
pbrooka745ec62008-05-06 15:36:17 +00002178}
2179
Andreas Färber05390242012-02-25 03:37:53 +01002180long do_rt_sigreturn(CPUARMState *env)
pbrooka745ec62008-05-06 15:36:17 +00002181{
2182 if (get_osversion() >= 0x020612) {
2183 return do_rt_sigreturn_v2(env);
2184 } else {
2185 return do_rt_sigreturn_v1(env);
2186 }
2187}
2188
bellard6d5e2162004-09-30 22:04:13 +00002189#elif defined(TARGET_SPARC)
bellard80a9d032005-01-03 23:31:27 +00002190
bellard6d5e2162004-09-30 22:04:13 +00002191#define __SUNOS_MAXWIN 31
2192
2193/* This is what SunOS does, so shall I. */
2194struct target_sigcontext {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002195 abi_ulong sigc_onstack; /* state to restore */
bellard6d5e2162004-09-30 22:04:13 +00002196
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002197 abi_ulong sigc_mask; /* sigmask to restore */
2198 abi_ulong sigc_sp; /* stack pointer */
2199 abi_ulong sigc_pc; /* program counter */
2200 abi_ulong sigc_npc; /* next program counter */
2201 abi_ulong sigc_psr; /* for condition codes etc */
2202 abi_ulong sigc_g1; /* User uses these two registers */
2203 abi_ulong sigc_o0; /* within the trampoline code. */
bellard6d5e2162004-09-30 22:04:13 +00002204
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002205 /* Now comes information regarding the users window set
bellard6d5e2162004-09-30 22:04:13 +00002206 * at the time of the signal.
2207 */
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002208 abi_ulong sigc_oswins; /* outstanding windows */
bellard6d5e2162004-09-30 22:04:13 +00002209
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002210 /* stack ptrs for each regwin buf */
2211 char *sigc_spbuf[__SUNOS_MAXWIN];
bellard6d5e2162004-09-30 22:04:13 +00002212
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002213 /* Windows to restore after signal */
2214 struct {
2215 abi_ulong locals[8];
2216 abi_ulong ins[8];
2217 } sigc_wbuf[__SUNOS_MAXWIN];
bellard6d5e2162004-09-30 22:04:13 +00002218};
2219/* A Sparc stack frame */
2220struct sparc_stackf {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002221 abi_ulong locals[8];
2222 abi_ulong ins[8];
2223 /* It's simpler to treat fp and callers_pc as elements of ins[]
Peter Maydelle321c342011-02-01 15:54:52 +00002224 * since we never need to access them ourselves.
2225 */
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002226 char *structptr;
2227 abi_ulong xargs[6];
2228 abi_ulong xxargs[1];
bellard6d5e2162004-09-30 22:04:13 +00002229};
2230
2231typedef struct {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002232 struct {
2233 abi_ulong psr;
2234 abi_ulong pc;
2235 abi_ulong npc;
2236 abi_ulong y;
2237 abi_ulong u_regs[16]; /* globals and ins */
2238 } si_regs;
2239 int si_mask;
bellard6d5e2162004-09-30 22:04:13 +00002240} __siginfo_t;
2241
2242typedef struct {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002243 abi_ulong si_float_regs[32];
2244 unsigned long si_fsr;
2245 unsigned long si_fpqdepth;
2246 struct {
2247 unsigned long *insn_addr;
2248 unsigned long insn;
2249 } si_fpqueue [16];
Anthony Liguoric227f092009-10-01 16:12:16 -05002250} qemu_siginfo_fpu_t;
bellard6d5e2162004-09-30 22:04:13 +00002251
2252
2253struct target_signal_frame {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002254 struct sparc_stackf ss;
2255 __siginfo_t info;
2256 abi_ulong fpu_save;
2257 abi_ulong insns[2] __attribute__ ((aligned (8)));
2258 abi_ulong extramask[TARGET_NSIG_WORDS - 1];
2259 abi_ulong extra_size; /* Should be 0 */
2260 qemu_siginfo_fpu_t fpu_state;
bellard6d5e2162004-09-30 22:04:13 +00002261};
2262struct target_rt_signal_frame {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002263 struct sparc_stackf ss;
2264 siginfo_t info;
2265 abi_ulong regs[20];
2266 sigset_t mask;
2267 abi_ulong fpu_save;
2268 unsigned int insns[2];
2269 stack_t stack;
2270 unsigned int extra_size; /* Should be 0 */
2271 qemu_siginfo_fpu_t fpu_state;
bellard6d5e2162004-09-30 22:04:13 +00002272};
2273
bellarde80cfcf2004-12-19 23:18:01 +00002274#define UREG_O0 16
2275#define UREG_O6 22
2276#define UREG_I0 0
2277#define UREG_I1 1
2278#define UREG_I2 2
blueswir15bfb56b2007-10-05 17:01:51 +00002279#define UREG_I3 3
2280#define UREG_I4 4
2281#define UREG_I5 5
bellarde80cfcf2004-12-19 23:18:01 +00002282#define UREG_I6 6
2283#define UREG_I7 7
2284#define UREG_L0 8
bellard6d5e2162004-09-30 22:04:13 +00002285#define UREG_FP UREG_I6
2286#define UREG_SP UREG_O6
2287
pbrook624f7972008-05-31 16:11:38 +00002288static inline abi_ulong get_sigframe(struct target_sigaction *sa,
Andreas Färber05390242012-02-25 03:37:53 +01002289 CPUSPARCState *env,
2290 unsigned long framesize)
bellard6d5e2162004-09-30 22:04:13 +00002291{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002292 abi_ulong sp;
bellard6d5e2162004-09-30 22:04:13 +00002293
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002294 sp = env->regwptr[UREG_FP];
bellard6d5e2162004-09-30 22:04:13 +00002295
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002296 /* This is the X/Open sanctioned signal stack switching. */
2297 if (sa->sa_flags & TARGET_SA_ONSTACK) {
2298 if (!on_sig_stack(sp)
2299 && !((target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size) & 7)) {
2300 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
2301 }
2302 }
2303 return sp - framesize;
bellard6d5e2162004-09-30 22:04:13 +00002304}
2305
2306static int
Andreas Färber05390242012-02-25 03:37:53 +01002307setup___siginfo(__siginfo_t *si, CPUSPARCState *env, abi_ulong mask)
bellard6d5e2162004-09-30 22:04:13 +00002308{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002309 int err = 0, i;
bellard6d5e2162004-09-30 22:04:13 +00002310
Riku Voipio1d8b5122014-04-23 10:26:05 +03002311 __put_user(env->psr, &si->si_regs.psr);
2312 __put_user(env->pc, &si->si_regs.pc);
2313 __put_user(env->npc, &si->si_regs.npc);
2314 __put_user(env->y, &si->si_regs.y);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002315 for (i=0; i < 8; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002316 __put_user(env->gregs[i], &si->si_regs.u_regs[i]);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002317 }
2318 for (i=0; i < 8; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002319 __put_user(env->regwptr[UREG_I0 + i], &si->si_regs.u_regs[i+8]);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002320 }
Riku Voipio1d8b5122014-04-23 10:26:05 +03002321 __put_user(mask, &si->si_mask);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002322 return err;
bellard6d5e2162004-09-30 22:04:13 +00002323}
bellarde80cfcf2004-12-19 23:18:01 +00002324
bellard80a9d032005-01-03 23:31:27 +00002325#if 0
bellard6d5e2162004-09-30 22:04:13 +00002326static int
2327setup_sigcontext(struct target_sigcontext *sc, /*struct _fpstate *fpstate,*/
Andreas Färber05390242012-02-25 03:37:53 +01002328 CPUSPARCState *env, unsigned long mask)
bellard6d5e2162004-09-30 22:04:13 +00002329{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002330 int err = 0;
bellard6d5e2162004-09-30 22:04:13 +00002331
Riku Voipio1d8b5122014-04-23 10:26:05 +03002332 __put_user(mask, &sc->sigc_mask);
2333 __put_user(env->regwptr[UREG_SP], &sc->sigc_sp);
2334 __put_user(env->pc, &sc->sigc_pc);
2335 __put_user(env->npc, &sc->sigc_npc);
2336 __put_user(env->psr, &sc->sigc_psr);
2337 __put_user(env->gregs[1], &sc->sigc_g1);
2338 __put_user(env->regwptr[UREG_O0], &sc->sigc_o0);
bellard6d5e2162004-09-30 22:04:13 +00002339
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002340 return err;
bellard6d5e2162004-09-30 22:04:13 +00002341}
bellard80a9d032005-01-03 23:31:27 +00002342#endif
bellard6d5e2162004-09-30 22:04:13 +00002343#define NF_ALIGNEDSZ (((sizeof(struct target_signal_frame) + 7) & (~7)))
2344
pbrook624f7972008-05-31 16:11:38 +00002345static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01002346 target_sigset_t *set, CPUSPARCState *env)
bellard6d5e2162004-09-30 22:04:13 +00002347{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002348 abi_ulong sf_addr;
2349 struct target_signal_frame *sf;
2350 int sigframe_size, err, i;
bellard6d5e2162004-09-30 22:04:13 +00002351
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002352 /* 1. Make sure everything is clean */
2353 //synchronize_user_stack();
bellard6d5e2162004-09-30 22:04:13 +00002354
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002355 sigframe_size = NF_ALIGNEDSZ;
2356 sf_addr = get_sigframe(ka, env, sigframe_size);
2357 trace_user_setup_frame(env, sf_addr);
bellard6d5e2162004-09-30 22:04:13 +00002358
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002359 sf = lock_user(VERIFY_WRITE, sf_addr,
2360 sizeof(struct target_signal_frame), 0);
2361 if (!sf) {
2362 goto sigsegv;
2363 }
bellard6d5e2162004-09-30 22:04:13 +00002364#if 0
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002365 if (invalid_frame_pointer(sf, sigframe_size))
2366 goto sigill_and_return;
bellard6d5e2162004-09-30 22:04:13 +00002367#endif
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002368 /* 2. Save the current process state */
2369 err = setup___siginfo(&sf->info, env, set->sig[0]);
Riku Voipio1d8b5122014-04-23 10:26:05 +03002370 __put_user(0, &sf->extra_size);
bellard6d5e2162004-09-30 22:04:13 +00002371
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002372 //save_fpu_state(regs, &sf->fpu_state);
2373 //__put_user(&sf->fpu_state, &sf->fpu_save);
bellard6d5e2162004-09-30 22:04:13 +00002374
Riku Voipio1d8b5122014-04-23 10:26:05 +03002375 __put_user(set->sig[0], &sf->info.si_mask);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002376 for (i = 0; i < TARGET_NSIG_WORDS - 1; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002377 __put_user(set->sig[i + 1], &sf->extramask[i]);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002378 }
bellard6d5e2162004-09-30 22:04:13 +00002379
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002380 for (i = 0; i < 8; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002381 __put_user(env->regwptr[i + UREG_L0], &sf->ss.locals[i]);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002382 }
2383 for (i = 0; i < 8; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002384 __put_user(env->regwptr[i + UREG_I0], &sf->ss.ins[i]);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002385 }
2386 if (err)
2387 goto sigsegv;
bellard6d5e2162004-09-30 22:04:13 +00002388
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002389 /* 3. signal handler back-trampoline and parameters */
2390 env->regwptr[UREG_FP] = sf_addr;
2391 env->regwptr[UREG_I0] = sig;
2392 env->regwptr[UREG_I1] = sf_addr +
2393 offsetof(struct target_signal_frame, info);
2394 env->regwptr[UREG_I2] = sf_addr +
2395 offsetof(struct target_signal_frame, info);
bellard6d5e2162004-09-30 22:04:13 +00002396
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002397 /* 4. signal handler */
2398 env->pc = ka->_sa_handler;
2399 env->npc = (env->pc + 4);
2400 /* 5. return to kernel instructions */
2401 if (ka->sa_restorer) {
2402 env->regwptr[UREG_I7] = ka->sa_restorer;
2403 } else {
2404 uint32_t val32;
bellard459a4012007-11-11 19:45:10 +00002405
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002406 env->regwptr[UREG_I7] = sf_addr +
2407 offsetof(struct target_signal_frame, insns) - 2 * 4;
bellard6d5e2162004-09-30 22:04:13 +00002408
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002409 /* mov __NR_sigreturn, %g1 */
2410 val32 = 0x821020d8;
Riku Voipio1d8b5122014-04-23 10:26:05 +03002411 __put_user(val32, &sf->insns[0]);
bellard6d5e2162004-09-30 22:04:13 +00002412
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002413 /* t 0x10 */
2414 val32 = 0x91d02010;
Riku Voipio1d8b5122014-04-23 10:26:05 +03002415 __put_user(val32, &sf->insns[1]);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002416 if (err)
2417 goto sigsegv;
bellard6d5e2162004-09-30 22:04:13 +00002418
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002419 /* Flush instruction space. */
2420 // flush_sig_insns(current->mm, (unsigned long) &(sf->insns[0]));
2421 // tb_flush(env);
2422 }
2423 unlock_user(sf, sf_addr, sizeof(struct target_signal_frame));
2424 return;
bellard459a4012007-11-11 19:45:10 +00002425#if 0
2426sigill_and_return:
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002427 force_sig(TARGET_SIGILL);
bellard459a4012007-11-11 19:45:10 +00002428#endif
bellard6d5e2162004-09-30 22:04:13 +00002429sigsegv:
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002430 unlock_user(sf, sf_addr, sizeof(struct target_signal_frame));
2431 force_sig(TARGET_SIGSEGV);
bellard6d5e2162004-09-30 22:04:13 +00002432}
bellard6d5e2162004-09-30 22:04:13 +00002433
pbrook624f7972008-05-31 16:11:38 +00002434static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05002435 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01002436 target_sigset_t *set, CPUSPARCState *env)
bellard6d5e2162004-09-30 22:04:13 +00002437{
2438 fprintf(stderr, "setup_rt_frame: not implemented\n");
2439}
2440
Andreas Färber05390242012-02-25 03:37:53 +01002441long do_sigreturn(CPUSPARCState *env)
bellard6d5e2162004-09-30 22:04:13 +00002442{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002443 abi_ulong sf_addr;
2444 struct target_signal_frame *sf;
2445 uint32_t up_psr, pc, npc;
2446 target_sigset_t set;
2447 sigset_t host_set;
2448 int err=0, i;
bellard6d5e2162004-09-30 22:04:13 +00002449
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002450 sf_addr = env->regwptr[UREG_FP];
2451 trace_user_do_sigreturn(env, sf_addr);
2452 if (!lock_user_struct(VERIFY_READ, sf, sf_addr, 1)) {
2453 goto segv_and_exit;
2454 }
bellard6d5e2162004-09-30 22:04:13 +00002455
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002456 /* 1. Make sure we are not getting garbage from the user */
bellard6d5e2162004-09-30 22:04:13 +00002457
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002458 if (sf_addr & 3)
2459 goto segv_and_exit;
bellard6d5e2162004-09-30 22:04:13 +00002460
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002461 __get_user(pc, &sf->info.si_regs.pc);
2462 __get_user(npc, &sf->info.si_regs.npc);
bellard6d5e2162004-09-30 22:04:13 +00002463
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002464 if ((pc | npc) & 3) {
2465 goto segv_and_exit;
2466 }
bellard6d5e2162004-09-30 22:04:13 +00002467
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002468 /* 2. Restore the state */
2469 __get_user(up_psr, &sf->info.si_regs.psr);
bellarde80cfcf2004-12-19 23:18:01 +00002470
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002471 /* User can only change condition codes and FPU enabling in %psr. */
2472 env->psr = (up_psr & (PSR_ICC /* | PSR_EF */))
2473 | (env->psr & ~(PSR_ICC /* | PSR_EF */));
bellarda315a142005-01-30 22:59:18 +00002474
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002475 env->pc = pc;
2476 env->npc = npc;
2477 __get_user(env->y, &sf->info.si_regs.y);
2478 for (i=0; i < 8; i++) {
2479 __get_user(env->gregs[i], &sf->info.si_regs.u_regs[i]);
2480 }
2481 for (i=0; i < 8; i++) {
2482 __get_user(env->regwptr[i + UREG_I0], &sf->info.si_regs.u_regs[i+8]);
2483 }
bellard6d5e2162004-09-30 22:04:13 +00002484
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002485 /* FIXME: implement FPU save/restore:
Peter Maydell2aec3a22011-06-16 17:37:14 +01002486 * __get_user(fpu_save, &sf->fpu_save);
2487 * if (fpu_save)
2488 * err |= restore_fpu_state(env, fpu_save);
2489 */
bellard6d5e2162004-09-30 22:04:13 +00002490
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002491 /* This is pretty much atomic, no amount locking would prevent
bellard6d5e2162004-09-30 22:04:13 +00002492 * the races which exist anyways.
2493 */
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002494 __get_user(set.sig[0], &sf->info.si_mask);
2495 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
2496 __get_user(set.sig[i], &sf->extramask[i - 1]);
2497 }
bellarde80cfcf2004-12-19 23:18:01 +00002498
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002499 target_to_host_sigset_internal(&host_set, &set);
Peter Maydell9eede5b2016-05-27 15:51:46 +01002500 set_sigmask(&host_set);
bellard6d5e2162004-09-30 22:04:13 +00002501
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002502 if (err) {
2503 goto segv_and_exit;
2504 }
2505 unlock_user_struct(sf, sf_addr, 0);
Timothy E Baldwinc0bea682016-05-12 18:47:34 +01002506 return -TARGET_QEMU_ESIGRETURN;
bellard6d5e2162004-09-30 22:04:13 +00002507
2508segv_and_exit:
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002509 unlock_user_struct(sf, sf_addr, 0);
2510 force_sig(TARGET_SIGSEGV);
bellard6d5e2162004-09-30 22:04:13 +00002511}
2512
Andreas Färber05390242012-02-25 03:37:53 +01002513long do_rt_sigreturn(CPUSPARCState *env)
bellard6d5e2162004-09-30 22:04:13 +00002514{
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01002515 trace_user_do_rt_sigreturn(env, 0);
bellard6d5e2162004-09-30 22:04:13 +00002516 fprintf(stderr, "do_rt_sigreturn: not implemented\n");
bellardf8b0aa22007-11-11 23:03:42 +00002517 return -TARGET_ENOSYS;
bellard6d5e2162004-09-30 22:04:13 +00002518}
2519
bellard459a4012007-11-11 19:45:10 +00002520#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
blueswir15bfb56b2007-10-05 17:01:51 +00002521#define MC_TSTATE 0
2522#define MC_PC 1
2523#define MC_NPC 2
2524#define MC_Y 3
2525#define MC_G1 4
2526#define MC_G2 5
2527#define MC_G3 6
2528#define MC_G4 7
2529#define MC_G5 8
2530#define MC_G6 9
2531#define MC_G7 10
2532#define MC_O0 11
2533#define MC_O1 12
2534#define MC_O2 13
2535#define MC_O3 14
2536#define MC_O4 15
2537#define MC_O5 16
2538#define MC_O6 17
2539#define MC_O7 18
2540#define MC_NGREG 19
2541
Anthony Liguoric227f092009-10-01 16:12:16 -05002542typedef abi_ulong target_mc_greg_t;
2543typedef target_mc_greg_t target_mc_gregset_t[MC_NGREG];
blueswir15bfb56b2007-10-05 17:01:51 +00002544
2545struct target_mc_fq {
blueswir1992f48a2007-10-14 16:27:31 +00002546 abi_ulong *mcfq_addr;
blueswir15bfb56b2007-10-05 17:01:51 +00002547 uint32_t mcfq_insn;
2548};
2549
2550struct target_mc_fpu {
2551 union {
2552 uint32_t sregs[32];
2553 uint64_t dregs[32];
2554 //uint128_t qregs[16];
2555 } mcfpu_fregs;
blueswir1992f48a2007-10-14 16:27:31 +00002556 abi_ulong mcfpu_fsr;
2557 abi_ulong mcfpu_fprs;
2558 abi_ulong mcfpu_gsr;
blueswir15bfb56b2007-10-05 17:01:51 +00002559 struct target_mc_fq *mcfpu_fq;
2560 unsigned char mcfpu_qcnt;
2561 unsigned char mcfpu_qentsz;
2562 unsigned char mcfpu_enab;
2563};
Anthony Liguoric227f092009-10-01 16:12:16 -05002564typedef struct target_mc_fpu target_mc_fpu_t;
blueswir15bfb56b2007-10-05 17:01:51 +00002565
2566typedef struct {
Anthony Liguoric227f092009-10-01 16:12:16 -05002567 target_mc_gregset_t mc_gregs;
2568 target_mc_greg_t mc_fp;
2569 target_mc_greg_t mc_i7;
2570 target_mc_fpu_t mc_fpregs;
2571} target_mcontext_t;
blueswir15bfb56b2007-10-05 17:01:51 +00002572
2573struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02002574 struct target_ucontext *tuc_link;
2575 abi_ulong tuc_flags;
2576 target_sigset_t tuc_sigmask;
2577 target_mcontext_t tuc_mcontext;
blueswir15bfb56b2007-10-05 17:01:51 +00002578};
2579
2580/* A V9 register window */
2581struct target_reg_window {
blueswir1992f48a2007-10-14 16:27:31 +00002582 abi_ulong locals[8];
2583 abi_ulong ins[8];
blueswir15bfb56b2007-10-05 17:01:51 +00002584};
2585
2586#define TARGET_STACK_BIAS 2047
2587
2588/* {set, get}context() needed for 64-bit SparcLinux userland. */
2589void sparc64_set_context(CPUSPARCState *env)
2590{
bellard459a4012007-11-11 19:45:10 +00002591 abi_ulong ucp_addr;
2592 struct target_ucontext *ucp;
Anthony Liguoric227f092009-10-01 16:12:16 -05002593 target_mc_gregset_t *grp;
blueswir1992f48a2007-10-14 16:27:31 +00002594 abi_ulong pc, npc, tstate;
bellard459a4012007-11-11 19:45:10 +00002595 abi_ulong fp, i7, w_addr;
blueswir15bfb56b2007-10-05 17:01:51 +00002596 unsigned int i;
blueswir15bfb56b2007-10-05 17:01:51 +00002597
bellard459a4012007-11-11 19:45:10 +00002598 ucp_addr = env->regwptr[UREG_I0];
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002599 if (!lock_user_struct(VERIFY_READ, ucp, ucp_addr, 1)) {
bellard459a4012007-11-11 19:45:10 +00002600 goto do_sigsegv;
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002601 }
Aurelien Jarno60e99242010-03-29 02:12:51 +02002602 grp = &ucp->tuc_mcontext.mc_gregs;
Riku Voipio1d8b5122014-04-23 10:26:05 +03002603 __get_user(pc, &((*grp)[MC_PC]));
2604 __get_user(npc, &((*grp)[MC_NPC]));
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002605 if ((pc | npc) & 3) {
blueswir15bfb56b2007-10-05 17:01:51 +00002606 goto do_sigsegv;
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002607 }
blueswir15bfb56b2007-10-05 17:01:51 +00002608 if (env->regwptr[UREG_I1]) {
Anthony Liguoric227f092009-10-01 16:12:16 -05002609 target_sigset_t target_set;
blueswir15bfb56b2007-10-05 17:01:51 +00002610 sigset_t set;
2611
2612 if (TARGET_NSIG_WORDS == 1) {
Riku Voipiobe3ef5c2014-04-23 14:02:36 +03002613 __get_user(target_set.sig[0], &ucp->tuc_sigmask.sig[0]);
blueswir15bfb56b2007-10-05 17:01:51 +00002614 } else {
bellard459a4012007-11-11 19:45:10 +00002615 abi_ulong *src, *dst;
Aurelien Jarno60e99242010-03-29 02:12:51 +02002616 src = ucp->tuc_sigmask.sig;
bellard459a4012007-11-11 19:45:10 +00002617 dst = target_set.sig;
Stefan Weil0d9e61c2013-12-07 14:48:08 +01002618 for (i = 0; i < TARGET_NSIG_WORDS; i++, dst++, src++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002619 __get_user(*dst, src);
Stefan Weil0d9e61c2013-12-07 14:48:08 +01002620 }
blueswir15bfb56b2007-10-05 17:01:51 +00002621 }
2622 target_to_host_sigset_internal(&set, &target_set);
Peter Maydell9eede5b2016-05-27 15:51:46 +01002623 set_sigmask(&set);
blueswir15bfb56b2007-10-05 17:01:51 +00002624 }
2625 env->pc = pc;
2626 env->npc = npc;
Riku Voipio1d8b5122014-04-23 10:26:05 +03002627 __get_user(env->y, &((*grp)[MC_Y]));
2628 __get_user(tstate, &((*grp)[MC_TSTATE]));
blueswir15bfb56b2007-10-05 17:01:51 +00002629 env->asi = (tstate >> 24) & 0xff;
Blue Swirl5a834bb2010-05-09 20:19:04 +00002630 cpu_put_ccr(env, tstate >> 32);
2631 cpu_put_cwp64(env, tstate & 0x1f);
Riku Voipio1d8b5122014-04-23 10:26:05 +03002632 __get_user(env->gregs[1], (&(*grp)[MC_G1]));
2633 __get_user(env->gregs[2], (&(*grp)[MC_G2]));
2634 __get_user(env->gregs[3], (&(*grp)[MC_G3]));
2635 __get_user(env->gregs[4], (&(*grp)[MC_G4]));
2636 __get_user(env->gregs[5], (&(*grp)[MC_G5]));
2637 __get_user(env->gregs[6], (&(*grp)[MC_G6]));
2638 __get_user(env->gregs[7], (&(*grp)[MC_G7]));
2639 __get_user(env->regwptr[UREG_I0], (&(*grp)[MC_O0]));
2640 __get_user(env->regwptr[UREG_I1], (&(*grp)[MC_O1]));
2641 __get_user(env->regwptr[UREG_I2], (&(*grp)[MC_O2]));
2642 __get_user(env->regwptr[UREG_I3], (&(*grp)[MC_O3]));
2643 __get_user(env->regwptr[UREG_I4], (&(*grp)[MC_O4]));
2644 __get_user(env->regwptr[UREG_I5], (&(*grp)[MC_O5]));
2645 __get_user(env->regwptr[UREG_I6], (&(*grp)[MC_O6]));
2646 __get_user(env->regwptr[UREG_I7], (&(*grp)[MC_O7]));
blueswir15bfb56b2007-10-05 17:01:51 +00002647
Riku Voipio1d8b5122014-04-23 10:26:05 +03002648 __get_user(fp, &(ucp->tuc_mcontext.mc_fp));
2649 __get_user(i7, &(ucp->tuc_mcontext.mc_i7));
blueswir15bfb56b2007-10-05 17:01:51 +00002650
bellard459a4012007-11-11 19:45:10 +00002651 w_addr = TARGET_STACK_BIAS+env->regwptr[UREG_I6];
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002652 if (put_user(fp, w_addr + offsetof(struct target_reg_window, ins[6]),
2653 abi_ulong) != 0) {
bellard459a4012007-11-11 19:45:10 +00002654 goto do_sigsegv;
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002655 }
2656 if (put_user(i7, w_addr + offsetof(struct target_reg_window, ins[7]),
2657 abi_ulong) != 0) {
bellard459a4012007-11-11 19:45:10 +00002658 goto do_sigsegv;
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002659 }
Peter Maydellc7b016b2011-06-16 17:37:15 +01002660 /* FIXME this does not match how the kernel handles the FPU in
2661 * its sparc64_set_context implementation. In particular the FPU
2662 * is only restored if fenab is non-zero in:
2663 * __get_user(fenab, &(ucp->tuc_mcontext.mc_fpregs.mcfpu_enab));
2664 */
Riku Voipiobe3ef5c2014-04-23 14:02:36 +03002665 __get_user(env->fprs, &(ucp->tuc_mcontext.mc_fpregs.mcfpu_fprs));
bellard459a4012007-11-11 19:45:10 +00002666 {
Richard Henderson30038fd2011-10-17 10:42:49 -07002667 uint32_t *src = ucp->tuc_mcontext.mc_fpregs.mcfpu_fregs.sregs;
2668 for (i = 0; i < 64; i++, src++) {
2669 if (i & 1) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002670 __get_user(env->fpr[i/2].l.lower, src);
Richard Henderson30038fd2011-10-17 10:42:49 -07002671 } else {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002672 __get_user(env->fpr[i/2].l.upper, src);
Richard Henderson30038fd2011-10-17 10:42:49 -07002673 }
2674 }
bellard459a4012007-11-11 19:45:10 +00002675 }
Riku Voipio1d8b5122014-04-23 10:26:05 +03002676 __get_user(env->fsr,
2677 &(ucp->tuc_mcontext.mc_fpregs.mcfpu_fsr));
2678 __get_user(env->gsr,
2679 &(ucp->tuc_mcontext.mc_fpregs.mcfpu_gsr));
bellard459a4012007-11-11 19:45:10 +00002680 unlock_user_struct(ucp, ucp_addr, 0);
blueswir15bfb56b2007-10-05 17:01:51 +00002681 return;
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002682do_sigsegv:
bellard459a4012007-11-11 19:45:10 +00002683 unlock_user_struct(ucp, ucp_addr, 0);
Riku Voipio66393fb2009-12-04 15:16:32 +02002684 force_sig(TARGET_SIGSEGV);
blueswir15bfb56b2007-10-05 17:01:51 +00002685}
2686
2687void sparc64_get_context(CPUSPARCState *env)
2688{
bellard459a4012007-11-11 19:45:10 +00002689 abi_ulong ucp_addr;
2690 struct target_ucontext *ucp;
Anthony Liguoric227f092009-10-01 16:12:16 -05002691 target_mc_gregset_t *grp;
2692 target_mcontext_t *mcp;
bellard459a4012007-11-11 19:45:10 +00002693 abi_ulong fp, i7, w_addr;
blueswir15bfb56b2007-10-05 17:01:51 +00002694 int err;
2695 unsigned int i;
Anthony Liguoric227f092009-10-01 16:12:16 -05002696 target_sigset_t target_set;
blueswir15bfb56b2007-10-05 17:01:51 +00002697 sigset_t set;
2698
bellard459a4012007-11-11 19:45:10 +00002699 ucp_addr = env->regwptr[UREG_I0];
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002700 if (!lock_user_struct(VERIFY_WRITE, ucp, ucp_addr, 0)) {
bellard459a4012007-11-11 19:45:10 +00002701 goto do_sigsegv;
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002702 }
bellard459a4012007-11-11 19:45:10 +00002703
Aurelien Jarno60e99242010-03-29 02:12:51 +02002704 mcp = &ucp->tuc_mcontext;
blueswir15bfb56b2007-10-05 17:01:51 +00002705 grp = &mcp->mc_gregs;
2706
2707 /* Skip over the trap instruction, first. */
2708 env->pc = env->npc;
2709 env->npc += 4;
2710
Peter Maydell3d3efba2016-05-27 15:51:49 +01002711 /* If we're only reading the signal mask then do_sigprocmask()
2712 * is guaranteed not to fail, which is important because we don't
2713 * have any way to signal a failure or restart this operation since
2714 * this is not a normal syscall.
2715 */
2716 err = do_sigprocmask(0, NULL, &set);
2717 assert(err == 0);
blueswir15bfb56b2007-10-05 17:01:51 +00002718 host_to_target_sigset_internal(&target_set, &set);
bellard459a4012007-11-11 19:45:10 +00002719 if (TARGET_NSIG_WORDS == 1) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002720 __put_user(target_set.sig[0],
2721 (abi_ulong *)&ucp->tuc_sigmask);
bellard459a4012007-11-11 19:45:10 +00002722 } else {
2723 abi_ulong *src, *dst;
2724 src = target_set.sig;
Aurelien Jarno60e99242010-03-29 02:12:51 +02002725 dst = ucp->tuc_sigmask.sig;
Stefan Weil0d9e61c2013-12-07 14:48:08 +01002726 for (i = 0; i < TARGET_NSIG_WORDS; i++, dst++, src++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002727 __put_user(*src, dst);
Stefan Weil0d9e61c2013-12-07 14:48:08 +01002728 }
blueswir15bfb56b2007-10-05 17:01:51 +00002729 if (err)
2730 goto do_sigsegv;
2731 }
2732
bellard459a4012007-11-11 19:45:10 +00002733 /* XXX: tstate must be saved properly */
Riku Voipio1d8b5122014-04-23 10:26:05 +03002734 // __put_user(env->tstate, &((*grp)[MC_TSTATE]));
2735 __put_user(env->pc, &((*grp)[MC_PC]));
2736 __put_user(env->npc, &((*grp)[MC_NPC]));
2737 __put_user(env->y, &((*grp)[MC_Y]));
2738 __put_user(env->gregs[1], &((*grp)[MC_G1]));
2739 __put_user(env->gregs[2], &((*grp)[MC_G2]));
2740 __put_user(env->gregs[3], &((*grp)[MC_G3]));
2741 __put_user(env->gregs[4], &((*grp)[MC_G4]));
2742 __put_user(env->gregs[5], &((*grp)[MC_G5]));
2743 __put_user(env->gregs[6], &((*grp)[MC_G6]));
2744 __put_user(env->gregs[7], &((*grp)[MC_G7]));
2745 __put_user(env->regwptr[UREG_I0], &((*grp)[MC_O0]));
2746 __put_user(env->regwptr[UREG_I1], &((*grp)[MC_O1]));
2747 __put_user(env->regwptr[UREG_I2], &((*grp)[MC_O2]));
2748 __put_user(env->regwptr[UREG_I3], &((*grp)[MC_O3]));
2749 __put_user(env->regwptr[UREG_I4], &((*grp)[MC_O4]));
2750 __put_user(env->regwptr[UREG_I5], &((*grp)[MC_O5]));
2751 __put_user(env->regwptr[UREG_I6], &((*grp)[MC_O6]));
2752 __put_user(env->regwptr[UREG_I7], &((*grp)[MC_O7]));
blueswir15bfb56b2007-10-05 17:01:51 +00002753
bellard459a4012007-11-11 19:45:10 +00002754 w_addr = TARGET_STACK_BIAS+env->regwptr[UREG_I6];
2755 fp = i7 = 0;
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002756 if (get_user(fp, w_addr + offsetof(struct target_reg_window, ins[6]),
2757 abi_ulong) != 0) {
bellard459a4012007-11-11 19:45:10 +00002758 goto do_sigsegv;
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002759 }
2760 if (get_user(i7, w_addr + offsetof(struct target_reg_window, ins[7]),
2761 abi_ulong) != 0) {
bellard459a4012007-11-11 19:45:10 +00002762 goto do_sigsegv;
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002763 }
Riku Voipio1d8b5122014-04-23 10:26:05 +03002764 __put_user(fp, &(mcp->mc_fp));
2765 __put_user(i7, &(mcp->mc_i7));
blueswir15bfb56b2007-10-05 17:01:51 +00002766
bellard459a4012007-11-11 19:45:10 +00002767 {
Richard Henderson30038fd2011-10-17 10:42:49 -07002768 uint32_t *dst = ucp->tuc_mcontext.mc_fpregs.mcfpu_fregs.sregs;
2769 for (i = 0; i < 64; i++, dst++) {
2770 if (i & 1) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002771 __put_user(env->fpr[i/2].l.lower, dst);
Richard Henderson30038fd2011-10-17 10:42:49 -07002772 } else {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002773 __put_user(env->fpr[i/2].l.upper, dst);
Richard Henderson30038fd2011-10-17 10:42:49 -07002774 }
2775 }
bellard459a4012007-11-11 19:45:10 +00002776 }
Riku Voipio1d8b5122014-04-23 10:26:05 +03002777 __put_user(env->fsr, &(mcp->mc_fpregs.mcfpu_fsr));
2778 __put_user(env->gsr, &(mcp->mc_fpregs.mcfpu_gsr));
2779 __put_user(env->fprs, &(mcp->mc_fpregs.mcfpu_fprs));
blueswir15bfb56b2007-10-05 17:01:51 +00002780
2781 if (err)
2782 goto do_sigsegv;
bellard459a4012007-11-11 19:45:10 +00002783 unlock_user_struct(ucp, ucp_addr, 1);
blueswir15bfb56b2007-10-05 17:01:51 +00002784 return;
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002785do_sigsegv:
bellard459a4012007-11-11 19:45:10 +00002786 unlock_user_struct(ucp, ucp_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02002787 force_sig(TARGET_SIGSEGV);
blueswir15bfb56b2007-10-05 17:01:51 +00002788}
2789#endif
Richard Hendersonff970902013-02-10 10:30:42 -08002790#elif defined(TARGET_MIPS) || defined(TARGET_MIPS64)
bellard106ec872006-06-27 21:08:10 +00002791
Richard Hendersonff970902013-02-10 10:30:42 -08002792# if defined(TARGET_ABI_MIPSO32)
bellard106ec872006-06-27 21:08:10 +00002793struct target_sigcontext {
2794 uint32_t sc_regmask; /* Unused */
2795 uint32_t sc_status;
2796 uint64_t sc_pc;
2797 uint64_t sc_regs[32];
2798 uint64_t sc_fpregs[32];
2799 uint32_t sc_ownedfp; /* Unused */
2800 uint32_t sc_fpc_csr;
2801 uint32_t sc_fpc_eir; /* Unused */
2802 uint32_t sc_used_math;
2803 uint32_t sc_dsp; /* dsp status, was sc_ssflags */
Paul Brook94c54952009-07-09 18:40:15 +01002804 uint32_t pad0;
bellard106ec872006-06-27 21:08:10 +00002805 uint64_t sc_mdhi;
2806 uint64_t sc_mdlo;
2807 target_ulong sc_hi1; /* Was sc_cause */
2808 target_ulong sc_lo1; /* Was sc_badvaddr */
2809 target_ulong sc_hi2; /* Was sc_sigset[4] */
2810 target_ulong sc_lo2;
2811 target_ulong sc_hi3;
2812 target_ulong sc_lo3;
2813};
Richard Hendersonff970902013-02-10 10:30:42 -08002814# else /* N32 || N64 */
2815struct target_sigcontext {
2816 uint64_t sc_regs[32];
2817 uint64_t sc_fpregs[32];
2818 uint64_t sc_mdhi;
2819 uint64_t sc_hi1;
2820 uint64_t sc_hi2;
2821 uint64_t sc_hi3;
2822 uint64_t sc_mdlo;
2823 uint64_t sc_lo1;
2824 uint64_t sc_lo2;
2825 uint64_t sc_lo3;
2826 uint64_t sc_pc;
2827 uint32_t sc_fpc_csr;
2828 uint32_t sc_used_math;
2829 uint32_t sc_dsp;
2830 uint32_t sc_reserved;
2831};
2832# endif /* O32 */
bellard106ec872006-06-27 21:08:10 +00002833
2834struct sigframe {
2835 uint32_t sf_ass[4]; /* argument save space for o32 */
2836 uint32_t sf_code[2]; /* signal trampoline */
2837 struct target_sigcontext sf_sc;
Anthony Liguoric227f092009-10-01 16:12:16 -05002838 target_sigset_t sf_mask;
bellard106ec872006-06-27 21:08:10 +00002839};
2840
pbrook0b1bcb02009-04-21 01:41:10 +00002841struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02002842 target_ulong tuc_flags;
2843 target_ulong tuc_link;
2844 target_stack_t tuc_stack;
Paul Brook94c54952009-07-09 18:40:15 +01002845 target_ulong pad0;
Aurelien Jarno60e99242010-03-29 02:12:51 +02002846 struct target_sigcontext tuc_mcontext;
2847 target_sigset_t tuc_sigmask;
pbrook0b1bcb02009-04-21 01:41:10 +00002848};
2849
2850struct target_rt_sigframe {
2851 uint32_t rs_ass[4]; /* argument save space for o32 */
2852 uint32_t rs_code[2]; /* signal trampoline */
2853 struct target_siginfo rs_info;
2854 struct target_ucontext rs_uc;
2855};
2856
bellard106ec872006-06-27 21:08:10 +00002857/* Install trampoline to jump back from signal handler */
2858static inline int install_sigtramp(unsigned int *tramp, unsigned int syscall)
2859{
Richard Henderson084d0492013-02-10 10:30:44 -08002860 int err = 0;
bellard106ec872006-06-27 21:08:10 +00002861
2862 /*
Richard Henderson084d0492013-02-10 10:30:44 -08002863 * Set up the return code ...
2864 *
2865 * li v0, __NR__foo_sigreturn
2866 * syscall
2867 */
bellard106ec872006-06-27 21:08:10 +00002868
Riku Voipio1d8b5122014-04-23 10:26:05 +03002869 __put_user(0x24020000 + syscall, tramp + 0);
2870 __put_user(0x0000000c , tramp + 1);
bellard106ec872006-06-27 21:08:10 +00002871 return err;
2872}
2873
Riku Voipio41ecc722014-04-23 11:01:00 +03002874static inline void setup_sigcontext(CPUMIPSState *regs,
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002875 struct target_sigcontext *sc)
bellard106ec872006-06-27 21:08:10 +00002876{
Richard Henderson084d0492013-02-10 10:30:44 -08002877 int i;
bellard106ec872006-06-27 21:08:10 +00002878
Riku Voipio1d8b5122014-04-23 10:26:05 +03002879 __put_user(exception_resume_pc(regs), &sc->sc_pc);
Kwok Cheung Yeung1239b472013-05-17 14:51:21 -07002880 regs->hflags &= ~MIPS_HFLAG_BMASK;
bellard106ec872006-06-27 21:08:10 +00002881
Richard Henderson084d0492013-02-10 10:30:44 -08002882 __put_user(0, &sc->sc_regs[0]);
2883 for (i = 1; i < 32; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002884 __put_user(regs->active_tc.gpr[i], &sc->sc_regs[i]);
Richard Henderson084d0492013-02-10 10:30:44 -08002885 }
bellard106ec872006-06-27 21:08:10 +00002886
Riku Voipio1d8b5122014-04-23 10:26:05 +03002887 __put_user(regs->active_tc.HI[0], &sc->sc_mdhi);
2888 __put_user(regs->active_tc.LO[0], &sc->sc_mdlo);
bellard106ec872006-06-27 21:08:10 +00002889
Richard Henderson084d0492013-02-10 10:30:44 -08002890 /* Rather than checking for dsp existence, always copy. The storage
2891 would just be garbage otherwise. */
Riku Voipio1d8b5122014-04-23 10:26:05 +03002892 __put_user(regs->active_tc.HI[1], &sc->sc_hi1);
2893 __put_user(regs->active_tc.HI[2], &sc->sc_hi2);
2894 __put_user(regs->active_tc.HI[3], &sc->sc_hi3);
2895 __put_user(regs->active_tc.LO[1], &sc->sc_lo1);
2896 __put_user(regs->active_tc.LO[2], &sc->sc_lo2);
2897 __put_user(regs->active_tc.LO[3], &sc->sc_lo3);
Richard Henderson084d0492013-02-10 10:30:44 -08002898 {
2899 uint32_t dsp = cpu_rddsp(0x3ff, regs);
Riku Voipio1d8b5122014-04-23 10:26:05 +03002900 __put_user(dsp, &sc->sc_dsp);
bellard106ec872006-06-27 21:08:10 +00002901 }
Richard Henderson084d0492013-02-10 10:30:44 -08002902
Riku Voipio1d8b5122014-04-23 10:26:05 +03002903 __put_user(1, &sc->sc_used_math);
Richard Henderson084d0492013-02-10 10:30:44 -08002904
2905 for (i = 0; i < 32; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002906 __put_user(regs->active_fpu.fpr[i].d, &sc->sc_fpregs[i]);
bellard106ec872006-06-27 21:08:10 +00002907 }
bellard106ec872006-06-27 21:08:10 +00002908}
2909
Riku Voipio016d2e12014-04-23 11:19:48 +03002910static inline void
Andreas Färber05390242012-02-25 03:37:53 +01002911restore_sigcontext(CPUMIPSState *regs, struct target_sigcontext *sc)
bellard106ec872006-06-27 21:08:10 +00002912{
Richard Henderson084d0492013-02-10 10:30:44 -08002913 int i;
bellard106ec872006-06-27 21:08:10 +00002914
Riku Voipio1d8b5122014-04-23 10:26:05 +03002915 __get_user(regs->CP0_EPC, &sc->sc_pc);
bellard106ec872006-06-27 21:08:10 +00002916
Riku Voipio1d8b5122014-04-23 10:26:05 +03002917 __get_user(regs->active_tc.HI[0], &sc->sc_mdhi);
2918 __get_user(regs->active_tc.LO[0], &sc->sc_mdlo);
bellard106ec872006-06-27 21:08:10 +00002919
Richard Henderson084d0492013-02-10 10:30:44 -08002920 for (i = 1; i < 32; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002921 __get_user(regs->active_tc.gpr[i], &sc->sc_regs[i]);
bellard106ec872006-06-27 21:08:10 +00002922 }
2923
Riku Voipio1d8b5122014-04-23 10:26:05 +03002924 __get_user(regs->active_tc.HI[1], &sc->sc_hi1);
2925 __get_user(regs->active_tc.HI[2], &sc->sc_hi2);
2926 __get_user(regs->active_tc.HI[3], &sc->sc_hi3);
2927 __get_user(regs->active_tc.LO[1], &sc->sc_lo1);
2928 __get_user(regs->active_tc.LO[2], &sc->sc_lo2);
2929 __get_user(regs->active_tc.LO[3], &sc->sc_lo3);
Richard Henderson084d0492013-02-10 10:30:44 -08002930 {
2931 uint32_t dsp;
Riku Voipio1d8b5122014-04-23 10:26:05 +03002932 __get_user(dsp, &sc->sc_dsp);
Richard Henderson084d0492013-02-10 10:30:44 -08002933 cpu_wrdsp(dsp, 0x3ff, regs);
2934 }
2935
2936 for (i = 0; i < 32; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002937 __get_user(regs->active_fpu.fpr[i].d, &sc->sc_fpregs[i]);
Richard Henderson084d0492013-02-10 10:30:44 -08002938 }
bellard106ec872006-06-27 21:08:10 +00002939}
Richard Hendersonff970902013-02-10 10:30:42 -08002940
bellard106ec872006-06-27 21:08:10 +00002941/*
2942 * Determine which stack to use..
2943 */
bellard579a97f2007-11-11 14:26:47 +00002944static inline abi_ulong
Andreas Färber05390242012-02-25 03:37:53 +01002945get_sigframe(struct target_sigaction *ka, CPUMIPSState *regs, size_t frame_size)
bellard106ec872006-06-27 21:08:10 +00002946{
2947 unsigned long sp;
2948
2949 /* Default to using normal stack */
thsb5dc7732008-06-27 10:02:35 +00002950 sp = regs->active_tc.gpr[29];
bellard106ec872006-06-27 21:08:10 +00002951
2952 /*
Stefan Weil93148aa2012-02-26 18:46:12 +01002953 * FPU emulator may have its own trampoline active just
bellard106ec872006-06-27 21:08:10 +00002954 * above the user stack, 16-bytes before the next lowest
2955 * 16 byte boundary. Try to avoid trashing it.
2956 */
2957 sp -= 32;
2958
bellard106ec872006-06-27 21:08:10 +00002959 /* This is the X/Open sanctioned signal stack switching. */
pbrook624f7972008-05-31 16:11:38 +00002960 if ((ka->sa_flags & TARGET_SA_ONSTACK) && (sas_ss_flags (sp) == 0)) {
thsa04e1342007-09-27 13:57:58 +00002961 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
2962 }
bellard106ec872006-06-27 21:08:10 +00002963
bellard579a97f2007-11-11 14:26:47 +00002964 return (sp - frame_size) & ~7;
bellard106ec872006-06-27 21:08:10 +00002965}
2966
Kwok Cheung Yeungea3164a2013-05-17 14:51:20 -07002967static void mips_set_hflags_isa_mode_from_pc(CPUMIPSState *env)
2968{
2969 if (env->insn_flags & (ASE_MIPS16 | ASE_MICROMIPS)) {
2970 env->hflags &= ~MIPS_HFLAG_M16;
2971 env->hflags |= (env->active_tc.PC & 1) << MIPS_HFLAG_M16_SHIFT;
2972 env->active_tc.PC &= ~(target_ulong) 1;
2973 }
2974}
2975
Richard Hendersonff970902013-02-10 10:30:42 -08002976# if defined(TARGET_ABI_MIPSO32)
bellard579a97f2007-11-11 14:26:47 +00002977/* compare linux/arch/mips/kernel/signal.c:setup_frame() */
pbrook624f7972008-05-31 16:11:38 +00002978static void setup_frame(int sig, struct target_sigaction * ka,
Andreas Färber05390242012-02-25 03:37:53 +01002979 target_sigset_t *set, CPUMIPSState *regs)
bellard106ec872006-06-27 21:08:10 +00002980{
2981 struct sigframe *frame;
bellard579a97f2007-11-11 14:26:47 +00002982 abi_ulong frame_addr;
bellard106ec872006-06-27 21:08:10 +00002983 int i;
2984
bellard579a97f2007-11-11 14:26:47 +00002985 frame_addr = get_sigframe(ka, regs, sizeof(*frame));
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01002986 trace_user_setup_frame(regs, frame_addr);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002987 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
2988 goto give_sigsegv;
2989 }
bellard106ec872006-06-27 21:08:10 +00002990
2991 install_sigtramp(frame->sf_code, TARGET_NR_sigreturn);
2992
Riku Voipio41ecc722014-04-23 11:01:00 +03002993 setup_sigcontext(regs, &frame->sf_sc);
bellard106ec872006-06-27 21:08:10 +00002994
2995 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
Riku Voipio0188fad2014-04-23 13:34:15 +03002996 __put_user(set->sig[i], &frame->sf_mask.sig[i]);
bellard106ec872006-06-27 21:08:10 +00002997 }
2998
2999 /*
3000 * Arguments to signal handler:
3001 *
3002 * a0 = signal number
3003 * a1 = 0 (should be cause)
3004 * a2 = pointer to struct sigcontext
3005 *
3006 * $25 and PC point to the signal handler, $29 points to the
3007 * struct sigframe.
3008 */
thsb5dc7732008-06-27 10:02:35 +00003009 regs->active_tc.gpr[ 4] = sig;
3010 regs->active_tc.gpr[ 5] = 0;
3011 regs->active_tc.gpr[ 6] = frame_addr + offsetof(struct sigframe, sf_sc);
3012 regs->active_tc.gpr[29] = frame_addr;
3013 regs->active_tc.gpr[31] = frame_addr + offsetof(struct sigframe, sf_code);
bellard106ec872006-06-27 21:08:10 +00003014 /* The original kernel code sets CP0_EPC to the handler
3015 * since it returns to userland using eret
3016 * we cannot do this here, and we must set PC directly */
thsb5dc7732008-06-27 10:02:35 +00003017 regs->active_tc.PC = regs->active_tc.gpr[25] = ka->_sa_handler;
Kwok Cheung Yeungea3164a2013-05-17 14:51:20 -07003018 mips_set_hflags_isa_mode_from_pc(regs);
bellard579a97f2007-11-11 14:26:47 +00003019 unlock_user_struct(frame, frame_addr, 1);
bellard106ec872006-06-27 21:08:10 +00003020 return;
3021
3022give_sigsegv:
3023 force_sig(TARGET_SIGSEGV/*, current*/);
bellard106ec872006-06-27 21:08:10 +00003024}
3025
Andreas Färber05390242012-02-25 03:37:53 +01003026long do_sigreturn(CPUMIPSState *regs)
bellard106ec872006-06-27 21:08:10 +00003027{
ths388bb212007-05-13 13:58:00 +00003028 struct sigframe *frame;
bellard579a97f2007-11-11 14:26:47 +00003029 abi_ulong frame_addr;
ths388bb212007-05-13 13:58:00 +00003030 sigset_t blocked;
Anthony Liguoric227f092009-10-01 16:12:16 -05003031 target_sigset_t target_set;
ths388bb212007-05-13 13:58:00 +00003032 int i;
bellard106ec872006-06-27 21:08:10 +00003033
thsb5dc7732008-06-27 10:02:35 +00003034 frame_addr = regs->active_tc.gpr[29];
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01003035 trace_user_do_sigreturn(regs, frame_addr);
bellard579a97f2007-11-11 14:26:47 +00003036 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003037 goto badframe;
bellard106ec872006-06-27 21:08:10 +00003038
ths388bb212007-05-13 13:58:00 +00003039 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
Riku Voipiof5f601a2014-04-23 13:00:17 +03003040 __get_user(target_set.sig[i], &frame->sf_mask.sig[i]);
ths388bb212007-05-13 13:58:00 +00003041 }
bellard106ec872006-06-27 21:08:10 +00003042
ths388bb212007-05-13 13:58:00 +00003043 target_to_host_sigset_internal(&blocked, &target_set);
Peter Maydell9eede5b2016-05-27 15:51:46 +01003044 set_sigmask(&blocked);
bellard106ec872006-06-27 21:08:10 +00003045
Riku Voipio016d2e12014-04-23 11:19:48 +03003046 restore_sigcontext(regs, &frame->sf_sc);
bellard106ec872006-06-27 21:08:10 +00003047
3048#if 0
ths388bb212007-05-13 13:58:00 +00003049 /*
3050 * Don't let your children do this ...
3051 */
3052 __asm__ __volatile__(
bellard106ec872006-06-27 21:08:10 +00003053 "move\t$29, %0\n\t"
3054 "j\tsyscall_exit"
3055 :/* no outputs */
3056 :"r" (&regs));
ths388bb212007-05-13 13:58:00 +00003057 /* Unreached */
bellard106ec872006-06-27 21:08:10 +00003058#endif
ths3b46e622007-09-17 08:09:54 +00003059
thsb5dc7732008-06-27 10:02:35 +00003060 regs->active_tc.PC = regs->CP0_EPC;
Kwok Cheung Yeungea3164a2013-05-17 14:51:20 -07003061 mips_set_hflags_isa_mode_from_pc(regs);
ths388bb212007-05-13 13:58:00 +00003062 /* I am not sure this is right, but it seems to work
bellard106ec872006-06-27 21:08:10 +00003063 * maybe a problem with nested signals ? */
3064 regs->CP0_EPC = 0;
pbrook0b1bcb02009-04-21 01:41:10 +00003065 return -TARGET_QEMU_ESIGRETURN;
bellard106ec872006-06-27 21:08:10 +00003066
3067badframe:
ths388bb212007-05-13 13:58:00 +00003068 force_sig(TARGET_SIGSEGV/*, current*/);
3069 return 0;
bellard106ec872006-06-27 21:08:10 +00003070}
Richard Hendersonff970902013-02-10 10:30:42 -08003071# endif /* O32 */
bellard106ec872006-06-27 21:08:10 +00003072
pbrook624f7972008-05-31 16:11:38 +00003073static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05003074 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01003075 target_sigset_t *set, CPUMIPSState *env)
bellard106ec872006-06-27 21:08:10 +00003076{
pbrook0b1bcb02009-04-21 01:41:10 +00003077 struct target_rt_sigframe *frame;
3078 abi_ulong frame_addr;
3079 int i;
3080
3081 frame_addr = get_sigframe(ka, env, sizeof(*frame));
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01003082 trace_user_setup_rt_frame(env, frame_addr);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003083 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
3084 goto give_sigsegv;
3085 }
pbrook0b1bcb02009-04-21 01:41:10 +00003086
3087 install_sigtramp(frame->rs_code, TARGET_NR_rt_sigreturn);
3088
Peter Maydellf6c7a052015-01-08 12:19:48 +00003089 tswap_siginfo(&frame->rs_info, info);
pbrook0b1bcb02009-04-21 01:41:10 +00003090
Aurelien Jarno60e99242010-03-29 02:12:51 +02003091 __put_user(0, &frame->rs_uc.tuc_flags);
3092 __put_user(0, &frame->rs_uc.tuc_link);
3093 __put_user(target_sigaltstack_used.ss_sp, &frame->rs_uc.tuc_stack.ss_sp);
3094 __put_user(target_sigaltstack_used.ss_size, &frame->rs_uc.tuc_stack.ss_size);
pbrook0b1bcb02009-04-21 01:41:10 +00003095 __put_user(sas_ss_flags(get_sp_from_cpustate(env)),
Aurelien Jarno60e99242010-03-29 02:12:51 +02003096 &frame->rs_uc.tuc_stack.ss_flags);
pbrook0b1bcb02009-04-21 01:41:10 +00003097
Aurelien Jarno60e99242010-03-29 02:12:51 +02003098 setup_sigcontext(env, &frame->rs_uc.tuc_mcontext);
pbrook0b1bcb02009-04-21 01:41:10 +00003099
3100 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
Aurelien Jarno60e99242010-03-29 02:12:51 +02003101 __put_user(set->sig[i], &frame->rs_uc.tuc_sigmask.sig[i]);
pbrook0b1bcb02009-04-21 01:41:10 +00003102 }
3103
3104 /*
3105 * Arguments to signal handler:
3106 *
3107 * a0 = signal number
Richard W.M. Jones02d2bd52012-07-05 03:32:44 +00003108 * a1 = pointer to siginfo_t
pbrook0b1bcb02009-04-21 01:41:10 +00003109 * a2 = pointer to struct ucontext
3110 *
3111 * $25 and PC point to the signal handler, $29 points to the
3112 * struct sigframe.
3113 */
3114 env->active_tc.gpr[ 4] = sig;
3115 env->active_tc.gpr[ 5] = frame_addr
3116 + offsetof(struct target_rt_sigframe, rs_info);
3117 env->active_tc.gpr[ 6] = frame_addr
3118 + offsetof(struct target_rt_sigframe, rs_uc);
3119 env->active_tc.gpr[29] = frame_addr;
3120 env->active_tc.gpr[31] = frame_addr
3121 + offsetof(struct target_rt_sigframe, rs_code);
3122 /* The original kernel code sets CP0_EPC to the handler
3123 * since it returns to userland using eret
3124 * we cannot do this here, and we must set PC directly */
3125 env->active_tc.PC = env->active_tc.gpr[25] = ka->_sa_handler;
Kwok Cheung Yeungea3164a2013-05-17 14:51:20 -07003126 mips_set_hflags_isa_mode_from_pc(env);
pbrook0b1bcb02009-04-21 01:41:10 +00003127 unlock_user_struct(frame, frame_addr, 1);
3128 return;
3129
3130give_sigsegv:
3131 unlock_user_struct(frame, frame_addr, 1);
3132 force_sig(TARGET_SIGSEGV/*, current*/);
bellard106ec872006-06-27 21:08:10 +00003133}
3134
Andreas Färber05390242012-02-25 03:37:53 +01003135long do_rt_sigreturn(CPUMIPSState *env)
bellard106ec872006-06-27 21:08:10 +00003136{
pbrook0b1bcb02009-04-21 01:41:10 +00003137 struct target_rt_sigframe *frame;
3138 abi_ulong frame_addr;
3139 sigset_t blocked;
3140
pbrook0b1bcb02009-04-21 01:41:10 +00003141 frame_addr = env->active_tc.gpr[29];
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01003142 trace_user_do_rt_sigreturn(env, frame_addr);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003143 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
3144 goto badframe;
3145 }
pbrook0b1bcb02009-04-21 01:41:10 +00003146
Aurelien Jarno60e99242010-03-29 02:12:51 +02003147 target_to_host_sigset(&blocked, &frame->rs_uc.tuc_sigmask);
Peter Maydell9eede5b2016-05-27 15:51:46 +01003148 set_sigmask(&blocked);
pbrook0b1bcb02009-04-21 01:41:10 +00003149
Riku Voipio016d2e12014-04-23 11:19:48 +03003150 restore_sigcontext(env, &frame->rs_uc.tuc_mcontext);
pbrook0b1bcb02009-04-21 01:41:10 +00003151
3152 if (do_sigaltstack(frame_addr +
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003153 offsetof(struct target_rt_sigframe, rs_uc.tuc_stack),
3154 0, get_sp_from_cpustate(env)) == -EFAULT)
pbrook0b1bcb02009-04-21 01:41:10 +00003155 goto badframe;
3156
3157 env->active_tc.PC = env->CP0_EPC;
Kwok Cheung Yeungea3164a2013-05-17 14:51:20 -07003158 mips_set_hflags_isa_mode_from_pc(env);
pbrook0b1bcb02009-04-21 01:41:10 +00003159 /* I am not sure this is right, but it seems to work
3160 * maybe a problem with nested signals ? */
3161 env->CP0_EPC = 0;
3162 return -TARGET_QEMU_ESIGRETURN;
3163
3164badframe:
3165 force_sig(TARGET_SIGSEGV/*, current*/);
3166 return 0;
bellard106ec872006-06-27 21:08:10 +00003167}
bellard6d5e2162004-09-30 22:04:13 +00003168
thsc3b5bc82007-12-02 06:31:25 +00003169#elif defined(TARGET_SH4)
3170
3171/*
3172 * code and data structures from linux kernel:
3173 * include/asm-sh/sigcontext.h
3174 * arch/sh/kernel/signal.c
3175 */
3176
3177struct target_sigcontext {
3178 target_ulong oldmask;
3179
3180 /* CPU registers */
3181 target_ulong sc_gregs[16];
3182 target_ulong sc_pc;
3183 target_ulong sc_pr;
3184 target_ulong sc_sr;
3185 target_ulong sc_gbr;
3186 target_ulong sc_mach;
3187 target_ulong sc_macl;
3188
3189 /* FPU registers */
3190 target_ulong sc_fpregs[16];
3191 target_ulong sc_xfpregs[16];
3192 unsigned int sc_fpscr;
3193 unsigned int sc_fpul;
3194 unsigned int sc_ownedfp;
3195};
3196
3197struct target_sigframe
3198{
3199 struct target_sigcontext sc;
3200 target_ulong extramask[TARGET_NSIG_WORDS-1];
3201 uint16_t retcode[3];
3202};
3203
3204
3205struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02003206 target_ulong tuc_flags;
3207 struct target_ucontext *tuc_link;
3208 target_stack_t tuc_stack;
3209 struct target_sigcontext tuc_mcontext;
3210 target_sigset_t tuc_sigmask; /* mask last for extensibility */
thsc3b5bc82007-12-02 06:31:25 +00003211};
3212
3213struct target_rt_sigframe
3214{
3215 struct target_siginfo info;
3216 struct target_ucontext uc;
3217 uint16_t retcode[3];
3218};
3219
3220
3221#define MOVW(n) (0x9300|((n)-2)) /* Move mem word at PC+n to R3 */
3222#define TRAP_NOARG 0xc310 /* Syscall w/no args (NR in R3) SH3/4 */
3223
pbrook624f7972008-05-31 16:11:38 +00003224static abi_ulong get_sigframe(struct target_sigaction *ka,
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003225 unsigned long sp, size_t frame_size)
thsc3b5bc82007-12-02 06:31:25 +00003226{
pbrook624f7972008-05-31 16:11:38 +00003227 if ((ka->sa_flags & TARGET_SA_ONSTACK) && (sas_ss_flags(sp) == 0)) {
thsc3b5bc82007-12-02 06:31:25 +00003228 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
3229 }
3230
3231 return (sp - frame_size) & -8ul;
3232}
3233
Riku Voipio41ecc722014-04-23 11:01:00 +03003234static void setup_sigcontext(struct target_sigcontext *sc,
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003235 CPUSH4State *regs, unsigned long mask)
thsc3b5bc82007-12-02 06:31:25 +00003236{
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003237 int i;
thsc3b5bc82007-12-02 06:31:25 +00003238
Riku Voipio1d8b5122014-04-23 10:26:05 +03003239#define COPY(x) __put_user(regs->x, &sc->sc_##x)
thsc3b5bc82007-12-02 06:31:25 +00003240 COPY(gregs[0]); COPY(gregs[1]);
3241 COPY(gregs[2]); COPY(gregs[3]);
3242 COPY(gregs[4]); COPY(gregs[5]);
3243 COPY(gregs[6]); COPY(gregs[7]);
3244 COPY(gregs[8]); COPY(gregs[9]);
3245 COPY(gregs[10]); COPY(gregs[11]);
3246 COPY(gregs[12]); COPY(gregs[13]);
3247 COPY(gregs[14]); COPY(gregs[15]);
3248 COPY(gbr); COPY(mach);
3249 COPY(macl); COPY(pr);
3250 COPY(sr); COPY(pc);
3251#undef COPY
3252
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003253 for (i=0; i<16; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03003254 __put_user(regs->fregs[i], &sc->sc_fpregs[i]);
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003255 }
Riku Voipio1d8b5122014-04-23 10:26:05 +03003256 __put_user(regs->fpscr, &sc->sc_fpscr);
3257 __put_user(regs->fpul, &sc->sc_fpul);
thsc3b5bc82007-12-02 06:31:25 +00003258
3259 /* non-iBCS2 extensions.. */
Riku Voipio1d8b5122014-04-23 10:26:05 +03003260 __put_user(mask, &sc->oldmask);
thsc3b5bc82007-12-02 06:31:25 +00003261}
3262
Timothy E Baldwinba412492016-05-12 18:47:35 +01003263static void restore_sigcontext(CPUSH4State *regs, struct target_sigcontext *sc)
thsc3b5bc82007-12-02 06:31:25 +00003264{
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003265 int i;
thsc3b5bc82007-12-02 06:31:25 +00003266
Riku Voipio1d8b5122014-04-23 10:26:05 +03003267#define COPY(x) __get_user(regs->x, &sc->sc_##x)
Timothy E Baldwinba412492016-05-12 18:47:35 +01003268 COPY(gregs[0]); COPY(gregs[1]);
thsc3b5bc82007-12-02 06:31:25 +00003269 COPY(gregs[2]); COPY(gregs[3]);
3270 COPY(gregs[4]); COPY(gregs[5]);
3271 COPY(gregs[6]); COPY(gregs[7]);
3272 COPY(gregs[8]); COPY(gregs[9]);
3273 COPY(gregs[10]); COPY(gregs[11]);
3274 COPY(gregs[12]); COPY(gregs[13]);
3275 COPY(gregs[14]); COPY(gregs[15]);
3276 COPY(gbr); COPY(mach);
3277 COPY(macl); COPY(pr);
3278 COPY(sr); COPY(pc);
3279#undef COPY
3280
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003281 for (i=0; i<16; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03003282 __get_user(regs->fregs[i], &sc->sc_fpregs[i]);
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003283 }
Riku Voipio1d8b5122014-04-23 10:26:05 +03003284 __get_user(regs->fpscr, &sc->sc_fpscr);
3285 __get_user(regs->fpul, &sc->sc_fpul);
thsc3b5bc82007-12-02 06:31:25 +00003286
3287 regs->tra = -1; /* disable syscall checks */
thsc3b5bc82007-12-02 06:31:25 +00003288}
3289
pbrook624f7972008-05-31 16:11:38 +00003290static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01003291 target_sigset_t *set, CPUSH4State *regs)
thsc3b5bc82007-12-02 06:31:25 +00003292{
3293 struct target_sigframe *frame;
3294 abi_ulong frame_addr;
3295 int i;
thsc3b5bc82007-12-02 06:31:25 +00003296
3297 frame_addr = get_sigframe(ka, regs->gregs[15], sizeof(*frame));
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01003298 trace_user_setup_frame(regs, frame_addr);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003299 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
3300 goto give_sigsegv;
3301 }
thsc3b5bc82007-12-02 06:31:25 +00003302
Riku Voipio41ecc722014-04-23 11:01:00 +03003303 setup_sigcontext(&frame->sc, regs, set->sig[0]);
thsc3b5bc82007-12-02 06:31:25 +00003304
3305 for (i = 0; i < TARGET_NSIG_WORDS - 1; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03003306 __put_user(set->sig[i + 1], &frame->extramask[i]);
thsc3b5bc82007-12-02 06:31:25 +00003307 }
3308
3309 /* Set up to return from userspace. If provided, use a stub
3310 already in userspace. */
pbrook624f7972008-05-31 16:11:38 +00003311 if (ka->sa_flags & TARGET_SA_RESTORER) {
3312 regs->pr = (unsigned long) ka->sa_restorer;
thsc3b5bc82007-12-02 06:31:25 +00003313 } else {
3314 /* Generate return code (system call to sigreturn) */
Laurent Vivier2a0fa682015-11-23 11:38:26 +01003315 abi_ulong retcode_addr = frame_addr +
3316 offsetof(struct target_sigframe, retcode);
Riku Voipio1d8b5122014-04-23 10:26:05 +03003317 __put_user(MOVW(2), &frame->retcode[0]);
3318 __put_user(TRAP_NOARG, &frame->retcode[1]);
3319 __put_user((TARGET_NR_sigreturn), &frame->retcode[2]);
Laurent Vivier2a0fa682015-11-23 11:38:26 +01003320 regs->pr = (unsigned long) retcode_addr;
thsc3b5bc82007-12-02 06:31:25 +00003321 }
3322
thsc3b5bc82007-12-02 06:31:25 +00003323 /* Set up registers for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003324 regs->gregs[15] = frame_addr;
Peter Maydellb6e2c932015-01-08 12:19:43 +00003325 regs->gregs[4] = sig; /* Arg for signal handler */
thsc3b5bc82007-12-02 06:31:25 +00003326 regs->gregs[5] = 0;
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003327 regs->gregs[6] = frame_addr += offsetof(typeof(*frame), sc);
pbrook624f7972008-05-31 16:11:38 +00003328 regs->pc = (unsigned long) ka->_sa_handler;
thsc3b5bc82007-12-02 06:31:25 +00003329
3330 unlock_user_struct(frame, frame_addr, 1);
3331 return;
3332
3333give_sigsegv:
3334 unlock_user_struct(frame, frame_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02003335 force_sig(TARGET_SIGSEGV);
thsc3b5bc82007-12-02 06:31:25 +00003336}
3337
pbrook624f7972008-05-31 16:11:38 +00003338static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05003339 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01003340 target_sigset_t *set, CPUSH4State *regs)
thsc3b5bc82007-12-02 06:31:25 +00003341{
3342 struct target_rt_sigframe *frame;
3343 abi_ulong frame_addr;
3344 int i;
thsc3b5bc82007-12-02 06:31:25 +00003345
3346 frame_addr = get_sigframe(ka, regs->gregs[15], sizeof(*frame));
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01003347 trace_user_setup_rt_frame(regs, frame_addr);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003348 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
3349 goto give_sigsegv;
3350 }
thsc3b5bc82007-12-02 06:31:25 +00003351
Peter Maydellf6c7a052015-01-08 12:19:48 +00003352 tswap_siginfo(&frame->info, info);
thsc3b5bc82007-12-02 06:31:25 +00003353
3354 /* Create the ucontext. */
Riku Voipio1d8b5122014-04-23 10:26:05 +03003355 __put_user(0, &frame->uc.tuc_flags);
3356 __put_user(0, (unsigned long *)&frame->uc.tuc_link);
3357 __put_user((unsigned long)target_sigaltstack_used.ss_sp,
3358 &frame->uc.tuc_stack.ss_sp);
3359 __put_user(sas_ss_flags(regs->gregs[15]),
3360 &frame->uc.tuc_stack.ss_flags);
3361 __put_user(target_sigaltstack_used.ss_size,
3362 &frame->uc.tuc_stack.ss_size);
3363 setup_sigcontext(&frame->uc.tuc_mcontext,
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003364 regs, set->sig[0]);
thsc3b5bc82007-12-02 06:31:25 +00003365 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03003366 __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
thsc3b5bc82007-12-02 06:31:25 +00003367 }
3368
3369 /* Set up to return from userspace. If provided, use a stub
3370 already in userspace. */
pbrook624f7972008-05-31 16:11:38 +00003371 if (ka->sa_flags & TARGET_SA_RESTORER) {
3372 regs->pr = (unsigned long) ka->sa_restorer;
thsc3b5bc82007-12-02 06:31:25 +00003373 } else {
3374 /* Generate return code (system call to sigreturn) */
Laurent Vivier2a0fa682015-11-23 11:38:26 +01003375 abi_ulong retcode_addr = frame_addr +
3376 offsetof(struct target_rt_sigframe, retcode);
Riku Voipio1d8b5122014-04-23 10:26:05 +03003377 __put_user(MOVW(2), &frame->retcode[0]);
3378 __put_user(TRAP_NOARG, &frame->retcode[1]);
3379 __put_user((TARGET_NR_rt_sigreturn), &frame->retcode[2]);
Laurent Vivier2a0fa682015-11-23 11:38:26 +01003380 regs->pr = (unsigned long) retcode_addr;
thsc3b5bc82007-12-02 06:31:25 +00003381 }
3382
thsc3b5bc82007-12-02 06:31:25 +00003383 /* Set up registers for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003384 regs->gregs[15] = frame_addr;
Peter Maydellb6e2c932015-01-08 12:19:43 +00003385 regs->gregs[4] = sig; /* Arg for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003386 regs->gregs[5] = frame_addr + offsetof(typeof(*frame), info);
3387 regs->gregs[6] = frame_addr + offsetof(typeof(*frame), uc);
pbrook624f7972008-05-31 16:11:38 +00003388 regs->pc = (unsigned long) ka->_sa_handler;
thsc3b5bc82007-12-02 06:31:25 +00003389
3390 unlock_user_struct(frame, frame_addr, 1);
3391 return;
3392
3393give_sigsegv:
3394 unlock_user_struct(frame, frame_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02003395 force_sig(TARGET_SIGSEGV);
thsc3b5bc82007-12-02 06:31:25 +00003396}
3397
Andreas Färber05390242012-02-25 03:37:53 +01003398long do_sigreturn(CPUSH4State *regs)
thsc3b5bc82007-12-02 06:31:25 +00003399{
3400 struct target_sigframe *frame;
3401 abi_ulong frame_addr;
3402 sigset_t blocked;
Anthony Liguoric227f092009-10-01 16:12:16 -05003403 target_sigset_t target_set;
thsc3b5bc82007-12-02 06:31:25 +00003404 int i;
3405 int err = 0;
3406
thsc3b5bc82007-12-02 06:31:25 +00003407 frame_addr = regs->gregs[15];
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01003408 trace_user_do_sigreturn(regs, frame_addr);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003409 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
3410 goto badframe;
3411 }
thsc3b5bc82007-12-02 06:31:25 +00003412
Riku Voipio1d8b5122014-04-23 10:26:05 +03003413 __get_user(target_set.sig[0], &frame->sc.oldmask);
thsc3b5bc82007-12-02 06:31:25 +00003414 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03003415 __get_user(target_set.sig[i], &frame->extramask[i - 1]);
thsc3b5bc82007-12-02 06:31:25 +00003416 }
3417
3418 if (err)
3419 goto badframe;
3420
3421 target_to_host_sigset_internal(&blocked, &target_set);
Peter Maydell9eede5b2016-05-27 15:51:46 +01003422 set_sigmask(&blocked);
thsc3b5bc82007-12-02 06:31:25 +00003423
Timothy E Baldwinba412492016-05-12 18:47:35 +01003424 restore_sigcontext(regs, &frame->sc);
thsc3b5bc82007-12-02 06:31:25 +00003425
3426 unlock_user_struct(frame, frame_addr, 0);
Timothy E Baldwinba412492016-05-12 18:47:35 +01003427 return -TARGET_QEMU_ESIGRETURN;
thsc3b5bc82007-12-02 06:31:25 +00003428
3429badframe:
3430 unlock_user_struct(frame, frame_addr, 0);
3431 force_sig(TARGET_SIGSEGV);
3432 return 0;
3433}
3434
Andreas Färber05390242012-02-25 03:37:53 +01003435long do_rt_sigreturn(CPUSH4State *regs)
thsc3b5bc82007-12-02 06:31:25 +00003436{
3437 struct target_rt_sigframe *frame;
3438 abi_ulong frame_addr;
3439 sigset_t blocked;
3440
thsc3b5bc82007-12-02 06:31:25 +00003441 frame_addr = regs->gregs[15];
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01003442 trace_user_do_rt_sigreturn(regs, frame_addr);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003443 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
3444 goto badframe;
3445 }
thsc3b5bc82007-12-02 06:31:25 +00003446
Aurelien Jarno60e99242010-03-29 02:12:51 +02003447 target_to_host_sigset(&blocked, &frame->uc.tuc_sigmask);
Peter Maydell9eede5b2016-05-27 15:51:46 +01003448 set_sigmask(&blocked);
thsc3b5bc82007-12-02 06:31:25 +00003449
Timothy E Baldwinba412492016-05-12 18:47:35 +01003450 restore_sigcontext(regs, &frame->uc.tuc_mcontext);
thsc3b5bc82007-12-02 06:31:25 +00003451
3452 if (do_sigaltstack(frame_addr +
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003453 offsetof(struct target_rt_sigframe, uc.tuc_stack),
3454 0, get_sp_from_cpustate(regs)) == -EFAULT) {
thsc3b5bc82007-12-02 06:31:25 +00003455 goto badframe;
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003456 }
thsc3b5bc82007-12-02 06:31:25 +00003457
3458 unlock_user_struct(frame, frame_addr, 0);
Timothy E Baldwinba412492016-05-12 18:47:35 +01003459 return -TARGET_QEMU_ESIGRETURN;
thsc3b5bc82007-12-02 06:31:25 +00003460
3461badframe:
3462 unlock_user_struct(frame, frame_addr, 0);
3463 force_sig(TARGET_SIGSEGV);
3464 return 0;
3465}
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003466#elif defined(TARGET_MICROBLAZE)
3467
3468struct target_sigcontext {
3469 struct target_pt_regs regs; /* needs to be first */
3470 uint32_t oldmask;
3471};
3472
Edgar E. Iglesiasb2178702010-07-23 09:30:37 +02003473struct target_stack_t {
3474 abi_ulong ss_sp;
3475 int ss_flags;
3476 unsigned int ss_size;
3477};
3478
3479struct target_ucontext {
Richard Hendersonf711df62010-11-22 14:57:52 -08003480 abi_ulong tuc_flags;
3481 abi_ulong tuc_link;
3482 struct target_stack_t tuc_stack;
3483 struct target_sigcontext tuc_mcontext;
3484 uint32_t tuc_extramask[TARGET_NSIG_WORDS - 1];
Edgar E. Iglesiasb2178702010-07-23 09:30:37 +02003485};
3486
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003487/* Signal frames. */
3488struct target_signal_frame {
Edgar E. Iglesiasb2178702010-07-23 09:30:37 +02003489 struct target_ucontext uc;
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003490 uint32_t extramask[TARGET_NSIG_WORDS - 1];
3491 uint32_t tramp[2];
3492};
3493
3494struct rt_signal_frame {
Richard W.M. Jones02d2bd52012-07-05 03:32:44 +00003495 siginfo_t info;
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003496 struct ucontext uc;
3497 uint32_t tramp[2];
3498};
3499
Andreas Färber05390242012-02-25 03:37:53 +01003500static void setup_sigcontext(struct target_sigcontext *sc, CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003501{
3502 __put_user(env->regs[0], &sc->regs.r0);
3503 __put_user(env->regs[1], &sc->regs.r1);
3504 __put_user(env->regs[2], &sc->regs.r2);
3505 __put_user(env->regs[3], &sc->regs.r3);
3506 __put_user(env->regs[4], &sc->regs.r4);
3507 __put_user(env->regs[5], &sc->regs.r5);
3508 __put_user(env->regs[6], &sc->regs.r6);
3509 __put_user(env->regs[7], &sc->regs.r7);
3510 __put_user(env->regs[8], &sc->regs.r8);
3511 __put_user(env->regs[9], &sc->regs.r9);
3512 __put_user(env->regs[10], &sc->regs.r10);
3513 __put_user(env->regs[11], &sc->regs.r11);
3514 __put_user(env->regs[12], &sc->regs.r12);
3515 __put_user(env->regs[13], &sc->regs.r13);
3516 __put_user(env->regs[14], &sc->regs.r14);
3517 __put_user(env->regs[15], &sc->regs.r15);
3518 __put_user(env->regs[16], &sc->regs.r16);
3519 __put_user(env->regs[17], &sc->regs.r17);
3520 __put_user(env->regs[18], &sc->regs.r18);
3521 __put_user(env->regs[19], &sc->regs.r19);
3522 __put_user(env->regs[20], &sc->regs.r20);
3523 __put_user(env->regs[21], &sc->regs.r21);
3524 __put_user(env->regs[22], &sc->regs.r22);
3525 __put_user(env->regs[23], &sc->regs.r23);
3526 __put_user(env->regs[24], &sc->regs.r24);
3527 __put_user(env->regs[25], &sc->regs.r25);
3528 __put_user(env->regs[26], &sc->regs.r26);
3529 __put_user(env->regs[27], &sc->regs.r27);
3530 __put_user(env->regs[28], &sc->regs.r28);
3531 __put_user(env->regs[29], &sc->regs.r29);
3532 __put_user(env->regs[30], &sc->regs.r30);
3533 __put_user(env->regs[31], &sc->regs.r31);
3534 __put_user(env->sregs[SR_PC], &sc->regs.pc);
3535}
3536
Andreas Färber05390242012-02-25 03:37:53 +01003537static void restore_sigcontext(struct target_sigcontext *sc, CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003538{
3539 __get_user(env->regs[0], &sc->regs.r0);
3540 __get_user(env->regs[1], &sc->regs.r1);
3541 __get_user(env->regs[2], &sc->regs.r2);
3542 __get_user(env->regs[3], &sc->regs.r3);
3543 __get_user(env->regs[4], &sc->regs.r4);
3544 __get_user(env->regs[5], &sc->regs.r5);
3545 __get_user(env->regs[6], &sc->regs.r6);
3546 __get_user(env->regs[7], &sc->regs.r7);
3547 __get_user(env->regs[8], &sc->regs.r8);
3548 __get_user(env->regs[9], &sc->regs.r9);
3549 __get_user(env->regs[10], &sc->regs.r10);
3550 __get_user(env->regs[11], &sc->regs.r11);
3551 __get_user(env->regs[12], &sc->regs.r12);
3552 __get_user(env->regs[13], &sc->regs.r13);
3553 __get_user(env->regs[14], &sc->regs.r14);
3554 __get_user(env->regs[15], &sc->regs.r15);
3555 __get_user(env->regs[16], &sc->regs.r16);
3556 __get_user(env->regs[17], &sc->regs.r17);
3557 __get_user(env->regs[18], &sc->regs.r18);
3558 __get_user(env->regs[19], &sc->regs.r19);
3559 __get_user(env->regs[20], &sc->regs.r20);
3560 __get_user(env->regs[21], &sc->regs.r21);
3561 __get_user(env->regs[22], &sc->regs.r22);
3562 __get_user(env->regs[23], &sc->regs.r23);
3563 __get_user(env->regs[24], &sc->regs.r24);
3564 __get_user(env->regs[25], &sc->regs.r25);
3565 __get_user(env->regs[26], &sc->regs.r26);
3566 __get_user(env->regs[27], &sc->regs.r27);
3567 __get_user(env->regs[28], &sc->regs.r28);
3568 __get_user(env->regs[29], &sc->regs.r29);
3569 __get_user(env->regs[30], &sc->regs.r30);
3570 __get_user(env->regs[31], &sc->regs.r31);
3571 __get_user(env->sregs[SR_PC], &sc->regs.pc);
3572}
3573
3574static abi_ulong get_sigframe(struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01003575 CPUMBState *env, int frame_size)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003576{
3577 abi_ulong sp = env->regs[1];
3578
Riku Voipiob545f632014-07-15 17:01:55 +03003579 if ((ka->sa_flags & TARGET_SA_ONSTACK) != 0 && !on_sig_stack(sp)) {
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003580 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
Riku Voipiob545f632014-07-15 17:01:55 +03003581 }
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003582
3583 return ((sp - frame_size) & -8UL);
3584}
3585
3586static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01003587 target_sigset_t *set, CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003588{
3589 struct target_signal_frame *frame;
3590 abi_ulong frame_addr;
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003591 int i;
3592
3593 frame_addr = get_sigframe(ka, env, sizeof *frame);
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01003594 trace_user_setup_frame(env, frame_addr);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003595 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
3596 goto badframe;
3597
3598 /* Save the mask. */
Riku Voipio1d8b5122014-04-23 10:26:05 +03003599 __put_user(set->sig[0], &frame->uc.tuc_mcontext.oldmask);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003600
3601 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
Riku Voipio0188fad2014-04-23 13:34:15 +03003602 __put_user(set->sig[i], &frame->extramask[i - 1]);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003603 }
3604
Richard Hendersonf711df62010-11-22 14:57:52 -08003605 setup_sigcontext(&frame->uc.tuc_mcontext, env);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003606
3607 /* Set up to return from userspace. If provided, use a stub
3608 already in userspace. */
3609 /* minus 8 is offset to cater for "rtsd r15,8" offset */
3610 if (ka->sa_flags & TARGET_SA_RESTORER) {
3611 env->regs[15] = ((unsigned long)ka->sa_restorer)-8;
3612 } else {
3613 uint32_t t;
3614 /* Note, these encodings are _big endian_! */
3615 /* addi r12, r0, __NR_sigreturn */
3616 t = 0x31800000UL | TARGET_NR_sigreturn;
Riku Voipio1d8b5122014-04-23 10:26:05 +03003617 __put_user(t, frame->tramp + 0);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003618 /* brki r14, 0x8 */
3619 t = 0xb9cc0008UL;
Riku Voipio1d8b5122014-04-23 10:26:05 +03003620 __put_user(t, frame->tramp + 1);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003621
3622 /* Return from sighandler will jump to the tramp.
3623 Negative 8 offset because return is rtsd r15, 8 */
Chen Gang166c97e2016-03-29 22:13:45 +08003624 env->regs[15] = frame_addr + offsetof(struct target_signal_frame, tramp)
3625 - 8;
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003626 }
3627
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003628 /* Set up registers for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003629 env->regs[1] = frame_addr;
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003630 /* Signal handler args: */
3631 env->regs[5] = sig; /* Arg 0: signum */
Edgar E. Iglesias187b4e02010-07-15 15:32:51 +02003632 env->regs[6] = 0;
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003633 /* arg 1: sigcontext */
3634 env->regs[7] = frame_addr += offsetof(typeof(*frame), uc);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003635
3636 /* Offset of 4 to handle microblaze rtid r14, 0 */
3637 env->sregs[SR_PC] = (unsigned long)ka->_sa_handler;
3638
3639 unlock_user_struct(frame, frame_addr, 1);
3640 return;
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003641badframe:
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003642 force_sig(TARGET_SIGSEGV);
3643}
3644
3645static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05003646 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01003647 target_sigset_t *set, CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003648{
3649 fprintf(stderr, "Microblaze setup_rt_frame: not implemented\n");
3650}
3651
Andreas Färber05390242012-02-25 03:37:53 +01003652long do_sigreturn(CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003653{
3654 struct target_signal_frame *frame;
3655 abi_ulong frame_addr;
Anthony Liguoric227f092009-10-01 16:12:16 -05003656 target_sigset_t target_set;
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003657 sigset_t set;
3658 int i;
3659
3660 frame_addr = env->regs[R_SP];
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01003661 trace_user_do_sigreturn(env, frame_addr);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003662 /* Make sure the guest isn't playing games. */
3663 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 1))
3664 goto badframe;
3665
3666 /* Restore blocked signals */
Riku Voipiof5f601a2014-04-23 13:00:17 +03003667 __get_user(target_set.sig[0], &frame->uc.tuc_mcontext.oldmask);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003668 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003669 __get_user(target_set.sig[i], &frame->extramask[i - 1]);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003670 }
3671 target_to_host_sigset_internal(&set, &target_set);
Peter Maydell9eede5b2016-05-27 15:51:46 +01003672 set_sigmask(&set);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003673
Richard Hendersonf711df62010-11-22 14:57:52 -08003674 restore_sigcontext(&frame->uc.tuc_mcontext, env);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003675 /* We got here through a sigreturn syscall, our path back is via an
3676 rtb insn so setup r14 for that. */
3677 env->regs[14] = env->sregs[SR_PC];
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003678
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003679 unlock_user_struct(frame, frame_addr, 0);
Timothy E Baldwin4134ecf2016-05-12 18:47:44 +01003680 return -TARGET_QEMU_ESIGRETURN;
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003681badframe:
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003682 force_sig(TARGET_SIGSEGV);
3683}
3684
Andreas Färber05390242012-02-25 03:37:53 +01003685long do_rt_sigreturn(CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003686{
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01003687 trace_user_do_rt_sigreturn(env, 0);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003688 fprintf(stderr, "Microblaze do_rt_sigreturn: not implemented\n");
3689 return -TARGET_ENOSYS;
3690}
3691
edgar_iglb6d3abd2008-02-28 11:29:27 +00003692#elif defined(TARGET_CRIS)
3693
3694struct target_sigcontext {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003695 struct target_pt_regs regs; /* needs to be first */
3696 uint32_t oldmask;
3697 uint32_t usp; /* usp before stacking this gunk on it */
edgar_iglb6d3abd2008-02-28 11:29:27 +00003698};
3699
3700/* Signal frames. */
3701struct target_signal_frame {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003702 struct target_sigcontext sc;
3703 uint32_t extramask[TARGET_NSIG_WORDS - 1];
3704 uint16_t retcode[4]; /* Trampoline code. */
edgar_iglb6d3abd2008-02-28 11:29:27 +00003705};
3706
3707struct rt_signal_frame {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003708 siginfo_t *pinfo;
3709 void *puc;
3710 siginfo_t info;
3711 struct ucontext uc;
3712 uint16_t retcode[4]; /* Trampoline code. */
edgar_iglb6d3abd2008-02-28 11:29:27 +00003713};
3714
Andreas Färber05390242012-02-25 03:37:53 +01003715static void setup_sigcontext(struct target_sigcontext *sc, CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003716{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003717 __put_user(env->regs[0], &sc->regs.r0);
3718 __put_user(env->regs[1], &sc->regs.r1);
3719 __put_user(env->regs[2], &sc->regs.r2);
3720 __put_user(env->regs[3], &sc->regs.r3);
3721 __put_user(env->regs[4], &sc->regs.r4);
3722 __put_user(env->regs[5], &sc->regs.r5);
3723 __put_user(env->regs[6], &sc->regs.r6);
3724 __put_user(env->regs[7], &sc->regs.r7);
3725 __put_user(env->regs[8], &sc->regs.r8);
3726 __put_user(env->regs[9], &sc->regs.r9);
3727 __put_user(env->regs[10], &sc->regs.r10);
3728 __put_user(env->regs[11], &sc->regs.r11);
3729 __put_user(env->regs[12], &sc->regs.r12);
3730 __put_user(env->regs[13], &sc->regs.r13);
3731 __put_user(env->regs[14], &sc->usp);
3732 __put_user(env->regs[15], &sc->regs.acr);
3733 __put_user(env->pregs[PR_MOF], &sc->regs.mof);
3734 __put_user(env->pregs[PR_SRP], &sc->regs.srp);
3735 __put_user(env->pc, &sc->regs.erp);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003736}
edgar_igl9664d922008-03-03 22:23:53 +00003737
Andreas Färber05390242012-02-25 03:37:53 +01003738static void restore_sigcontext(struct target_sigcontext *sc, CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003739{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003740 __get_user(env->regs[0], &sc->regs.r0);
3741 __get_user(env->regs[1], &sc->regs.r1);
3742 __get_user(env->regs[2], &sc->regs.r2);
3743 __get_user(env->regs[3], &sc->regs.r3);
3744 __get_user(env->regs[4], &sc->regs.r4);
3745 __get_user(env->regs[5], &sc->regs.r5);
3746 __get_user(env->regs[6], &sc->regs.r6);
3747 __get_user(env->regs[7], &sc->regs.r7);
3748 __get_user(env->regs[8], &sc->regs.r8);
3749 __get_user(env->regs[9], &sc->regs.r9);
3750 __get_user(env->regs[10], &sc->regs.r10);
3751 __get_user(env->regs[11], &sc->regs.r11);
3752 __get_user(env->regs[12], &sc->regs.r12);
3753 __get_user(env->regs[13], &sc->regs.r13);
3754 __get_user(env->regs[14], &sc->usp);
3755 __get_user(env->regs[15], &sc->regs.acr);
3756 __get_user(env->pregs[PR_MOF], &sc->regs.mof);
3757 __get_user(env->pregs[PR_SRP], &sc->regs.srp);
3758 __get_user(env->pc, &sc->regs.erp);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003759}
3760
Andreas Färber05390242012-02-25 03:37:53 +01003761static abi_ulong get_sigframe(CPUCRISState *env, int framesize)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003762{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003763 abi_ulong sp;
3764 /* Align the stack downwards to 4. */
3765 sp = (env->regs[R_SP] & ~3);
3766 return sp - framesize;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003767}
3768
pbrook624f7972008-05-31 16:11:38 +00003769static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01003770 target_sigset_t *set, CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003771{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003772 struct target_signal_frame *frame;
3773 abi_ulong frame_addr;
3774 int i;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003775
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003776 frame_addr = get_sigframe(env, sizeof *frame);
3777 trace_user_setup_frame(env, frame_addr);
3778 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
3779 goto badframe;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003780
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003781 /*
3782 * The CRIS signal return trampoline. A real linux/CRIS kernel doesn't
3783 * use this trampoline anymore but it sets it up for GDB.
3784 * In QEMU, using the trampoline simplifies things a bit so we use it.
3785 *
3786 * This is movu.w __NR_sigreturn, r9; break 13;
3787 */
Riku Voipio1d8b5122014-04-23 10:26:05 +03003788 __put_user(0x9c5f, frame->retcode+0);
3789 __put_user(TARGET_NR_sigreturn,
3790 frame->retcode + 1);
3791 __put_user(0xe93d, frame->retcode + 2);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003792
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003793 /* Save the mask. */
Riku Voipio1d8b5122014-04-23 10:26:05 +03003794 __put_user(set->sig[0], &frame->sc.oldmask);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003795
Riku Voipio0188fad2014-04-23 13:34:15 +03003796 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
3797 __put_user(set->sig[i], &frame->extramask[i - 1]);
3798 }
edgar_iglb6d3abd2008-02-28 11:29:27 +00003799
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003800 setup_sigcontext(&frame->sc, env);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003801
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003802 /* Move the stack and setup the arguments for the handler. */
3803 env->regs[R_SP] = frame_addr;
3804 env->regs[10] = sig;
3805 env->pc = (unsigned long) ka->_sa_handler;
3806 /* Link SRP so the guest returns through the trampoline. */
3807 env->pregs[PR_SRP] = frame_addr + offsetof(typeof(*frame), retcode);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003808
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003809 unlock_user_struct(frame, frame_addr, 1);
3810 return;
3811badframe:
3812 force_sig(TARGET_SIGSEGV);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003813}
3814
pbrook624f7972008-05-31 16:11:38 +00003815static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05003816 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01003817 target_sigset_t *set, CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003818{
3819 fprintf(stderr, "CRIS setup_rt_frame: not implemented\n");
3820}
3821
Andreas Färber05390242012-02-25 03:37:53 +01003822long do_sigreturn(CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003823{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003824 struct target_signal_frame *frame;
3825 abi_ulong frame_addr;
3826 target_sigset_t target_set;
3827 sigset_t set;
3828 int i;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003829
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003830 frame_addr = env->regs[R_SP];
3831 trace_user_do_sigreturn(env, frame_addr);
3832 /* Make sure the guest isn't playing games. */
3833 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 1)) {
3834 goto badframe;
3835 }
edgar_iglb6d3abd2008-02-28 11:29:27 +00003836
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003837 /* Restore blocked signals */
Riku Voipiof5f601a2014-04-23 13:00:17 +03003838 __get_user(target_set.sig[0], &frame->sc.oldmask);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003839 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
Riku Voipiof5f601a2014-04-23 13:00:17 +03003840 __get_user(target_set.sig[i], &frame->extramask[i - 1]);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003841 }
3842 target_to_host_sigset_internal(&set, &target_set);
Peter Maydell9eede5b2016-05-27 15:51:46 +01003843 set_sigmask(&set);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003844
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003845 restore_sigcontext(&frame->sc, env);
3846 unlock_user_struct(frame, frame_addr, 0);
Timothy E Baldwin62050862016-05-12 18:47:41 +01003847 return -TARGET_QEMU_ESIGRETURN;
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003848badframe:
3849 force_sig(TARGET_SIGSEGV);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003850}
3851
Andreas Färber05390242012-02-25 03:37:53 +01003852long do_rt_sigreturn(CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003853{
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01003854 trace_user_do_rt_sigreturn(env, 0);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003855 fprintf(stderr, "CRIS do_rt_sigreturn: not implemented\n");
3856 return -TARGET_ENOSYS;
3857}
thsc3b5bc82007-12-02 06:31:25 +00003858
Jia Liud9627832012-07-20 15:50:52 +08003859#elif defined(TARGET_OPENRISC)
3860
3861struct target_sigcontext {
3862 struct target_pt_regs regs;
3863 abi_ulong oldmask;
3864 abi_ulong usp;
3865};
3866
3867struct target_ucontext {
3868 abi_ulong tuc_flags;
3869 abi_ulong tuc_link;
3870 target_stack_t tuc_stack;
3871 struct target_sigcontext tuc_mcontext;
3872 target_sigset_t tuc_sigmask; /* mask last for extensibility */
3873};
3874
3875struct target_rt_sigframe {
3876 abi_ulong pinfo;
3877 uint64_t puc;
3878 struct target_siginfo info;
3879 struct target_sigcontext sc;
3880 struct target_ucontext uc;
3881 unsigned char retcode[16]; /* trampoline code */
3882};
3883
3884/* This is the asm-generic/ucontext.h version */
3885#if 0
3886static int restore_sigcontext(CPUOpenRISCState *regs,
3887 struct target_sigcontext *sc)
3888{
3889 unsigned int err = 0;
3890 unsigned long old_usp;
3891
3892 /* Alwys make any pending restarted system call return -EINTR */
3893 current_thread_info()->restart_block.fn = do_no_restart_syscall;
3894
3895 /* restore the regs from &sc->regs (same as sc, since regs is first)
3896 * (sc is already checked for VERIFY_READ since the sigframe was
3897 * checked in sys_sigreturn previously)
3898 */
3899
3900 if (copy_from_user(regs, &sc, sizeof(struct target_pt_regs))) {
3901 goto badframe;
3902 }
3903
3904 /* make sure the U-flag is set so user-mode cannot fool us */
3905
3906 regs->sr &= ~SR_SM;
3907
3908 /* restore the old USP as it was before we stacked the sc etc.
3909 * (we cannot just pop the sigcontext since we aligned the sp and
3910 * stuff after pushing it)
3911 */
3912
Riku Voipio1d8b5122014-04-23 10:26:05 +03003913 __get_user(old_usp, &sc->usp);
Jia Liud9627832012-07-20 15:50:52 +08003914 phx_signal("old_usp 0x%lx", old_usp);
3915
3916 __PHX__ REALLY /* ??? */
3917 wrusp(old_usp);
3918 regs->gpr[1] = old_usp;
3919
3920 /* TODO: the other ports use regs->orig_XX to disable syscall checks
3921 * after this completes, but we don't use that mechanism. maybe we can
3922 * use it now ?
3923 */
3924
3925 return err;
3926
3927badframe:
3928 return 1;
3929}
3930#endif
3931
3932/* Set up a signal frame. */
3933
Riku Voipio41ecc722014-04-23 11:01:00 +03003934static void setup_sigcontext(struct target_sigcontext *sc,
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003935 CPUOpenRISCState *regs,
3936 unsigned long mask)
Jia Liud9627832012-07-20 15:50:52 +08003937{
Jia Liud9627832012-07-20 15:50:52 +08003938 unsigned long usp = regs->gpr[1];
3939
3940 /* copy the regs. they are first in sc so we can use sc directly */
3941
Riku Voipio1d8b5122014-04-23 10:26:05 +03003942 /*copy_to_user(&sc, regs, sizeof(struct target_pt_regs));*/
Jia Liud9627832012-07-20 15:50:52 +08003943
3944 /* Set the frametype to CRIS_FRAME_NORMAL for the execution of
3945 the signal handler. The frametype will be restored to its previous
3946 value in restore_sigcontext. */
3947 /*regs->frametype = CRIS_FRAME_NORMAL;*/
3948
3949 /* then some other stuff */
Riku Voipio1d8b5122014-04-23 10:26:05 +03003950 __put_user(mask, &sc->oldmask);
Riku Voipio41ecc722014-04-23 11:01:00 +03003951 __put_user(usp, &sc->usp);
Jia Liud9627832012-07-20 15:50:52 +08003952}
3953
3954static inline unsigned long align_sigframe(unsigned long sp)
3955{
3956 unsigned long i;
3957 i = sp & ~3UL;
3958 return i;
3959}
3960
3961static inline abi_ulong get_sigframe(struct target_sigaction *ka,
3962 CPUOpenRISCState *regs,
3963 size_t frame_size)
3964{
3965 unsigned long sp = regs->gpr[1];
3966 int onsigstack = on_sig_stack(sp);
3967
3968 /* redzone */
3969 /* This is the X/Open sanctioned signal stack switching. */
Riku Voipiob545f632014-07-15 17:01:55 +03003970 if ((ka->sa_flags & TARGET_SA_ONSTACK) != 0 && !onsigstack) {
Jia Liud9627832012-07-20 15:50:52 +08003971 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
3972 }
3973
3974 sp = align_sigframe(sp - frame_size);
3975
3976 /*
3977 * If we are on the alternate signal stack and would overflow it, don't.
3978 * Return an always-bogus address instead so we will die with SIGSEGV.
3979 */
3980
3981 if (onsigstack && !likely(on_sig_stack(sp))) {
3982 return -1L;
3983 }
3984
3985 return sp;
3986}
3987
Jia Liud9627832012-07-20 15:50:52 +08003988static void setup_rt_frame(int sig, struct target_sigaction *ka,
3989 target_siginfo_t *info,
3990 target_sigset_t *set, CPUOpenRISCState *env)
3991{
3992 int err = 0;
3993 abi_ulong frame_addr;
3994 unsigned long return_ip;
3995 struct target_rt_sigframe *frame;
3996 abi_ulong info_addr, uc_addr;
3997
Jia Liud9627832012-07-20 15:50:52 +08003998 frame_addr = get_sigframe(ka, env, sizeof(*frame));
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01003999 trace_user_setup_rt_frame(env, frame_addr);
Jia Liud9627832012-07-20 15:50:52 +08004000 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
4001 goto give_sigsegv;
4002 }
4003
4004 info_addr = frame_addr + offsetof(struct target_rt_sigframe, info);
Riku Voipio1d8b5122014-04-23 10:26:05 +03004005 __put_user(info_addr, &frame->pinfo);
Jia Liud9627832012-07-20 15:50:52 +08004006 uc_addr = frame_addr + offsetof(struct target_rt_sigframe, uc);
Riku Voipio1d8b5122014-04-23 10:26:05 +03004007 __put_user(uc_addr, &frame->puc);
Jia Liud9627832012-07-20 15:50:52 +08004008
4009 if (ka->sa_flags & SA_SIGINFO) {
Peter Maydellf6c7a052015-01-08 12:19:48 +00004010 tswap_siginfo(&frame->info, info);
Jia Liud9627832012-07-20 15:50:52 +08004011 }
4012
4013 /*err |= __clear_user(&frame->uc, offsetof(struct ucontext, uc_mcontext));*/
Riku Voipio1d8b5122014-04-23 10:26:05 +03004014 __put_user(0, &frame->uc.tuc_flags);
4015 __put_user(0, &frame->uc.tuc_link);
4016 __put_user(target_sigaltstack_used.ss_sp,
4017 &frame->uc.tuc_stack.ss_sp);
4018 __put_user(sas_ss_flags(env->gpr[1]), &frame->uc.tuc_stack.ss_flags);
4019 __put_user(target_sigaltstack_used.ss_size,
4020 &frame->uc.tuc_stack.ss_size);
Riku Voipio41ecc722014-04-23 11:01:00 +03004021 setup_sigcontext(&frame->sc, env, set->sig[0]);
Jia Liud9627832012-07-20 15:50:52 +08004022
4023 /*err |= copy_to_user(frame->uc.tuc_sigmask, set, sizeof(*set));*/
4024
Jia Liud9627832012-07-20 15:50:52 +08004025 /* trampoline - the desired return ip is the retcode itself */
4026 return_ip = (unsigned long)&frame->retcode;
4027 /* This is l.ori r11,r0,__NR_sigreturn, l.sys 1 */
Riku Voipio1d8b5122014-04-23 10:26:05 +03004028 __put_user(0xa960, (short *)(frame->retcode + 0));
4029 __put_user(TARGET_NR_rt_sigreturn, (short *)(frame->retcode + 2));
4030 __put_user(0x20000001, (unsigned long *)(frame->retcode + 4));
4031 __put_user(0x15000000, (unsigned long *)(frame->retcode + 8));
Jia Liud9627832012-07-20 15:50:52 +08004032
4033 if (err) {
4034 goto give_sigsegv;
4035 }
4036
4037 /* TODO what is the current->exec_domain stuff and invmap ? */
4038
4039 /* Set up registers for signal handler */
4040 env->pc = (unsigned long)ka->_sa_handler; /* what we enter NOW */
4041 env->gpr[9] = (unsigned long)return_ip; /* what we enter LATER */
4042 env->gpr[3] = (unsigned long)sig; /* arg 1: signo */
4043 env->gpr[4] = (unsigned long)&frame->info; /* arg 2: (siginfo_t*) */
4044 env->gpr[5] = (unsigned long)&frame->uc; /* arg 3: ucontext */
4045
4046 /* actually move the usp to reflect the stacked frame */
4047 env->gpr[1] = (unsigned long)frame;
4048
4049 return;
4050
4051give_sigsegv:
4052 unlock_user_struct(frame, frame_addr, 1);
4053 if (sig == TARGET_SIGSEGV) {
4054 ka->_sa_handler = TARGET_SIG_DFL;
4055 }
4056 force_sig(TARGET_SIGSEGV);
4057}
4058
4059long do_sigreturn(CPUOpenRISCState *env)
4060{
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01004061 trace_user_do_sigreturn(env, 0);
4062 fprintf(stderr, "do_sigreturn: not implemented\n");
Jia Liud9627832012-07-20 15:50:52 +08004063 return -TARGET_ENOSYS;
4064}
4065
4066long do_rt_sigreturn(CPUOpenRISCState *env)
4067{
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01004068 trace_user_do_rt_sigreturn(env, 0);
4069 fprintf(stderr, "do_rt_sigreturn: not implemented\n");
Jia Liud9627832012-07-20 15:50:52 +08004070 return -TARGET_ENOSYS;
4071}
4072/* TARGET_OPENRISC */
4073
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004074#elif defined(TARGET_S390X)
4075
4076#define __NUM_GPRS 16
4077#define __NUM_FPRS 16
4078#define __NUM_ACRS 16
4079
4080#define S390_SYSCALL_SIZE 2
4081#define __SIGNAL_FRAMESIZE 160 /* FIXME: 31-bit mode -> 96 */
4082
4083#define _SIGCONTEXT_NSIG 64
4084#define _SIGCONTEXT_NSIG_BPW 64 /* FIXME: 31-bit mode -> 32 */
4085#define _SIGCONTEXT_NSIG_WORDS (_SIGCONTEXT_NSIG / _SIGCONTEXT_NSIG_BPW)
4086#define _SIGMASK_COPY_SIZE (sizeof(unsigned long)*_SIGCONTEXT_NSIG_WORDS)
4087#define PSW_ADDR_AMODE 0x0000000000000000UL /* 0x80000000UL for 31-bit */
4088#define S390_SYSCALL_OPCODE ((uint16_t)0x0a00)
4089
4090typedef struct {
4091 target_psw_t psw;
4092 target_ulong gprs[__NUM_GPRS];
4093 unsigned int acrs[__NUM_ACRS];
4094} target_s390_regs_common;
4095
4096typedef struct {
4097 unsigned int fpc;
4098 double fprs[__NUM_FPRS];
4099} target_s390_fp_regs;
4100
4101typedef struct {
4102 target_s390_regs_common regs;
4103 target_s390_fp_regs fpregs;
4104} target_sigregs;
4105
4106struct target_sigcontext {
4107 target_ulong oldmask[_SIGCONTEXT_NSIG_WORDS];
4108 target_sigregs *sregs;
4109};
4110
4111typedef struct {
4112 uint8_t callee_used_stack[__SIGNAL_FRAMESIZE];
4113 struct target_sigcontext sc;
4114 target_sigregs sregs;
4115 int signo;
4116 uint8_t retcode[S390_SYSCALL_SIZE];
4117} sigframe;
4118
4119struct target_ucontext {
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004120 target_ulong tuc_flags;
4121 struct target_ucontext *tuc_link;
4122 target_stack_t tuc_stack;
4123 target_sigregs tuc_mcontext;
4124 target_sigset_t tuc_sigmask; /* mask last for extensibility */
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004125};
4126
4127typedef struct {
4128 uint8_t callee_used_stack[__SIGNAL_FRAMESIZE];
4129 uint8_t retcode[S390_SYSCALL_SIZE];
4130 struct target_siginfo info;
4131 struct target_ucontext uc;
4132} rt_sigframe;
4133
4134static inline abi_ulong
Andreas Färber05390242012-02-25 03:37:53 +01004135get_sigframe(struct target_sigaction *ka, CPUS390XState *env, size_t frame_size)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004136{
4137 abi_ulong sp;
4138
4139 /* Default to using normal stack */
4140 sp = env->regs[15];
4141
4142 /* This is the X/Open sanctioned signal stack switching. */
4143 if (ka->sa_flags & TARGET_SA_ONSTACK) {
4144 if (!sas_ss_flags(sp)) {
4145 sp = target_sigaltstack_used.ss_sp +
4146 target_sigaltstack_used.ss_size;
4147 }
4148 }
4149
4150 /* This is the legacy signal stack switching. */
4151 else if (/* FIXME !user_mode(regs) */ 0 &&
4152 !(ka->sa_flags & TARGET_SA_RESTORER) &&
4153 ka->sa_restorer) {
4154 sp = (abi_ulong) ka->sa_restorer;
4155 }
4156
4157 return (sp - frame_size) & -8ul;
4158}
4159
Andreas Färber05390242012-02-25 03:37:53 +01004160static void save_sigregs(CPUS390XState *env, target_sigregs *sregs)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004161{
4162 int i;
4163 //save_access_regs(current->thread.acrs); FIXME
4164
4165 /* Copy a 'clean' PSW mask to the user to avoid leaking
4166 information about whether PER is currently on. */
4167 __put_user(env->psw.mask, &sregs->regs.psw.mask);
4168 __put_user(env->psw.addr, &sregs->regs.psw.addr);
4169 for (i = 0; i < 16; i++) {
4170 __put_user(env->regs[i], &sregs->regs.gprs[i]);
4171 }
4172 for (i = 0; i < 16; i++) {
4173 __put_user(env->aregs[i], &sregs->regs.acrs[i]);
4174 }
4175 /*
4176 * We have to store the fp registers to current->thread.fp_regs
4177 * to merge them with the emulated registers.
4178 */
4179 //save_fp_regs(&current->thread.fp_regs); FIXME
4180 for (i = 0; i < 16; i++) {
Eric Farmanc498d8e2015-05-07 14:35:44 -04004181 __put_user(get_freg(env, i)->ll, &sregs->fpregs.fprs[i]);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004182 }
4183}
4184
4185static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01004186 target_sigset_t *set, CPUS390XState *env)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004187{
4188 sigframe *frame;
4189 abi_ulong frame_addr;
4190
4191 frame_addr = get_sigframe(ka, env, sizeof(*frame));
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01004192 trace_user_setup_frame(env, frame_addr);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004193 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01004194 goto give_sigsegv;
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004195 }
4196
Riku Voipio0188fad2014-04-23 13:34:15 +03004197 __put_user(set->sig[0], &frame->sc.oldmask[0]);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004198
4199 save_sigregs(env, &frame->sregs);
4200
4201 __put_user((abi_ulong)(unsigned long)&frame->sregs,
4202 (abi_ulong *)&frame->sc.sregs);
4203
4204 /* Set up to return from userspace. If provided, use a stub
4205 already in userspace. */
4206 if (ka->sa_flags & TARGET_SA_RESTORER) {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01004207 env->regs[14] = (unsigned long)
4208 ka->sa_restorer | PSW_ADDR_AMODE;
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004209 } else {
Chen Gang5b1d59d2016-05-24 14:54:32 +03004210 env->regs[14] = (frame_addr + offsetof(sigframe, retcode))
4211 | PSW_ADDR_AMODE;
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01004212 __put_user(S390_SYSCALL_OPCODE | TARGET_NR_sigreturn,
4213 (uint16_t *)(frame->retcode));
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004214 }
4215
4216 /* Set up backchain. */
Riku Voipio0188fad2014-04-23 13:34:15 +03004217 __put_user(env->regs[15], (abi_ulong *) frame);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004218
4219 /* Set up registers for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02004220 env->regs[15] = frame_addr;
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004221 env->psw.addr = (target_ulong) ka->_sa_handler | PSW_ADDR_AMODE;
4222
4223 env->regs[2] = sig; //map_signal(sig);
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02004224 env->regs[3] = frame_addr += offsetof(typeof(*frame), sc);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004225
4226 /* We forgot to include these in the sigcontext.
4227 To avoid breaking binary compatibility, they are passed as args. */
4228 env->regs[4] = 0; // FIXME: no clue... current->thread.trap_no;
4229 env->regs[5] = 0; // FIXME: no clue... current->thread.prot_addr;
4230
4231 /* Place signal number on stack to allow backtrace from handler. */
Riku Voipio0188fad2014-04-23 13:34:15 +03004232 __put_user(env->regs[2], (int *) &frame->signo);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004233 unlock_user_struct(frame, frame_addr, 1);
4234 return;
4235
4236give_sigsegv:
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004237 force_sig(TARGET_SIGSEGV);
4238}
4239
4240static void setup_rt_frame(int sig, struct target_sigaction *ka,
4241 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01004242 target_sigset_t *set, CPUS390XState *env)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004243{
4244 int i;
4245 rt_sigframe *frame;
4246 abi_ulong frame_addr;
4247
4248 frame_addr = get_sigframe(ka, env, sizeof *frame);
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01004249 trace_user_setup_rt_frame(env, frame_addr);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004250 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
4251 goto give_sigsegv;
4252 }
4253
Peter Maydellf6c7a052015-01-08 12:19:48 +00004254 tswap_siginfo(&frame->info, info);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004255
4256 /* Create the ucontext. */
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004257 __put_user(0, &frame->uc.tuc_flags);
4258 __put_user((abi_ulong)0, (abi_ulong *)&frame->uc.tuc_link);
4259 __put_user(target_sigaltstack_used.ss_sp, &frame->uc.tuc_stack.ss_sp);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004260 __put_user(sas_ss_flags(get_sp_from_cpustate(env)),
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01004261 &frame->uc.tuc_stack.ss_flags);
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004262 __put_user(target_sigaltstack_used.ss_size, &frame->uc.tuc_stack.ss_size);
4263 save_sigregs(env, &frame->uc.tuc_mcontext);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004264 for (i = 0; i < TARGET_NSIG_WORDS; i++) {
4265 __put_user((abi_ulong)set->sig[i],
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01004266 (abi_ulong *)&frame->uc.tuc_sigmask.sig[i]);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004267 }
4268
4269 /* Set up to return from userspace. If provided, use a stub
4270 already in userspace. */
4271 if (ka->sa_flags & TARGET_SA_RESTORER) {
4272 env->regs[14] = (unsigned long) ka->sa_restorer | PSW_ADDR_AMODE;
4273 } else {
4274 env->regs[14] = (unsigned long) frame->retcode | PSW_ADDR_AMODE;
Riku Voipio0188fad2014-04-23 13:34:15 +03004275 __put_user(S390_SYSCALL_OPCODE | TARGET_NR_rt_sigreturn,
4276 (uint16_t *)(frame->retcode));
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004277 }
4278
4279 /* Set up backchain. */
Riku Voipio0188fad2014-04-23 13:34:15 +03004280 __put_user(env->regs[15], (abi_ulong *) frame);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004281
4282 /* Set up registers for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02004283 env->regs[15] = frame_addr;
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004284 env->psw.addr = (target_ulong) ka->_sa_handler | PSW_ADDR_AMODE;
4285
4286 env->regs[2] = sig; //map_signal(sig);
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02004287 env->regs[3] = frame_addr + offsetof(typeof(*frame), info);
4288 env->regs[4] = frame_addr + offsetof(typeof(*frame), uc);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004289 return;
4290
4291give_sigsegv:
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004292 force_sig(TARGET_SIGSEGV);
4293}
4294
4295static int
Andreas Färber05390242012-02-25 03:37:53 +01004296restore_sigregs(CPUS390XState *env, target_sigregs *sc)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004297{
4298 int err = 0;
4299 int i;
4300
4301 for (i = 0; i < 16; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03004302 __get_user(env->regs[i], &sc->regs.gprs[i]);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004303 }
4304
Riku Voipio1d8b5122014-04-23 10:26:05 +03004305 __get_user(env->psw.mask, &sc->regs.psw.mask);
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01004306 trace_user_s390x_restore_sigregs(env, (unsigned long long)sc->regs.psw.addr,
4307 (unsigned long long)env->psw.addr);
Riku Voipio1d8b5122014-04-23 10:26:05 +03004308 __get_user(env->psw.addr, &sc->regs.psw.addr);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004309 /* FIXME: 31-bit -> | PSW_ADDR_AMODE */
4310
4311 for (i = 0; i < 16; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03004312 __get_user(env->aregs[i], &sc->regs.acrs[i]);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004313 }
4314 for (i = 0; i < 16; i++) {
Eric Farmanc498d8e2015-05-07 14:35:44 -04004315 __get_user(get_freg(env, i)->ll, &sc->fpregs.fprs[i]);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004316 }
4317
4318 return err;
4319}
4320
Andreas Färber05390242012-02-25 03:37:53 +01004321long do_sigreturn(CPUS390XState *env)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004322{
4323 sigframe *frame;
4324 abi_ulong frame_addr = env->regs[15];
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004325 target_sigset_t target_set;
4326 sigset_t set;
4327
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01004328 trace_user_do_sigreturn(env, frame_addr);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004329 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
4330 goto badframe;
4331 }
Riku Voipiof5f601a2014-04-23 13:00:17 +03004332 __get_user(target_set.sig[0], &frame->sc.oldmask[0]);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004333
4334 target_to_host_sigset_internal(&set, &target_set);
Peter Maydell9eede5b2016-05-27 15:51:46 +01004335 set_sigmask(&set); /* ~_BLOCKABLE? */
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004336
4337 if (restore_sigregs(env, &frame->sregs)) {
4338 goto badframe;
4339 }
4340
4341 unlock_user_struct(frame, frame_addr, 0);
Timothy E Baldwin47405ab2016-05-12 18:47:40 +01004342 return -TARGET_QEMU_ESIGRETURN;
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004343
4344badframe:
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004345 force_sig(TARGET_SIGSEGV);
4346 return 0;
4347}
4348
Andreas Färber05390242012-02-25 03:37:53 +01004349long do_rt_sigreturn(CPUS390XState *env)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004350{
4351 rt_sigframe *frame;
4352 abi_ulong frame_addr = env->regs[15];
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004353 sigset_t set;
4354
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01004355 trace_user_do_rt_sigreturn(env, frame_addr);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004356 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
4357 goto badframe;
4358 }
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004359 target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004360
Peter Maydell9eede5b2016-05-27 15:51:46 +01004361 set_sigmask(&set); /* ~_BLOCKABLE? */
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004362
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004363 if (restore_sigregs(env, &frame->uc.tuc_mcontext)) {
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004364 goto badframe;
4365 }
4366
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004367 if (do_sigaltstack(frame_addr + offsetof(rt_sigframe, uc.tuc_stack), 0,
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004368 get_sp_from_cpustate(env)) == -EFAULT) {
4369 goto badframe;
4370 }
4371 unlock_user_struct(frame, frame_addr, 0);
Timothy E Baldwin47405ab2016-05-12 18:47:40 +01004372 return -TARGET_QEMU_ESIGRETURN;
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004373
4374badframe:
4375 unlock_user_struct(frame, frame_addr, 0);
4376 force_sig(TARGET_SIGSEGV);
4377 return 0;
4378}
4379
Tom Musta61e75fe2014-06-30 08:13:38 -05004380#elif defined(TARGET_PPC)
Nathan Froydbcd49332009-05-12 19:13:18 -07004381
4382/* Size of dummy stack frame allocated when calling signal handler.
4383 See arch/powerpc/include/asm/ptrace.h. */
4384#if defined(TARGET_PPC64)
4385#define SIGNAL_FRAMESIZE 128
4386#else
4387#define SIGNAL_FRAMESIZE 64
4388#endif
4389
Tom Musta61e75fe2014-06-30 08:13:38 -05004390/* See arch/powerpc/include/asm/ucontext.h. Only used for 32-bit PPC;
4391 on 64-bit PPC, sigcontext and mcontext are one and the same. */
4392struct target_mcontext {
4393 target_ulong mc_gregs[48];
4394 /* Includes fpscr. */
4395 uint64_t mc_fregs[33];
4396 target_ulong mc_pad[2];
4397 /* We need to handle Altivec and SPE at the same time, which no
4398 kernel needs to do. Fortunately, the kernel defines this bit to
4399 be Altivec-register-large all the time, rather than trying to
4400 twiddle it based on the specific platform. */
4401 union {
4402 /* SPE vector registers. One extra for SPEFSCR. */
4403 uint32_t spe[33];
4404 /* Altivec vector registers. The packing of VSCR and VRSAVE
4405 varies depending on whether we're PPC64 or not: PPC64 splits
4406 them apart; PPC32 stuffs them together. */
4407#if defined(TARGET_PPC64)
4408#define QEMU_NVRREG 34
4409#else
4410#define QEMU_NVRREG 33
4411#endif
4412 ppc_avr_t altivec[QEMU_NVRREG];
4413#undef QEMU_NVRREG
4414 } mc_vregs __attribute__((__aligned__(16)));
4415};
4416
Nathan Froydbcd49332009-05-12 19:13:18 -07004417/* See arch/powerpc/include/asm/sigcontext.h. */
4418struct target_sigcontext {
4419 target_ulong _unused[4];
4420 int32_t signal;
4421#if defined(TARGET_PPC64)
4422 int32_t pad0;
4423#endif
4424 target_ulong handler;
4425 target_ulong oldmask;
4426 target_ulong regs; /* struct pt_regs __user * */
Tom Musta61e75fe2014-06-30 08:13:38 -05004427#if defined(TARGET_PPC64)
4428 struct target_mcontext mcontext;
4429#endif
Nathan Froydbcd49332009-05-12 19:13:18 -07004430};
4431
4432/* Indices for target_mcontext.mc_gregs, below.
4433 See arch/powerpc/include/asm/ptrace.h for details. */
4434enum {
4435 TARGET_PT_R0 = 0,
4436 TARGET_PT_R1 = 1,
4437 TARGET_PT_R2 = 2,
4438 TARGET_PT_R3 = 3,
4439 TARGET_PT_R4 = 4,
4440 TARGET_PT_R5 = 5,
4441 TARGET_PT_R6 = 6,
4442 TARGET_PT_R7 = 7,
4443 TARGET_PT_R8 = 8,
4444 TARGET_PT_R9 = 9,
4445 TARGET_PT_R10 = 10,
4446 TARGET_PT_R11 = 11,
4447 TARGET_PT_R12 = 12,
4448 TARGET_PT_R13 = 13,
4449 TARGET_PT_R14 = 14,
4450 TARGET_PT_R15 = 15,
4451 TARGET_PT_R16 = 16,
4452 TARGET_PT_R17 = 17,
4453 TARGET_PT_R18 = 18,
4454 TARGET_PT_R19 = 19,
4455 TARGET_PT_R20 = 20,
4456 TARGET_PT_R21 = 21,
4457 TARGET_PT_R22 = 22,
4458 TARGET_PT_R23 = 23,
4459 TARGET_PT_R24 = 24,
4460 TARGET_PT_R25 = 25,
4461 TARGET_PT_R26 = 26,
4462 TARGET_PT_R27 = 27,
4463 TARGET_PT_R28 = 28,
4464 TARGET_PT_R29 = 29,
4465 TARGET_PT_R30 = 30,
4466 TARGET_PT_R31 = 31,
4467 TARGET_PT_NIP = 32,
4468 TARGET_PT_MSR = 33,
4469 TARGET_PT_ORIG_R3 = 34,
4470 TARGET_PT_CTR = 35,
4471 TARGET_PT_LNK = 36,
4472 TARGET_PT_XER = 37,
4473 TARGET_PT_CCR = 38,
4474 /* Yes, there are two registers with #39. One is 64-bit only. */
4475 TARGET_PT_MQ = 39,
4476 TARGET_PT_SOFTE = 39,
4477 TARGET_PT_TRAP = 40,
4478 TARGET_PT_DAR = 41,
4479 TARGET_PT_DSISR = 42,
4480 TARGET_PT_RESULT = 43,
4481 TARGET_PT_REGS_COUNT = 44
4482};
4483
Nathan Froydbcd49332009-05-12 19:13:18 -07004484
4485struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02004486 target_ulong tuc_flags;
4487 target_ulong tuc_link; /* struct ucontext __user * */
4488 struct target_sigaltstack tuc_stack;
Nathan Froydbcd49332009-05-12 19:13:18 -07004489#if !defined(TARGET_PPC64)
Aurelien Jarno60e99242010-03-29 02:12:51 +02004490 int32_t tuc_pad[7];
4491 target_ulong tuc_regs; /* struct mcontext __user *
Nathan Froydbcd49332009-05-12 19:13:18 -07004492 points to uc_mcontext field */
4493#endif
Aurelien Jarno60e99242010-03-29 02:12:51 +02004494 target_sigset_t tuc_sigmask;
Nathan Froydbcd49332009-05-12 19:13:18 -07004495#if defined(TARGET_PPC64)
Anthony Liguoric227f092009-10-01 16:12:16 -05004496 target_sigset_t unused[15]; /* Allow for uc_sigmask growth */
Tom Musta61e75fe2014-06-30 08:13:38 -05004497 struct target_sigcontext tuc_sigcontext;
Nathan Froydbcd49332009-05-12 19:13:18 -07004498#else
Aurelien Jarno60e99242010-03-29 02:12:51 +02004499 int32_t tuc_maskext[30];
4500 int32_t tuc_pad2[3];
4501 struct target_mcontext tuc_mcontext;
Nathan Froydbcd49332009-05-12 19:13:18 -07004502#endif
4503};
4504
4505/* See arch/powerpc/kernel/signal_32.c. */
4506struct target_sigframe {
4507 struct target_sigcontext sctx;
4508 struct target_mcontext mctx;
4509 int32_t abigap[56];
4510};
4511
Tom Musta61e75fe2014-06-30 08:13:38 -05004512#if defined(TARGET_PPC64)
4513
4514#define TARGET_TRAMP_SIZE 6
4515
4516struct target_rt_sigframe {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01004517 /* sys_rt_sigreturn requires the ucontext be the first field */
4518 struct target_ucontext uc;
4519 target_ulong _unused[2];
4520 uint32_t trampoline[TARGET_TRAMP_SIZE];
4521 target_ulong pinfo; /* struct siginfo __user * */
4522 target_ulong puc; /* void __user * */
4523 struct target_siginfo info;
4524 /* 64 bit ABI allows for 288 bytes below sp before decrementing it. */
4525 char abigap[288];
Tom Musta61e75fe2014-06-30 08:13:38 -05004526} __attribute__((aligned(16)));
4527
4528#else
4529
Nathan Froydbcd49332009-05-12 19:13:18 -07004530struct target_rt_sigframe {
4531 struct target_siginfo info;
4532 struct target_ucontext uc;
4533 int32_t abigap[56];
4534};
4535
Tom Musta61e75fe2014-06-30 08:13:38 -05004536#endif
4537
Tom Musta8d6ab332014-06-30 08:13:39 -05004538#if defined(TARGET_PPC64)
4539
4540struct target_func_ptr {
4541 target_ulong entry;
4542 target_ulong toc;
4543};
4544
4545#endif
4546
Nathan Froydbcd49332009-05-12 19:13:18 -07004547/* We use the mc_pad field for the signal return trampoline. */
4548#define tramp mc_pad
4549
4550/* See arch/powerpc/kernel/signal.c. */
4551static target_ulong get_sigframe(struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01004552 CPUPPCState *env,
Nathan Froydbcd49332009-05-12 19:13:18 -07004553 int frame_size)
4554{
4555 target_ulong oldsp, newsp;
4556
4557 oldsp = env->gpr[1];
4558
4559 if ((ka->sa_flags & TARGET_SA_ONSTACK) &&
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01004560 (sas_ss_flags(oldsp) == 0)) {
Nathan Froydbcd49332009-05-12 19:13:18 -07004561 oldsp = (target_sigaltstack_used.ss_sp
4562 + target_sigaltstack_used.ss_size);
4563 }
4564
4565 newsp = (oldsp - frame_size) & ~0xFUL;
4566
4567 return newsp;
4568}
4569
Tom Musta76781082014-06-30 08:13:37 -05004570static void save_user_regs(CPUPPCState *env, struct target_mcontext *frame)
Nathan Froydbcd49332009-05-12 19:13:18 -07004571{
4572 target_ulong msr = env->msr;
4573 int i;
4574 target_ulong ccr = 0;
4575
4576 /* In general, the kernel attempts to be intelligent about what it
4577 needs to save for Altivec/FP/SPE registers. We don't care that
4578 much, so we just go ahead and save everything. */
4579
4580 /* Save general registers. */
4581 for (i = 0; i < ARRAY_SIZE(env->gpr); i++) {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01004582 __put_user(env->gpr[i], &frame->mc_gregs[i]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004583 }
Riku Voipioc650c002014-04-23 13:53:45 +03004584 __put_user(env->nip, &frame->mc_gregs[TARGET_PT_NIP]);
4585 __put_user(env->ctr, &frame->mc_gregs[TARGET_PT_CTR]);
4586 __put_user(env->lr, &frame->mc_gregs[TARGET_PT_LNK]);
4587 __put_user(env->xer, &frame->mc_gregs[TARGET_PT_XER]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004588
4589 for (i = 0; i < ARRAY_SIZE(env->crf); i++) {
4590 ccr |= env->crf[i] << (32 - ((i + 1) * 4));
4591 }
Riku Voipioc650c002014-04-23 13:53:45 +03004592 __put_user(ccr, &frame->mc_gregs[TARGET_PT_CCR]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004593
4594 /* Save Altivec registers if necessary. */
4595 if (env->insns_flags & PPC_ALTIVEC) {
4596 for (i = 0; i < ARRAY_SIZE(env->avr); i++) {
Anthony Liguoric227f092009-10-01 16:12:16 -05004597 ppc_avr_t *avr = &env->avr[i];
4598 ppc_avr_t *vreg = &frame->mc_vregs.altivec[i];
Nathan Froydbcd49332009-05-12 19:13:18 -07004599
Riku Voipioc650c002014-04-23 13:53:45 +03004600 __put_user(avr->u64[0], &vreg->u64[0]);
4601 __put_user(avr->u64[1], &vreg->u64[1]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004602 }
4603 /* Set MSR_VR in the saved MSR value to indicate that
4604 frame->mc_vregs contains valid data. */
4605 msr |= MSR_VR;
Riku Voipioc650c002014-04-23 13:53:45 +03004606 __put_user((uint32_t)env->spr[SPR_VRSAVE],
4607 &frame->mc_vregs.altivec[32].u32[3]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004608 }
4609
4610 /* Save floating point registers. */
4611 if (env->insns_flags & PPC_FLOAT) {
4612 for (i = 0; i < ARRAY_SIZE(env->fpr); i++) {
Riku Voipioc650c002014-04-23 13:53:45 +03004613 __put_user(env->fpr[i], &frame->mc_fregs[i]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004614 }
Riku Voipioc650c002014-04-23 13:53:45 +03004615 __put_user((uint64_t) env->fpscr, &frame->mc_fregs[32]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004616 }
4617
4618 /* Save SPE registers. The kernel only saves the high half. */
4619 if (env->insns_flags & PPC_SPE) {
4620#if defined(TARGET_PPC64)
4621 for (i = 0; i < ARRAY_SIZE(env->gpr); i++) {
Riku Voipioc650c002014-04-23 13:53:45 +03004622 __put_user(env->gpr[i] >> 32, &frame->mc_vregs.spe[i]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004623 }
4624#else
4625 for (i = 0; i < ARRAY_SIZE(env->gprh); i++) {
Riku Voipioc650c002014-04-23 13:53:45 +03004626 __put_user(env->gprh[i], &frame->mc_vregs.spe[i]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004627 }
4628#endif
4629 /* Set MSR_SPE in the saved MSR value to indicate that
4630 frame->mc_vregs contains valid data. */
4631 msr |= MSR_SPE;
Riku Voipioc650c002014-04-23 13:53:45 +03004632 __put_user(env->spe_fscr, &frame->mc_vregs.spe[32]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004633 }
4634
4635 /* Store MSR. */
Riku Voipioc650c002014-04-23 13:53:45 +03004636 __put_user(msr, &frame->mc_gregs[TARGET_PT_MSR]);
Tom Musta76781082014-06-30 08:13:37 -05004637}
Nathan Froydbcd49332009-05-12 19:13:18 -07004638
Tom Musta76781082014-06-30 08:13:37 -05004639static void encode_trampoline(int sigret, uint32_t *tramp)
4640{
Nathan Froydbcd49332009-05-12 19:13:18 -07004641 /* Set up the sigreturn trampoline: li r0,sigret; sc. */
4642 if (sigret) {
Tom Musta76781082014-06-30 08:13:37 -05004643 __put_user(0x38000000 | sigret, &tramp[0]);
4644 __put_user(0x44000002, &tramp[1]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004645 }
Nathan Froydbcd49332009-05-12 19:13:18 -07004646}
4647
Riku Voipioc650c002014-04-23 13:53:45 +03004648static void restore_user_regs(CPUPPCState *env,
4649 struct target_mcontext *frame, int sig)
Nathan Froydbcd49332009-05-12 19:13:18 -07004650{
4651 target_ulong save_r2 = 0;
4652 target_ulong msr;
4653 target_ulong ccr;
4654
4655 int i;
4656
4657 if (!sig) {
4658 save_r2 = env->gpr[2];
4659 }
4660
4661 /* Restore general registers. */
4662 for (i = 0; i < ARRAY_SIZE(env->gpr); i++) {
Riku Voipioc650c002014-04-23 13:53:45 +03004663 __get_user(env->gpr[i], &frame->mc_gregs[i]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004664 }
Riku Voipioc650c002014-04-23 13:53:45 +03004665 __get_user(env->nip, &frame->mc_gregs[TARGET_PT_NIP]);
4666 __get_user(env->ctr, &frame->mc_gregs[TARGET_PT_CTR]);
4667 __get_user(env->lr, &frame->mc_gregs[TARGET_PT_LNK]);
4668 __get_user(env->xer, &frame->mc_gregs[TARGET_PT_XER]);
4669 __get_user(ccr, &frame->mc_gregs[TARGET_PT_CCR]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004670
4671 for (i = 0; i < ARRAY_SIZE(env->crf); i++) {
4672 env->crf[i] = (ccr >> (32 - ((i + 1) * 4))) & 0xf;
4673 }
4674
4675 if (!sig) {
4676 env->gpr[2] = save_r2;
4677 }
4678 /* Restore MSR. */
Riku Voipioc650c002014-04-23 13:53:45 +03004679 __get_user(msr, &frame->mc_gregs[TARGET_PT_MSR]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004680
4681 /* If doing signal return, restore the previous little-endian mode. */
4682 if (sig)
Laurent Vivier49e55cb2016-03-30 18:36:51 +02004683 env->msr = (env->msr & ~(1ull << MSR_LE)) | (msr & (1ull << MSR_LE));
Nathan Froydbcd49332009-05-12 19:13:18 -07004684
4685 /* Restore Altivec registers if necessary. */
4686 if (env->insns_flags & PPC_ALTIVEC) {
4687 for (i = 0; i < ARRAY_SIZE(env->avr); i++) {
Anthony Liguoric227f092009-10-01 16:12:16 -05004688 ppc_avr_t *avr = &env->avr[i];
4689 ppc_avr_t *vreg = &frame->mc_vregs.altivec[i];
Nathan Froydbcd49332009-05-12 19:13:18 -07004690
Riku Voipioc650c002014-04-23 13:53:45 +03004691 __get_user(avr->u64[0], &vreg->u64[0]);
4692 __get_user(avr->u64[1], &vreg->u64[1]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004693 }
4694 /* Set MSR_VEC in the saved MSR value to indicate that
4695 frame->mc_vregs contains valid data. */
Riku Voipioc650c002014-04-23 13:53:45 +03004696 __get_user(env->spr[SPR_VRSAVE],
4697 (target_ulong *)(&frame->mc_vregs.altivec[32].u32[3]));
Nathan Froydbcd49332009-05-12 19:13:18 -07004698 }
4699
4700 /* Restore floating point registers. */
4701 if (env->insns_flags & PPC_FLOAT) {
4702 uint64_t fpscr;
4703 for (i = 0; i < ARRAY_SIZE(env->fpr); i++) {
Riku Voipioc650c002014-04-23 13:53:45 +03004704 __get_user(env->fpr[i], &frame->mc_fregs[i]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004705 }
Riku Voipioc650c002014-04-23 13:53:45 +03004706 __get_user(fpscr, &frame->mc_fregs[32]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004707 env->fpscr = (uint32_t) fpscr;
4708 }
4709
4710 /* Save SPE registers. The kernel only saves the high half. */
4711 if (env->insns_flags & PPC_SPE) {
4712#if defined(TARGET_PPC64)
4713 for (i = 0; i < ARRAY_SIZE(env->gpr); i++) {
4714 uint32_t hi;
4715
Riku Voipioc650c002014-04-23 13:53:45 +03004716 __get_user(hi, &frame->mc_vregs.spe[i]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004717 env->gpr[i] = ((uint64_t)hi << 32) | ((uint32_t) env->gpr[i]);
4718 }
4719#else
4720 for (i = 0; i < ARRAY_SIZE(env->gprh); i++) {
Riku Voipioc650c002014-04-23 13:53:45 +03004721 __get_user(env->gprh[i], &frame->mc_vregs.spe[i]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004722 }
4723#endif
Riku Voipioc650c002014-04-23 13:53:45 +03004724 __get_user(env->spe_fscr, &frame->mc_vregs.spe[32]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004725 }
Nathan Froydbcd49332009-05-12 19:13:18 -07004726}
4727
4728static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01004729 target_sigset_t *set, CPUPPCState *env)
Nathan Froydbcd49332009-05-12 19:13:18 -07004730{
4731 struct target_sigframe *frame;
4732 struct target_sigcontext *sc;
4733 target_ulong frame_addr, newsp;
4734 int err = 0;
Tom Musta14585582014-06-30 08:13:42 -05004735#if defined(TARGET_PPC64)
4736 struct image_info *image = ((TaskState *)thread_cpu->opaque)->info;
4737#endif
Nathan Froydbcd49332009-05-12 19:13:18 -07004738
4739 frame_addr = get_sigframe(ka, env, sizeof(*frame));
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01004740 trace_user_setup_frame(env, frame_addr);
Nathan Froydbcd49332009-05-12 19:13:18 -07004741 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 1))
4742 goto sigsegv;
4743 sc = &frame->sctx;
4744
Riku Voipio1d8b5122014-04-23 10:26:05 +03004745 __put_user(ka->_sa_handler, &sc->handler);
4746 __put_user(set->sig[0], &sc->oldmask);
Tom Musta61e75fe2014-06-30 08:13:38 -05004747#if TARGET_ABI_BITS == 64
Riku Voipio1d8b5122014-04-23 10:26:05 +03004748 __put_user(set->sig[0] >> 32, &sc->_unused[3]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004749#else
Riku Voipio1d8b5122014-04-23 10:26:05 +03004750 __put_user(set->sig[1], &sc->_unused[3]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004751#endif
Riku Voipio1d8b5122014-04-23 10:26:05 +03004752 __put_user(h2g(&frame->mctx), &sc->regs);
4753 __put_user(sig, &sc->signal);
Nathan Froydbcd49332009-05-12 19:13:18 -07004754
4755 /* Save user regs. */
Tom Musta76781082014-06-30 08:13:37 -05004756 save_user_regs(env, &frame->mctx);
4757
4758 /* Construct the trampoline code on the stack. */
4759 encode_trampoline(TARGET_NR_sigreturn, (uint32_t *)&frame->mctx.tramp);
Nathan Froydbcd49332009-05-12 19:13:18 -07004760
4761 /* The kernel checks for the presence of a VDSO here. We don't
4762 emulate a vdso, so use a sigreturn system call. */
4763 env->lr = (target_ulong) h2g(frame->mctx.tramp);
4764
4765 /* Turn off all fp exceptions. */
4766 env->fpscr = 0;
4767
4768 /* Create a stack frame for the caller of the handler. */
4769 newsp = frame_addr - SIGNAL_FRAMESIZE;
Samuel Seaybeb526b2013-01-02 10:53:46 +00004770 err |= put_user(env->gpr[1], newsp, target_ulong);
Nathan Froydbcd49332009-05-12 19:13:18 -07004771
4772 if (err)
4773 goto sigsegv;
4774
4775 /* Set up registers for signal handler. */
4776 env->gpr[1] = newsp;
Peter Maydellb6e2c932015-01-08 12:19:43 +00004777 env->gpr[3] = sig;
Samuel Seay61993a62013-01-04 14:35:48 +00004778 env->gpr[4] = frame_addr + offsetof(struct target_sigframe, sctx);
Tom Musta8d6ab332014-06-30 08:13:39 -05004779
4780#if defined(TARGET_PPC64)
Tom Musta14585582014-06-30 08:13:42 -05004781 if (get_ppc64_abi(image) < 2) {
4782 /* ELFv1 PPC64 function pointers are pointers to OPD entries. */
4783 struct target_func_ptr *handler =
4784 (struct target_func_ptr *)g2h(ka->_sa_handler);
4785 env->nip = tswapl(handler->entry);
4786 env->gpr[2] = tswapl(handler->toc);
4787 } else {
4788 /* ELFv2 PPC64 function pointers are entry points, but R12
4789 * must also be set */
4790 env->nip = tswapl((target_ulong) ka->_sa_handler);
4791 env->gpr[12] = env->nip;
4792 }
Tom Musta8d6ab332014-06-30 08:13:39 -05004793#else
Nathan Froydbcd49332009-05-12 19:13:18 -07004794 env->nip = (target_ulong) ka->_sa_handler;
Tom Musta8d6ab332014-06-30 08:13:39 -05004795#endif
4796
Nathan Froydbcd49332009-05-12 19:13:18 -07004797 /* Signal handlers are entered in big-endian mode. */
Laurent Vivier49e55cb2016-03-30 18:36:51 +02004798 env->msr &= ~(1ull << MSR_LE);
Nathan Froydbcd49332009-05-12 19:13:18 -07004799
4800 unlock_user_struct(frame, frame_addr, 1);
4801 return;
4802
4803sigsegv:
4804 unlock_user_struct(frame, frame_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02004805 force_sig(TARGET_SIGSEGV);
Nathan Froydbcd49332009-05-12 19:13:18 -07004806}
4807
4808static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05004809 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01004810 target_sigset_t *set, CPUPPCState *env)
Nathan Froydbcd49332009-05-12 19:13:18 -07004811{
4812 struct target_rt_sigframe *rt_sf;
Tom Musta61e75fe2014-06-30 08:13:38 -05004813 uint32_t *trampptr = 0;
4814 struct target_mcontext *mctx = 0;
Nathan Froydbcd49332009-05-12 19:13:18 -07004815 target_ulong rt_sf_addr, newsp = 0;
4816 int i, err = 0;
Tom Musta14585582014-06-30 08:13:42 -05004817#if defined(TARGET_PPC64)
4818 struct image_info *image = ((TaskState *)thread_cpu->opaque)->info;
4819#endif
Nathan Froydbcd49332009-05-12 19:13:18 -07004820
4821 rt_sf_addr = get_sigframe(ka, env, sizeof(*rt_sf));
4822 if (!lock_user_struct(VERIFY_WRITE, rt_sf, rt_sf_addr, 1))
4823 goto sigsegv;
4824
Peter Maydellf6c7a052015-01-08 12:19:48 +00004825 tswap_siginfo(&rt_sf->info, info);
Nathan Froydbcd49332009-05-12 19:13:18 -07004826
Riku Voipio1d8b5122014-04-23 10:26:05 +03004827 __put_user(0, &rt_sf->uc.tuc_flags);
4828 __put_user(0, &rt_sf->uc.tuc_link);
4829 __put_user((target_ulong)target_sigaltstack_used.ss_sp,
4830 &rt_sf->uc.tuc_stack.ss_sp);
4831 __put_user(sas_ss_flags(env->gpr[1]),
4832 &rt_sf->uc.tuc_stack.ss_flags);
4833 __put_user(target_sigaltstack_used.ss_size,
4834 &rt_sf->uc.tuc_stack.ss_size);
Tom Musta61e75fe2014-06-30 08:13:38 -05004835#if !defined(TARGET_PPC64)
Riku Voipio1d8b5122014-04-23 10:26:05 +03004836 __put_user(h2g (&rt_sf->uc.tuc_mcontext),
4837 &rt_sf->uc.tuc_regs);
Tom Musta61e75fe2014-06-30 08:13:38 -05004838#endif
Nathan Froydbcd49332009-05-12 19:13:18 -07004839 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03004840 __put_user(set->sig[i], &rt_sf->uc.tuc_sigmask.sig[i]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004841 }
4842
Tom Musta61e75fe2014-06-30 08:13:38 -05004843#if defined(TARGET_PPC64)
4844 mctx = &rt_sf->uc.tuc_sigcontext.mcontext;
4845 trampptr = &rt_sf->trampoline[0];
4846#else
4847 mctx = &rt_sf->uc.tuc_mcontext;
4848 trampptr = (uint32_t *)&rt_sf->uc.tuc_mcontext.tramp;
4849#endif
4850
4851 save_user_regs(env, mctx);
4852 encode_trampoline(TARGET_NR_rt_sigreturn, trampptr);
Nathan Froydbcd49332009-05-12 19:13:18 -07004853
4854 /* The kernel checks for the presence of a VDSO here. We don't
4855 emulate a vdso, so use a sigreturn system call. */
Tom Musta61e75fe2014-06-30 08:13:38 -05004856 env->lr = (target_ulong) h2g(trampptr);
Nathan Froydbcd49332009-05-12 19:13:18 -07004857
4858 /* Turn off all fp exceptions. */
4859 env->fpscr = 0;
4860
4861 /* Create a stack frame for the caller of the handler. */
4862 newsp = rt_sf_addr - (SIGNAL_FRAMESIZE + 16);
Tom Mustafbdc2002014-06-30 08:13:36 -05004863 err |= put_user(env->gpr[1], newsp, target_ulong);
Nathan Froydbcd49332009-05-12 19:13:18 -07004864
4865 if (err)
4866 goto sigsegv;
4867
4868 /* Set up registers for signal handler. */
4869 env->gpr[1] = newsp;
Peter Maydellb6e2c932015-01-08 12:19:43 +00004870 env->gpr[3] = (target_ulong) sig;
Nathan Froydbcd49332009-05-12 19:13:18 -07004871 env->gpr[4] = (target_ulong) h2g(&rt_sf->info);
4872 env->gpr[5] = (target_ulong) h2g(&rt_sf->uc);
4873 env->gpr[6] = (target_ulong) h2g(rt_sf);
Tom Musta8d6ab332014-06-30 08:13:39 -05004874
4875#if defined(TARGET_PPC64)
Tom Musta14585582014-06-30 08:13:42 -05004876 if (get_ppc64_abi(image) < 2) {
4877 /* ELFv1 PPC64 function pointers are pointers to OPD entries. */
4878 struct target_func_ptr *handler =
4879 (struct target_func_ptr *)g2h(ka->_sa_handler);
4880 env->nip = tswapl(handler->entry);
4881 env->gpr[2] = tswapl(handler->toc);
4882 } else {
4883 /* ELFv2 PPC64 function pointers are entry points, but R12
4884 * must also be set */
4885 env->nip = tswapl((target_ulong) ka->_sa_handler);
4886 env->gpr[12] = env->nip;
4887 }
Tom Musta8d6ab332014-06-30 08:13:39 -05004888#else
Nathan Froydbcd49332009-05-12 19:13:18 -07004889 env->nip = (target_ulong) ka->_sa_handler;
Tom Musta8d6ab332014-06-30 08:13:39 -05004890#endif
4891
Nathan Froydbcd49332009-05-12 19:13:18 -07004892 /* Signal handlers are entered in big-endian mode. */
Laurent Vivier49e55cb2016-03-30 18:36:51 +02004893 env->msr &= ~(1ull << MSR_LE);
Nathan Froydbcd49332009-05-12 19:13:18 -07004894
4895 unlock_user_struct(rt_sf, rt_sf_addr, 1);
4896 return;
4897
4898sigsegv:
4899 unlock_user_struct(rt_sf, rt_sf_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02004900 force_sig(TARGET_SIGSEGV);
Nathan Froydbcd49332009-05-12 19:13:18 -07004901
4902}
4903
Andreas Färber05390242012-02-25 03:37:53 +01004904long do_sigreturn(CPUPPCState *env)
Nathan Froydbcd49332009-05-12 19:13:18 -07004905{
4906 struct target_sigcontext *sc = NULL;
4907 struct target_mcontext *sr = NULL;
Peter Maydellb04636f2013-07-29 12:00:31 +01004908 target_ulong sr_addr = 0, sc_addr;
Nathan Froydbcd49332009-05-12 19:13:18 -07004909 sigset_t blocked;
Anthony Liguoric227f092009-10-01 16:12:16 -05004910 target_sigset_t set;
Nathan Froydbcd49332009-05-12 19:13:18 -07004911
4912 sc_addr = env->gpr[1] + SIGNAL_FRAMESIZE;
4913 if (!lock_user_struct(VERIFY_READ, sc, sc_addr, 1))
4914 goto sigsegv;
4915
4916#if defined(TARGET_PPC64)
Tom Musta61e75fe2014-06-30 08:13:38 -05004917 set.sig[0] = sc->oldmask + ((uint64_t)(sc->_unused[3]) << 32);
Nathan Froydbcd49332009-05-12 19:13:18 -07004918#else
Riku Voipiof5f601a2014-04-23 13:00:17 +03004919 __get_user(set.sig[0], &sc->oldmask);
4920 __get_user(set.sig[1], &sc->_unused[3]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004921#endif
4922 target_to_host_sigset_internal(&blocked, &set);
Peter Maydell9eede5b2016-05-27 15:51:46 +01004923 set_sigmask(&blocked);
Nathan Froydbcd49332009-05-12 19:13:18 -07004924
Riku Voipiof5f601a2014-04-23 13:00:17 +03004925 __get_user(sr_addr, &sc->regs);
Nathan Froydbcd49332009-05-12 19:13:18 -07004926 if (!lock_user_struct(VERIFY_READ, sr, sr_addr, 1))
4927 goto sigsegv;
Riku Voipioc650c002014-04-23 13:53:45 +03004928 restore_user_regs(env, sr, 1);
Nathan Froydbcd49332009-05-12 19:13:18 -07004929
4930 unlock_user_struct(sr, sr_addr, 1);
4931 unlock_user_struct(sc, sc_addr, 1);
4932 return -TARGET_QEMU_ESIGRETURN;
4933
4934sigsegv:
4935 unlock_user_struct(sr, sr_addr, 1);
4936 unlock_user_struct(sc, sc_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02004937 force_sig(TARGET_SIGSEGV);
Nathan Froydbcd49332009-05-12 19:13:18 -07004938 return 0;
4939}
4940
4941/* See arch/powerpc/kernel/signal_32.c. */
Andreas Färber05390242012-02-25 03:37:53 +01004942static int do_setcontext(struct target_ucontext *ucp, CPUPPCState *env, int sig)
Nathan Froydbcd49332009-05-12 19:13:18 -07004943{
4944 struct target_mcontext *mcp;
4945 target_ulong mcp_addr;
4946 sigset_t blocked;
Anthony Liguoric227f092009-10-01 16:12:16 -05004947 target_sigset_t set;
Nathan Froydbcd49332009-05-12 19:13:18 -07004948
Aurelien Jarno60e99242010-03-29 02:12:51 +02004949 if (copy_from_user(&set, h2g(ucp) + offsetof(struct target_ucontext, tuc_sigmask),
Nathan Froydbcd49332009-05-12 19:13:18 -07004950 sizeof (set)))
4951 return 1;
4952
Tom Musta19774ec2014-06-30 08:13:40 -05004953#if defined(TARGET_PPC64)
4954 mcp_addr = h2g(ucp) +
4955 offsetof(struct target_ucontext, tuc_sigcontext.mcontext);
4956#else
Riku Voipio9e918dc2014-04-23 14:05:09 +03004957 __get_user(mcp_addr, &ucp->tuc_regs);
Tom Musta19774ec2014-06-30 08:13:40 -05004958#endif
Nathan Froydbcd49332009-05-12 19:13:18 -07004959
4960 if (!lock_user_struct(VERIFY_READ, mcp, mcp_addr, 1))
4961 return 1;
4962
4963 target_to_host_sigset_internal(&blocked, &set);
Peter Maydell9eede5b2016-05-27 15:51:46 +01004964 set_sigmask(&blocked);
Riku Voipioc650c002014-04-23 13:53:45 +03004965 restore_user_regs(env, mcp, sig);
Nathan Froydbcd49332009-05-12 19:13:18 -07004966
4967 unlock_user_struct(mcp, mcp_addr, 1);
4968 return 0;
Nathan Froydbcd49332009-05-12 19:13:18 -07004969}
4970
Andreas Färber05390242012-02-25 03:37:53 +01004971long do_rt_sigreturn(CPUPPCState *env)
Nathan Froydbcd49332009-05-12 19:13:18 -07004972{
4973 struct target_rt_sigframe *rt_sf = NULL;
4974 target_ulong rt_sf_addr;
4975
4976 rt_sf_addr = env->gpr[1] + SIGNAL_FRAMESIZE + 16;
4977 if (!lock_user_struct(VERIFY_READ, rt_sf, rt_sf_addr, 1))
4978 goto sigsegv;
4979
4980 if (do_setcontext(&rt_sf->uc, env, 1))
4981 goto sigsegv;
4982
4983 do_sigaltstack(rt_sf_addr
Aurelien Jarno60e99242010-03-29 02:12:51 +02004984 + offsetof(struct target_rt_sigframe, uc.tuc_stack),
Nathan Froydbcd49332009-05-12 19:13:18 -07004985 0, env->gpr[1]);
4986
4987 unlock_user_struct(rt_sf, rt_sf_addr, 1);
4988 return -TARGET_QEMU_ESIGRETURN;
4989
4990sigsegv:
4991 unlock_user_struct(rt_sf, rt_sf_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02004992 force_sig(TARGET_SIGSEGV);
Nathan Froydbcd49332009-05-12 19:13:18 -07004993 return 0;
4994}
4995
Laurent Vivier492a8742009-08-03 16:12:17 +02004996#elif defined(TARGET_M68K)
4997
4998struct target_sigcontext {
4999 abi_ulong sc_mask;
5000 abi_ulong sc_usp;
5001 abi_ulong sc_d0;
5002 abi_ulong sc_d1;
5003 abi_ulong sc_a0;
5004 abi_ulong sc_a1;
5005 unsigned short sc_sr;
5006 abi_ulong sc_pc;
5007};
5008
5009struct target_sigframe
5010{
5011 abi_ulong pretcode;
5012 int sig;
5013 int code;
5014 abi_ulong psc;
5015 char retcode[8];
5016 abi_ulong extramask[TARGET_NSIG_WORDS-1];
5017 struct target_sigcontext sc;
5018};
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01005019
Anthony Liguoric227f092009-10-01 16:12:16 -05005020typedef int target_greg_t;
Laurent Vivier71811552009-08-03 16:12:18 +02005021#define TARGET_NGREG 18
Anthony Liguoric227f092009-10-01 16:12:16 -05005022typedef target_greg_t target_gregset_t[TARGET_NGREG];
Laurent Vivier71811552009-08-03 16:12:18 +02005023
5024typedef struct target_fpregset {
5025 int f_fpcntl[3];
5026 int f_fpregs[8*3];
Anthony Liguoric227f092009-10-01 16:12:16 -05005027} target_fpregset_t;
Laurent Vivier71811552009-08-03 16:12:18 +02005028
5029struct target_mcontext {
5030 int version;
Anthony Liguoric227f092009-10-01 16:12:16 -05005031 target_gregset_t gregs;
5032 target_fpregset_t fpregs;
Laurent Vivier71811552009-08-03 16:12:18 +02005033};
5034
5035#define TARGET_MCONTEXT_VERSION 2
5036
5037struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02005038 abi_ulong tuc_flags;
5039 abi_ulong tuc_link;
5040 target_stack_t tuc_stack;
5041 struct target_mcontext tuc_mcontext;
5042 abi_long tuc_filler[80];
5043 target_sigset_t tuc_sigmask;
Laurent Vivier71811552009-08-03 16:12:18 +02005044};
5045
5046struct target_rt_sigframe
5047{
5048 abi_ulong pretcode;
5049 int sig;
5050 abi_ulong pinfo;
5051 abi_ulong puc;
5052 char retcode[8];
5053 struct target_siginfo info;
5054 struct target_ucontext uc;
5055};
Laurent Vivier492a8742009-08-03 16:12:17 +02005056
Riku Voipio41ecc722014-04-23 11:01:00 +03005057static void setup_sigcontext(struct target_sigcontext *sc, CPUM68KState *env,
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01005058 abi_ulong mask)
Laurent Vivier492a8742009-08-03 16:12:17 +02005059{
Riku Voipio1d8b5122014-04-23 10:26:05 +03005060 __put_user(mask, &sc->sc_mask);
5061 __put_user(env->aregs[7], &sc->sc_usp);
5062 __put_user(env->dregs[0], &sc->sc_d0);
5063 __put_user(env->dregs[1], &sc->sc_d1);
5064 __put_user(env->aregs[0], &sc->sc_a0);
5065 __put_user(env->aregs[1], &sc->sc_a1);
5066 __put_user(env->sr, &sc->sc_sr);
5067 __put_user(env->pc, &sc->sc_pc);
Laurent Vivier492a8742009-08-03 16:12:17 +02005068}
5069
Riku Voipio016d2e12014-04-23 11:19:48 +03005070static void
Timothy E Baldwin7ccb84a2016-05-12 18:47:39 +01005071restore_sigcontext(CPUM68KState *env, struct target_sigcontext *sc)
Laurent Vivier492a8742009-08-03 16:12:17 +02005072{
Laurent Vivier492a8742009-08-03 16:12:17 +02005073 int temp;
5074
Riku Voipio1d8b5122014-04-23 10:26:05 +03005075 __get_user(env->aregs[7], &sc->sc_usp);
Timothy E Baldwin7ccb84a2016-05-12 18:47:39 +01005076 __get_user(env->dregs[0], &sc->sc_d0);
Riku Voipio1d8b5122014-04-23 10:26:05 +03005077 __get_user(env->dregs[1], &sc->sc_d1);
5078 __get_user(env->aregs[0], &sc->sc_a0);
5079 __get_user(env->aregs[1], &sc->sc_a1);
5080 __get_user(env->pc, &sc->sc_pc);
5081 __get_user(temp, &sc->sc_sr);
Laurent Vivier492a8742009-08-03 16:12:17 +02005082 env->sr = (env->sr & 0xff00) | (temp & 0xff);
Laurent Vivier492a8742009-08-03 16:12:17 +02005083}
5084
5085/*
5086 * Determine which stack to use..
5087 */
5088static inline abi_ulong
Andreas Färber05390242012-02-25 03:37:53 +01005089get_sigframe(struct target_sigaction *ka, CPUM68KState *regs,
5090 size_t frame_size)
Laurent Vivier492a8742009-08-03 16:12:17 +02005091{
5092 unsigned long sp;
5093
5094 sp = regs->aregs[7];
5095
5096 /* This is the X/Open sanctioned signal stack switching. */
5097 if ((ka->sa_flags & TARGET_SA_ONSTACK) && (sas_ss_flags (sp) == 0)) {
5098 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
5099 }
5100
5101 return ((sp - frame_size) & -8UL);
5102}
5103
5104static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01005105 target_sigset_t *set, CPUM68KState *env)
Laurent Vivier492a8742009-08-03 16:12:17 +02005106{
5107 struct target_sigframe *frame;
5108 abi_ulong frame_addr;
5109 abi_ulong retcode_addr;
5110 abi_ulong sc_addr;
Laurent Vivier492a8742009-08-03 16:12:17 +02005111 int i;
5112
5113 frame_addr = get_sigframe(ka, env, sizeof *frame);
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01005114 trace_user_setup_frame(env, frame_addr);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01005115 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
5116 goto give_sigsegv;
5117 }
Laurent Vivier492a8742009-08-03 16:12:17 +02005118
Riku Voipio1d8b5122014-04-23 10:26:05 +03005119 __put_user(sig, &frame->sig);
Laurent Vivier492a8742009-08-03 16:12:17 +02005120
5121 sc_addr = frame_addr + offsetof(struct target_sigframe, sc);
Riku Voipio1d8b5122014-04-23 10:26:05 +03005122 __put_user(sc_addr, &frame->psc);
Laurent Vivier492a8742009-08-03 16:12:17 +02005123
Riku Voipio41ecc722014-04-23 11:01:00 +03005124 setup_sigcontext(&frame->sc, env, set->sig[0]);
Laurent Vivier492a8742009-08-03 16:12:17 +02005125
5126 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
Riku Voipio0188fad2014-04-23 13:34:15 +03005127 __put_user(set->sig[i], &frame->extramask[i - 1]);
Laurent Vivier492a8742009-08-03 16:12:17 +02005128 }
5129
5130 /* Set up to return from userspace. */
5131
5132 retcode_addr = frame_addr + offsetof(struct target_sigframe, retcode);
Riku Voipio1d8b5122014-04-23 10:26:05 +03005133 __put_user(retcode_addr, &frame->pretcode);
Laurent Vivier492a8742009-08-03 16:12:17 +02005134
5135 /* moveq #,d0; trap #0 */
5136
Riku Voipio1d8b5122014-04-23 10:26:05 +03005137 __put_user(0x70004e40 + (TARGET_NR_sigreturn << 16),
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01005138 (uint32_t *)(frame->retcode));
Laurent Vivier492a8742009-08-03 16:12:17 +02005139
Laurent Vivier492a8742009-08-03 16:12:17 +02005140 /* Set up to return from userspace */
5141
5142 env->aregs[7] = frame_addr;
5143 env->pc = ka->_sa_handler;
5144
5145 unlock_user_struct(frame, frame_addr, 1);
5146 return;
5147
5148give_sigsegv:
Riku Voipio66393fb2009-12-04 15:16:32 +02005149 force_sig(TARGET_SIGSEGV);
Laurent Vivier492a8742009-08-03 16:12:17 +02005150}
5151
Laurent Vivier71811552009-08-03 16:12:18 +02005152static inline int target_rt_setup_ucontext(struct target_ucontext *uc,
Andreas Färber05390242012-02-25 03:37:53 +01005153 CPUM68KState *env)
Laurent Vivier71811552009-08-03 16:12:18 +02005154{
Aurelien Jarno60e99242010-03-29 02:12:51 +02005155 target_greg_t *gregs = uc->tuc_mcontext.gregs;
Laurent Vivier71811552009-08-03 16:12:18 +02005156
Riku Voipio1d8b5122014-04-23 10:26:05 +03005157 __put_user(TARGET_MCONTEXT_VERSION, &uc->tuc_mcontext.version);
5158 __put_user(env->dregs[0], &gregs[0]);
5159 __put_user(env->dregs[1], &gregs[1]);
5160 __put_user(env->dregs[2], &gregs[2]);
5161 __put_user(env->dregs[3], &gregs[3]);
5162 __put_user(env->dregs[4], &gregs[4]);
5163 __put_user(env->dregs[5], &gregs[5]);
5164 __put_user(env->dregs[6], &gregs[6]);
5165 __put_user(env->dregs[7], &gregs[7]);
5166 __put_user(env->aregs[0], &gregs[8]);
5167 __put_user(env->aregs[1], &gregs[9]);
5168 __put_user(env->aregs[2], &gregs[10]);
5169 __put_user(env->aregs[3], &gregs[11]);
5170 __put_user(env->aregs[4], &gregs[12]);
5171 __put_user(env->aregs[5], &gregs[13]);
5172 __put_user(env->aregs[6], &gregs[14]);
5173 __put_user(env->aregs[7], &gregs[15]);
5174 __put_user(env->pc, &gregs[16]);
5175 __put_user(env->sr, &gregs[17]);
Laurent Vivier71811552009-08-03 16:12:18 +02005176
Riku Voipio1d8b5122014-04-23 10:26:05 +03005177 return 0;
Laurent Vivier71811552009-08-03 16:12:18 +02005178}
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01005179
Andreas Färber05390242012-02-25 03:37:53 +01005180static inline int target_rt_restore_ucontext(CPUM68KState *env,
Timothy E Baldwin7ccb84a2016-05-12 18:47:39 +01005181 struct target_ucontext *uc)
Laurent Vivier71811552009-08-03 16:12:18 +02005182{
5183 int temp;
Aurelien Jarno60e99242010-03-29 02:12:51 +02005184 target_greg_t *gregs = uc->tuc_mcontext.gregs;
Laurent Vivier71811552009-08-03 16:12:18 +02005185
Riku Voipio1d8b5122014-04-23 10:26:05 +03005186 __get_user(temp, &uc->tuc_mcontext.version);
Laurent Vivier71811552009-08-03 16:12:18 +02005187 if (temp != TARGET_MCONTEXT_VERSION)
5188 goto badframe;
5189
5190 /* restore passed registers */
Riku Voipio1d8b5122014-04-23 10:26:05 +03005191 __get_user(env->dregs[0], &gregs[0]);
5192 __get_user(env->dregs[1], &gregs[1]);
5193 __get_user(env->dregs[2], &gregs[2]);
5194 __get_user(env->dregs[3], &gregs[3]);
5195 __get_user(env->dregs[4], &gregs[4]);
5196 __get_user(env->dregs[5], &gregs[5]);
5197 __get_user(env->dregs[6], &gregs[6]);
5198 __get_user(env->dregs[7], &gregs[7]);
5199 __get_user(env->aregs[0], &gregs[8]);
5200 __get_user(env->aregs[1], &gregs[9]);
5201 __get_user(env->aregs[2], &gregs[10]);
5202 __get_user(env->aregs[3], &gregs[11]);
5203 __get_user(env->aregs[4], &gregs[12]);
5204 __get_user(env->aregs[5], &gregs[13]);
5205 __get_user(env->aregs[6], &gregs[14]);
5206 __get_user(env->aregs[7], &gregs[15]);
5207 __get_user(env->pc, &gregs[16]);
5208 __get_user(temp, &gregs[17]);
Laurent Vivier71811552009-08-03 16:12:18 +02005209 env->sr = (env->sr & 0xff00) | (temp & 0xff);
5210
Riku Voipio1d8b5122014-04-23 10:26:05 +03005211 return 0;
Laurent Vivier71811552009-08-03 16:12:18 +02005212
5213badframe:
5214 return 1;
5215}
5216
Laurent Vivier492a8742009-08-03 16:12:17 +02005217static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05005218 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01005219 target_sigset_t *set, CPUM68KState *env)
Laurent Vivier492a8742009-08-03 16:12:17 +02005220{
Laurent Vivier71811552009-08-03 16:12:18 +02005221 struct target_rt_sigframe *frame;
5222 abi_ulong frame_addr;
5223 abi_ulong retcode_addr;
5224 abi_ulong info_addr;
5225 abi_ulong uc_addr;
5226 int err = 0;
5227 int i;
5228
5229 frame_addr = get_sigframe(ka, env, sizeof *frame);
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01005230 trace_user_setup_rt_frame(env, frame_addr);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01005231 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
5232 goto give_sigsegv;
5233 }
Laurent Vivier71811552009-08-03 16:12:18 +02005234
Riku Voipio1d8b5122014-04-23 10:26:05 +03005235 __put_user(sig, &frame->sig);
Laurent Vivier71811552009-08-03 16:12:18 +02005236
5237 info_addr = frame_addr + offsetof(struct target_rt_sigframe, info);
Riku Voipio1d8b5122014-04-23 10:26:05 +03005238 __put_user(info_addr, &frame->pinfo);
Laurent Vivier71811552009-08-03 16:12:18 +02005239
5240 uc_addr = frame_addr + offsetof(struct target_rt_sigframe, uc);
Riku Voipio1d8b5122014-04-23 10:26:05 +03005241 __put_user(uc_addr, &frame->puc);
Laurent Vivier71811552009-08-03 16:12:18 +02005242
Peter Maydellf6c7a052015-01-08 12:19:48 +00005243 tswap_siginfo(&frame->info, info);
Laurent Vivier71811552009-08-03 16:12:18 +02005244
5245 /* Create the ucontext */
5246
Riku Voipio1d8b5122014-04-23 10:26:05 +03005247 __put_user(0, &frame->uc.tuc_flags);
5248 __put_user(0, &frame->uc.tuc_link);
5249 __put_user(target_sigaltstack_used.ss_sp,
5250 &frame->uc.tuc_stack.ss_sp);
5251 __put_user(sas_ss_flags(env->aregs[7]),
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01005252 &frame->uc.tuc_stack.ss_flags);
Riku Voipio1d8b5122014-04-23 10:26:05 +03005253 __put_user(target_sigaltstack_used.ss_size,
5254 &frame->uc.tuc_stack.ss_size);
Laurent Vivier71811552009-08-03 16:12:18 +02005255 err |= target_rt_setup_ucontext(&frame->uc, env);
5256
5257 if (err)
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01005258 goto give_sigsegv;
Laurent Vivier71811552009-08-03 16:12:18 +02005259
5260 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
Riku Voipio0188fad2014-04-23 13:34:15 +03005261 __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
Laurent Vivier71811552009-08-03 16:12:18 +02005262 }
5263
5264 /* Set up to return from userspace. */
5265
5266 retcode_addr = frame_addr + offsetof(struct target_sigframe, retcode);
Riku Voipio1d8b5122014-04-23 10:26:05 +03005267 __put_user(retcode_addr, &frame->pretcode);
Laurent Vivier71811552009-08-03 16:12:18 +02005268
5269 /* moveq #,d0; notb d0; trap #0 */
5270
Riku Voipio1d8b5122014-04-23 10:26:05 +03005271 __put_user(0x70004600 + ((TARGET_NR_rt_sigreturn ^ 0xff) << 16),
Peter Maydell1669add2014-12-22 17:47:00 +00005272 (uint32_t *)(frame->retcode + 0));
5273 __put_user(0x4e40, (uint16_t *)(frame->retcode + 4));
Laurent Vivier71811552009-08-03 16:12:18 +02005274
5275 if (err)
5276 goto give_sigsegv;
5277
5278 /* Set up to return from userspace */
5279
5280 env->aregs[7] = frame_addr;
5281 env->pc = ka->_sa_handler;
5282
5283 unlock_user_struct(frame, frame_addr, 1);
5284 return;
5285
5286give_sigsegv:
5287 unlock_user_struct(frame, frame_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02005288 force_sig(TARGET_SIGSEGV);
Laurent Vivier492a8742009-08-03 16:12:17 +02005289}
5290
Andreas Färber05390242012-02-25 03:37:53 +01005291long do_sigreturn(CPUM68KState *env)
Laurent Vivier492a8742009-08-03 16:12:17 +02005292{
5293 struct target_sigframe *frame;
5294 abi_ulong frame_addr = env->aregs[7] - 4;
Anthony Liguoric227f092009-10-01 16:12:16 -05005295 target_sigset_t target_set;
Laurent Vivier492a8742009-08-03 16:12:17 +02005296 sigset_t set;
Timothy E Baldwin7ccb84a2016-05-12 18:47:39 +01005297 int i;
Laurent Vivier492a8742009-08-03 16:12:17 +02005298
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01005299 trace_user_do_sigreturn(env, frame_addr);
Laurent Vivier492a8742009-08-03 16:12:17 +02005300 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
5301 goto badframe;
5302
5303 /* set blocked signals */
5304
Riku Voipiof5f601a2014-04-23 13:00:17 +03005305 __get_user(target_set.sig[0], &frame->sc.sc_mask);
Laurent Vivier492a8742009-08-03 16:12:17 +02005306
5307 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
Riku Voipiof5f601a2014-04-23 13:00:17 +03005308 __get_user(target_set.sig[i], &frame->extramask[i - 1]);
Laurent Vivier492a8742009-08-03 16:12:17 +02005309 }
5310
5311 target_to_host_sigset_internal(&set, &target_set);
Peter Maydell9eede5b2016-05-27 15:51:46 +01005312 set_sigmask(&set);
Laurent Vivier492a8742009-08-03 16:12:17 +02005313
5314 /* restore registers */
5315
Timothy E Baldwin7ccb84a2016-05-12 18:47:39 +01005316 restore_sigcontext(env, &frame->sc);
Laurent Vivier492a8742009-08-03 16:12:17 +02005317
5318 unlock_user_struct(frame, frame_addr, 0);
Timothy E Baldwin7ccb84a2016-05-12 18:47:39 +01005319 return -TARGET_QEMU_ESIGRETURN;
Laurent Vivier492a8742009-08-03 16:12:17 +02005320
5321badframe:
Laurent Vivier492a8742009-08-03 16:12:17 +02005322 force_sig(TARGET_SIGSEGV);
5323 return 0;
5324}
5325
Andreas Färber05390242012-02-25 03:37:53 +01005326long do_rt_sigreturn(CPUM68KState *env)
Laurent Vivier492a8742009-08-03 16:12:17 +02005327{
Laurent Vivier71811552009-08-03 16:12:18 +02005328 struct target_rt_sigframe *frame;
5329 abi_ulong frame_addr = env->aregs[7] - 4;
Anthony Liguoric227f092009-10-01 16:12:16 -05005330 target_sigset_t target_set;
Laurent Vivier71811552009-08-03 16:12:18 +02005331 sigset_t set;
Laurent Vivier71811552009-08-03 16:12:18 +02005332
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01005333 trace_user_do_rt_sigreturn(env, frame_addr);
Laurent Vivier71811552009-08-03 16:12:18 +02005334 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
5335 goto badframe;
5336
5337 target_to_host_sigset_internal(&set, &target_set);
Peter Maydell9eede5b2016-05-27 15:51:46 +01005338 set_sigmask(&set);
Laurent Vivier71811552009-08-03 16:12:18 +02005339
5340 /* restore registers */
5341
Timothy E Baldwin7ccb84a2016-05-12 18:47:39 +01005342 if (target_rt_restore_ucontext(env, &frame->uc))
Laurent Vivier71811552009-08-03 16:12:18 +02005343 goto badframe;
5344
5345 if (do_sigaltstack(frame_addr +
Aurelien Jarno60e99242010-03-29 02:12:51 +02005346 offsetof(struct target_rt_sigframe, uc.tuc_stack),
Laurent Vivier71811552009-08-03 16:12:18 +02005347 0, get_sp_from_cpustate(env)) == -EFAULT)
5348 goto badframe;
5349
5350 unlock_user_struct(frame, frame_addr, 0);
Timothy E Baldwin7ccb84a2016-05-12 18:47:39 +01005351 return -TARGET_QEMU_ESIGRETURN;
Laurent Vivier71811552009-08-03 16:12:18 +02005352
5353badframe:
5354 unlock_user_struct(frame, frame_addr, 0);
5355 force_sig(TARGET_SIGSEGV);
5356 return 0;
Laurent Vivier492a8742009-08-03 16:12:17 +02005357}
5358
Richard Henderson6049f4f2009-12-27 18:30:03 -08005359#elif defined(TARGET_ALPHA)
5360
5361struct target_sigcontext {
5362 abi_long sc_onstack;
5363 abi_long sc_mask;
5364 abi_long sc_pc;
5365 abi_long sc_ps;
5366 abi_long sc_regs[32];
5367 abi_long sc_ownedfp;
5368 abi_long sc_fpregs[32];
5369 abi_ulong sc_fpcr;
5370 abi_ulong sc_fp_control;
5371 abi_ulong sc_reserved1;
5372 abi_ulong sc_reserved2;
5373 abi_ulong sc_ssize;
5374 abi_ulong sc_sbase;
5375 abi_ulong sc_traparg_a0;
5376 abi_ulong sc_traparg_a1;
5377 abi_ulong sc_traparg_a2;
5378 abi_ulong sc_fp_trap_pc;
5379 abi_ulong sc_fp_trigger_sum;
5380 abi_ulong sc_fp_trigger_inst;
5381};
5382
5383struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02005384 abi_ulong tuc_flags;
5385 abi_ulong tuc_link;
5386 abi_ulong tuc_osf_sigmask;
5387 target_stack_t tuc_stack;
5388 struct target_sigcontext tuc_mcontext;
5389 target_sigset_t tuc_sigmask;
Richard Henderson6049f4f2009-12-27 18:30:03 -08005390};
5391
5392struct target_sigframe {
5393 struct target_sigcontext sc;
5394 unsigned int retcode[3];
5395};
5396
5397struct target_rt_sigframe {
5398 target_siginfo_t info;
5399 struct target_ucontext uc;
5400 unsigned int retcode[3];
5401};
5402
5403#define INSN_MOV_R30_R16 0x47fe0410
5404#define INSN_LDI_R0 0x201f0000
5405#define INSN_CALLSYS 0x00000083
5406
Riku Voipio41ecc722014-04-23 11:01:00 +03005407static void setup_sigcontext(struct target_sigcontext *sc, CPUAlphaState *env,
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01005408 abi_ulong frame_addr, target_sigset_t *set)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005409{
Riku Voipio41ecc722014-04-23 11:01:00 +03005410 int i;
Richard Henderson6049f4f2009-12-27 18:30:03 -08005411
Riku Voipio1d8b5122014-04-23 10:26:05 +03005412 __put_user(on_sig_stack(frame_addr), &sc->sc_onstack);
5413 __put_user(set->sig[0], &sc->sc_mask);
5414 __put_user(env->pc, &sc->sc_pc);
5415 __put_user(8, &sc->sc_ps);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005416
5417 for (i = 0; i < 31; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03005418 __put_user(env->ir[i], &sc->sc_regs[i]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005419 }
Riku Voipio1d8b5122014-04-23 10:26:05 +03005420 __put_user(0, &sc->sc_regs[31]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005421
5422 for (i = 0; i < 31; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03005423 __put_user(env->fir[i], &sc->sc_fpregs[i]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005424 }
Riku Voipio1d8b5122014-04-23 10:26:05 +03005425 __put_user(0, &sc->sc_fpregs[31]);
5426 __put_user(cpu_alpha_load_fpcr(env), &sc->sc_fpcr);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005427
Riku Voipio1d8b5122014-04-23 10:26:05 +03005428 __put_user(0, &sc->sc_traparg_a0); /* FIXME */
5429 __put_user(0, &sc->sc_traparg_a1); /* FIXME */
5430 __put_user(0, &sc->sc_traparg_a2); /* FIXME */
Richard Henderson6049f4f2009-12-27 18:30:03 -08005431}
5432
Riku Voipio016d2e12014-04-23 11:19:48 +03005433static void restore_sigcontext(CPUAlphaState *env,
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01005434 struct target_sigcontext *sc)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005435{
5436 uint64_t fpcr;
Riku Voipio016d2e12014-04-23 11:19:48 +03005437 int i;
Richard Henderson6049f4f2009-12-27 18:30:03 -08005438
Riku Voipio1d8b5122014-04-23 10:26:05 +03005439 __get_user(env->pc, &sc->sc_pc);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005440
5441 for (i = 0; i < 31; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03005442 __get_user(env->ir[i], &sc->sc_regs[i]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005443 }
5444 for (i = 0; i < 31; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03005445 __get_user(env->fir[i], &sc->sc_fpregs[i]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005446 }
5447
Riku Voipio1d8b5122014-04-23 10:26:05 +03005448 __get_user(fpcr, &sc->sc_fpcr);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005449 cpu_alpha_store_fpcr(env, fpcr);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005450}
5451
5452static inline abi_ulong get_sigframe(struct target_sigaction *sa,
Andreas Färber05390242012-02-25 03:37:53 +01005453 CPUAlphaState *env,
5454 unsigned long framesize)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005455{
5456 abi_ulong sp = env->ir[IR_SP];
5457
5458 /* This is the X/Open sanctioned signal stack switching. */
5459 if ((sa->sa_flags & TARGET_SA_ONSTACK) != 0 && !sas_ss_flags(sp)) {
5460 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
5461 }
5462 return (sp - framesize) & -32;
5463}
5464
5465static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01005466 target_sigset_t *set, CPUAlphaState *env)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005467{
5468 abi_ulong frame_addr, r26;
5469 struct target_sigframe *frame;
5470 int err = 0;
5471
5472 frame_addr = get_sigframe(ka, env, sizeof(*frame));
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01005473 trace_user_setup_frame(env, frame_addr);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005474 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
5475 goto give_sigsegv;
5476 }
5477
Riku Voipio41ecc722014-04-23 11:01:00 +03005478 setup_sigcontext(&frame->sc, env, frame_addr, set);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005479
5480 if (ka->sa_restorer) {
5481 r26 = ka->sa_restorer;
5482 } else {
Riku Voipio1d8b5122014-04-23 10:26:05 +03005483 __put_user(INSN_MOV_R30_R16, &frame->retcode[0]);
5484 __put_user(INSN_LDI_R0 + TARGET_NR_sigreturn,
5485 &frame->retcode[1]);
5486 __put_user(INSN_CALLSYS, &frame->retcode[2]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005487 /* imb() */
5488 r26 = frame_addr;
5489 }
5490
5491 unlock_user_struct(frame, frame_addr, 1);
5492
5493 if (err) {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01005494give_sigsegv:
Richard Henderson6049f4f2009-12-27 18:30:03 -08005495 if (sig == TARGET_SIGSEGV) {
5496 ka->_sa_handler = TARGET_SIG_DFL;
5497 }
5498 force_sig(TARGET_SIGSEGV);
5499 }
5500
5501 env->ir[IR_RA] = r26;
5502 env->ir[IR_PV] = env->pc = ka->_sa_handler;
5503 env->ir[IR_A0] = sig;
5504 env->ir[IR_A1] = 0;
5505 env->ir[IR_A2] = frame_addr + offsetof(struct target_sigframe, sc);
5506 env->ir[IR_SP] = frame_addr;
5507}
5508
5509static void setup_rt_frame(int sig, struct target_sigaction *ka,
5510 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01005511 target_sigset_t *set, CPUAlphaState *env)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005512{
5513 abi_ulong frame_addr, r26;
5514 struct target_rt_sigframe *frame;
5515 int i, err = 0;
5516
5517 frame_addr = get_sigframe(ka, env, sizeof(*frame));
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01005518 trace_user_setup_rt_frame(env, frame_addr);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005519 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
5520 goto give_sigsegv;
5521 }
5522
Peter Maydellf6c7a052015-01-08 12:19:48 +00005523 tswap_siginfo(&frame->info, info);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005524
Riku Voipio1d8b5122014-04-23 10:26:05 +03005525 __put_user(0, &frame->uc.tuc_flags);
5526 __put_user(0, &frame->uc.tuc_link);
5527 __put_user(set->sig[0], &frame->uc.tuc_osf_sigmask);
5528 __put_user(target_sigaltstack_used.ss_sp,
5529 &frame->uc.tuc_stack.ss_sp);
5530 __put_user(sas_ss_flags(env->ir[IR_SP]),
5531 &frame->uc.tuc_stack.ss_flags);
5532 __put_user(target_sigaltstack_used.ss_size,
5533 &frame->uc.tuc_stack.ss_size);
Riku Voipio41ecc722014-04-23 11:01:00 +03005534 setup_sigcontext(&frame->uc.tuc_mcontext, env, frame_addr, set);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005535 for (i = 0; i < TARGET_NSIG_WORDS; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03005536 __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005537 }
5538
5539 if (ka->sa_restorer) {
5540 r26 = ka->sa_restorer;
5541 } else {
Riku Voipio1d8b5122014-04-23 10:26:05 +03005542 __put_user(INSN_MOV_R30_R16, &frame->retcode[0]);
5543 __put_user(INSN_LDI_R0 + TARGET_NR_rt_sigreturn,
5544 &frame->retcode[1]);
5545 __put_user(INSN_CALLSYS, &frame->retcode[2]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005546 /* imb(); */
5547 r26 = frame_addr;
5548 }
5549
5550 if (err) {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01005551give_sigsegv:
5552 if (sig == TARGET_SIGSEGV) {
Richard Henderson6049f4f2009-12-27 18:30:03 -08005553 ka->_sa_handler = TARGET_SIG_DFL;
5554 }
5555 force_sig(TARGET_SIGSEGV);
5556 }
5557
5558 env->ir[IR_RA] = r26;
5559 env->ir[IR_PV] = env->pc = ka->_sa_handler;
5560 env->ir[IR_A0] = sig;
5561 env->ir[IR_A1] = frame_addr + offsetof(struct target_rt_sigframe, info);
5562 env->ir[IR_A2] = frame_addr + offsetof(struct target_rt_sigframe, uc);
5563 env->ir[IR_SP] = frame_addr;
5564}
5565
Andreas Färber05390242012-02-25 03:37:53 +01005566long do_sigreturn(CPUAlphaState *env)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005567{
5568 struct target_sigcontext *sc;
5569 abi_ulong sc_addr = env->ir[IR_A0];
5570 target_sigset_t target_set;
5571 sigset_t set;
5572
5573 if (!lock_user_struct(VERIFY_READ, sc, sc_addr, 1)) {
5574 goto badframe;
5575 }
5576
5577 target_sigemptyset(&target_set);
Riku Voipiof5f601a2014-04-23 13:00:17 +03005578 __get_user(target_set.sig[0], &sc->sc_mask);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005579
5580 target_to_host_sigset_internal(&set, &target_set);
Peter Maydell9eede5b2016-05-27 15:51:46 +01005581 set_sigmask(&set);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005582
Riku Voipio016d2e12014-04-23 11:19:48 +03005583 restore_sigcontext(env, sc);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005584 unlock_user_struct(sc, sc_addr, 0);
Timothy E Baldwin338c8582016-05-12 18:47:36 +01005585 return -TARGET_QEMU_ESIGRETURN;
Richard Henderson6049f4f2009-12-27 18:30:03 -08005586
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01005587badframe:
Richard Henderson6049f4f2009-12-27 18:30:03 -08005588 force_sig(TARGET_SIGSEGV);
5589}
5590
Andreas Färber05390242012-02-25 03:37:53 +01005591long do_rt_sigreturn(CPUAlphaState *env)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005592{
5593 abi_ulong frame_addr = env->ir[IR_A0];
5594 struct target_rt_sigframe *frame;
5595 sigset_t set;
5596
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01005597 trace_user_do_rt_sigreturn(env, frame_addr);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005598 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
5599 goto badframe;
5600 }
Aurelien Jarno60e99242010-03-29 02:12:51 +02005601 target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
Peter Maydell9eede5b2016-05-27 15:51:46 +01005602 set_sigmask(&set);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005603
Riku Voipio016d2e12014-04-23 11:19:48 +03005604 restore_sigcontext(env, &frame->uc.tuc_mcontext);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005605 if (do_sigaltstack(frame_addr + offsetof(struct target_rt_sigframe,
Aurelien Jarno60e99242010-03-29 02:12:51 +02005606 uc.tuc_stack),
Richard Henderson6049f4f2009-12-27 18:30:03 -08005607 0, env->ir[IR_SP]) == -EFAULT) {
5608 goto badframe;
5609 }
5610
5611 unlock_user_struct(frame, frame_addr, 0);
Timothy E Baldwin338c8582016-05-12 18:47:36 +01005612 return -TARGET_QEMU_ESIGRETURN;
Richard Henderson6049f4f2009-12-27 18:30:03 -08005613
5614
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01005615badframe:
Richard Henderson6049f4f2009-12-27 18:30:03 -08005616 unlock_user_struct(frame, frame_addr, 0);
5617 force_sig(TARGET_SIGSEGV);
5618}
5619
Chen Gangbf0f60a2015-09-27 08:10:18 +08005620#elif defined(TARGET_TILEGX)
5621
5622struct target_sigcontext {
5623 union {
5624 /* General-purpose registers. */
5625 abi_ulong gregs[56];
5626 struct {
5627 abi_ulong __gregs[53];
5628 abi_ulong tp; /* Aliases gregs[TREG_TP]. */
5629 abi_ulong sp; /* Aliases gregs[TREG_SP]. */
5630 abi_ulong lr; /* Aliases gregs[TREG_LR]. */
5631 };
5632 };
5633 abi_ulong pc; /* Program counter. */
5634 abi_ulong ics; /* In Interrupt Critical Section? */
5635 abi_ulong faultnum; /* Fault number. */
5636 abi_ulong pad[5];
5637};
5638
5639struct target_ucontext {
5640 abi_ulong tuc_flags;
5641 abi_ulong tuc_link;
5642 target_stack_t tuc_stack;
5643 struct target_sigcontext tuc_mcontext;
5644 target_sigset_t tuc_sigmask; /* mask last for extensibility */
5645};
5646
5647struct target_rt_sigframe {
5648 unsigned char save_area[16]; /* caller save area */
5649 struct target_siginfo info;
5650 struct target_ucontext uc;
Chen Gangf1d9d102016-03-29 21:53:49 +08005651 abi_ulong retcode[2];
Chen Gangbf0f60a2015-09-27 08:10:18 +08005652};
5653
Chen Gangf1d9d102016-03-29 21:53:49 +08005654#define INSN_MOVELI_R10_139 0x00045fe551483000ULL /* { moveli r10, 139 } */
5655#define INSN_SWINT1 0x286b180051485000ULL /* { swint1 } */
5656
5657
Chen Gangbf0f60a2015-09-27 08:10:18 +08005658static void setup_sigcontext(struct target_sigcontext *sc,
5659 CPUArchState *env, int signo)
5660{
5661 int i;
5662
5663 for (i = 0; i < TILEGX_R_COUNT; ++i) {
5664 __put_user(env->regs[i], &sc->gregs[i]);
5665 }
5666
5667 __put_user(env->pc, &sc->pc);
5668 __put_user(0, &sc->ics);
5669 __put_user(signo, &sc->faultnum);
5670}
5671
5672static void restore_sigcontext(CPUTLGState *env, struct target_sigcontext *sc)
5673{
5674 int i;
5675
5676 for (i = 0; i < TILEGX_R_COUNT; ++i) {
5677 __get_user(env->regs[i], &sc->gregs[i]);
5678 }
5679
5680 __get_user(env->pc, &sc->pc);
5681}
5682
5683static abi_ulong get_sigframe(struct target_sigaction *ka, CPUArchState *env,
5684 size_t frame_size)
5685{
5686 unsigned long sp = env->regs[TILEGX_R_SP];
5687
5688 if (on_sig_stack(sp) && !likely(on_sig_stack(sp - frame_size))) {
5689 return -1UL;
5690 }
5691
5692 if ((ka->sa_flags & SA_ONSTACK) && !sas_ss_flags(sp)) {
5693 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
5694 }
5695
5696 sp -= frame_size;
5697 sp &= -16UL;
5698 return sp;
5699}
5700
5701static void setup_rt_frame(int sig, struct target_sigaction *ka,
5702 target_siginfo_t *info,
5703 target_sigset_t *set, CPUArchState *env)
5704{
5705 abi_ulong frame_addr;
5706 struct target_rt_sigframe *frame;
5707 unsigned long restorer;
5708
5709 frame_addr = get_sigframe(ka, env, sizeof(*frame));
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01005710 trace_user_setup_rt_frame(env, frame_addr);
Chen Gangbf0f60a2015-09-27 08:10:18 +08005711 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
5712 goto give_sigsegv;
5713 }
5714
5715 /* Always write at least the signal number for the stack backtracer. */
5716 if (ka->sa_flags & TARGET_SA_SIGINFO) {
5717 /* At sigreturn time, restore the callee-save registers too. */
5718 tswap_siginfo(&frame->info, info);
5719 /* regs->flags |= PT_FLAGS_RESTORE_REGS; FIXME: we can skip it? */
5720 } else {
5721 __put_user(info->si_signo, &frame->info.si_signo);
5722 }
5723
5724 /* Create the ucontext. */
5725 __put_user(0, &frame->uc.tuc_flags);
5726 __put_user(0, &frame->uc.tuc_link);
5727 __put_user(target_sigaltstack_used.ss_sp, &frame->uc.tuc_stack.ss_sp);
5728 __put_user(sas_ss_flags(env->regs[TILEGX_R_SP]),
5729 &frame->uc.tuc_stack.ss_flags);
5730 __put_user(target_sigaltstack_used.ss_size, &frame->uc.tuc_stack.ss_size);
5731 setup_sigcontext(&frame->uc.tuc_mcontext, env, info->si_signo);
5732
Chen Gangbf0f60a2015-09-27 08:10:18 +08005733 if (ka->sa_flags & TARGET_SA_RESTORER) {
Chen Gangf1d9d102016-03-29 21:53:49 +08005734 restorer = (unsigned long) ka->sa_restorer;
5735 } else {
5736 __put_user(INSN_MOVELI_R10_139, &frame->retcode[0]);
5737 __put_user(INSN_SWINT1, &frame->retcode[1]);
5738 restorer = frame_addr + offsetof(struct target_rt_sigframe, retcode);
Chen Gangbf0f60a2015-09-27 08:10:18 +08005739 }
5740 env->pc = (unsigned long) ka->_sa_handler;
5741 env->regs[TILEGX_R_SP] = (unsigned long) frame;
5742 env->regs[TILEGX_R_LR] = restorer;
5743 env->regs[0] = (unsigned long) sig;
5744 env->regs[1] = (unsigned long) &frame->info;
5745 env->regs[2] = (unsigned long) &frame->uc;
5746 /* regs->flags |= PT_FLAGS_CALLER_SAVES; FIXME: we can skip it? */
5747
5748 unlock_user_struct(frame, frame_addr, 1);
5749 return;
5750
5751give_sigsegv:
5752 if (sig == TARGET_SIGSEGV) {
5753 ka->_sa_handler = TARGET_SIG_DFL;
5754 }
5755 force_sig(TARGET_SIGSEGV /* , current */);
5756}
5757
5758long do_rt_sigreturn(CPUTLGState *env)
5759{
5760 abi_ulong frame_addr = env->regs[TILEGX_R_SP];
5761 struct target_rt_sigframe *frame;
5762 sigset_t set;
5763
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01005764 trace_user_do_rt_sigreturn(env, frame_addr);
Chen Gangbf0f60a2015-09-27 08:10:18 +08005765 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
5766 goto badframe;
5767 }
5768 target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
Peter Maydell9eede5b2016-05-27 15:51:46 +01005769 set_sigmask(&set);
Chen Gangbf0f60a2015-09-27 08:10:18 +08005770
5771 restore_sigcontext(env, &frame->uc.tuc_mcontext);
5772 if (do_sigaltstack(frame_addr + offsetof(struct target_rt_sigframe,
5773 uc.tuc_stack),
5774 0, env->regs[TILEGX_R_SP]) == -EFAULT) {
5775 goto badframe;
5776 }
5777
5778 unlock_user_struct(frame, frame_addr, 0);
Peter Maydella9175162016-05-12 18:47:42 +01005779 return -TARGET_QEMU_ESIGRETURN;
Chen Gangbf0f60a2015-09-27 08:10:18 +08005780
5781
5782 badframe:
5783 unlock_user_struct(frame, frame_addr, 0);
5784 force_sig(TARGET_SIGSEGV);
5785}
5786
bellardb346ff42003-06-15 20:05:50 +00005787#else
5788
pbrook624f7972008-05-31 16:11:38 +00005789static void setup_frame(int sig, struct target_sigaction *ka,
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01005790 target_sigset_t *set, CPUArchState *env)
bellardb346ff42003-06-15 20:05:50 +00005791{
5792 fprintf(stderr, "setup_frame: not implemented\n");
5793}
5794
pbrook624f7972008-05-31 16:11:38 +00005795static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05005796 target_siginfo_t *info,
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01005797 target_sigset_t *set, CPUArchState *env)
bellardb346ff42003-06-15 20:05:50 +00005798{
5799 fprintf(stderr, "setup_rt_frame: not implemented\n");
5800}
5801
Andreas Färber9349b4f2012-03-14 01:38:32 +01005802long do_sigreturn(CPUArchState *env)
bellardb346ff42003-06-15 20:05:50 +00005803{
5804 fprintf(stderr, "do_sigreturn: not implemented\n");
bellardf8b0aa22007-11-11 23:03:42 +00005805 return -TARGET_ENOSYS;
bellardb346ff42003-06-15 20:05:50 +00005806}
5807
Andreas Färber9349b4f2012-03-14 01:38:32 +01005808long do_rt_sigreturn(CPUArchState *env)
bellardb346ff42003-06-15 20:05:50 +00005809{
5810 fprintf(stderr, "do_rt_sigreturn: not implemented\n");
bellardf8b0aa22007-11-11 23:03:42 +00005811 return -TARGET_ENOSYS;
bellardb346ff42003-06-15 20:05:50 +00005812}
5813
bellard66fb9762003-03-23 01:06:05 +00005814#endif
5815
Peter Maydelleb552502016-05-27 15:51:43 +01005816static void handle_pending_signal(CPUArchState *cpu_env, int sig)
5817{
5818 CPUState *cpu = ENV_GET_CPU(cpu_env);
5819 abi_ulong handler;
Peter Maydell3d3efba2016-05-27 15:51:49 +01005820 sigset_t set;
Peter Maydelleb552502016-05-27 15:51:43 +01005821 target_sigset_t target_old_set;
5822 struct target_sigaction *sa;
5823 struct sigqueue *q;
5824 TaskState *ts = cpu->opaque;
5825 struct emulated_sigtable *k = &ts->sigtab[sig - 1];
5826
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01005827 trace_user_handle_signal(cpu_env, sig);
bellard66fb9762003-03-23 01:06:05 +00005828 /* dequeue signal */
5829 q = k->first;
5830 k->first = q->next;
5831 if (!k->first)
5832 k->pending = 0;
ths3b46e622007-09-17 08:09:54 +00005833
Andreas Färberdb6b81d2013-06-27 19:49:31 +02005834 sig = gdb_handlesig(cpu, sig);
bellard1fddef42005-04-17 19:16:13 +00005835 if (!sig) {
aurel32ca587a82008-12-18 22:44:13 +00005836 sa = NULL;
5837 handler = TARGET_SIG_IGN;
5838 } else {
5839 sa = &sigact_table[sig - 1];
5840 handler = sa->_sa_handler;
bellard1fddef42005-04-17 19:16:13 +00005841 }
bellard66fb9762003-03-23 01:06:05 +00005842
Peter Maydell3d3efba2016-05-27 15:51:49 +01005843 if (sig == TARGET_SIGSEGV && sigismember(&ts->signal_mask, SIGSEGV)) {
Peter Maydella7ec0f92014-03-14 14:36:56 +00005844 /* Guest has blocked SIGSEGV but we got one anyway. Assume this
5845 * is a forced SIGSEGV (ie one the kernel handles via force_sig_info
5846 * because it got a real MMU fault), and treat as if default handler.
5847 */
5848 handler = TARGET_SIG_DFL;
5849 }
5850
bellard66fb9762003-03-23 01:06:05 +00005851 if (handler == TARGET_SIG_DFL) {
aurel32ca587a82008-12-18 22:44:13 +00005852 /* default handler : ignore some signal. The other are job control or fatal */
5853 if (sig == TARGET_SIGTSTP || sig == TARGET_SIGTTIN || sig == TARGET_SIGTTOU) {
5854 kill(getpid(),SIGSTOP);
5855 } else if (sig != TARGET_SIGCHLD &&
5856 sig != TARGET_SIGURG &&
5857 sig != TARGET_SIGWINCH &&
5858 sig != TARGET_SIGCONT) {
bellard66fb9762003-03-23 01:06:05 +00005859 force_sig(sig);
5860 }
5861 } else if (handler == TARGET_SIG_IGN) {
5862 /* ignore sig */
5863 } else if (handler == TARGET_SIG_ERR) {
5864 force_sig(sig);
5865 } else {
bellard9de5e442003-03-23 16:49:39 +00005866 /* compute the blocked signals during the handler execution */
Peter Maydell3d3efba2016-05-27 15:51:49 +01005867 sigset_t *blocked_set;
5868
pbrook624f7972008-05-31 16:11:38 +00005869 target_to_host_sigset(&set, &sa->sa_mask);
bellard9de5e442003-03-23 16:49:39 +00005870 /* SA_NODEFER indicates that the current signal should not be
5871 blocked during the handler */
pbrook624f7972008-05-31 16:11:38 +00005872 if (!(sa->sa_flags & TARGET_SA_NODEFER))
bellard9de5e442003-03-23 16:49:39 +00005873 sigaddset(&set, target_to_host_signal(sig));
ths3b46e622007-09-17 08:09:54 +00005874
bellard9de5e442003-03-23 16:49:39 +00005875 /* save the previous blocked signal state to restore it at the
5876 end of the signal execution (see do_sigreturn) */
Peter Maydell3d3efba2016-05-27 15:51:49 +01005877 host_to_target_sigset_internal(&target_old_set, &ts->signal_mask);
5878
5879 /* block signals in the handler */
5880 blocked_set = ts->in_sigsuspend ?
5881 &ts->sigsuspend_mask : &ts->signal_mask;
5882 sigorset(&ts->signal_mask, blocked_set, &set);
5883 ts->in_sigsuspend = 0;
bellard9de5e442003-03-23 16:49:39 +00005884
bellardbc8a22c2003-03-30 21:02:40 +00005885 /* if the CPU is in VM86 mode, we restore the 32 bit values */
j_mayer84409dd2007-04-06 08:56:50 +00005886#if defined(TARGET_I386) && !defined(TARGET_X86_64)
bellardbc8a22c2003-03-30 21:02:40 +00005887 {
5888 CPUX86State *env = cpu_env;
5889 if (env->eflags & VM_MASK)
5890 save_v86_state(env);
5891 }
5892#endif
bellard9de5e442003-03-23 16:49:39 +00005893 /* prepare the stack frame of the virtual CPU */
Chen Gangd0924a22015-09-12 23:32:30 +08005894#if defined(TARGET_ABI_MIPSN32) || defined(TARGET_ABI_MIPSN64) \
Chen Gangbf0f60a2015-09-27 08:10:18 +08005895 || defined(TARGET_OPENRISC) || defined(TARGET_TILEGX)
Richard Hendersonff970902013-02-10 10:30:42 -08005896 /* These targets do not have traditional signals. */
5897 setup_rt_frame(sig, sa, &q->info, &target_old_set, cpu_env);
5898#else
pbrook624f7972008-05-31 16:11:38 +00005899 if (sa->sa_flags & TARGET_SA_SIGINFO)
5900 setup_rt_frame(sig, sa, &q->info, &target_old_set, cpu_env);
bellard66fb9762003-03-23 01:06:05 +00005901 else
pbrook624f7972008-05-31 16:11:38 +00005902 setup_frame(sig, sa, &target_old_set, cpu_env);
Richard Hendersonff970902013-02-10 10:30:42 -08005903#endif
Peter Maydell7ec87e02016-05-27 15:51:45 +01005904 if (sa->sa_flags & TARGET_SA_RESETHAND) {
pbrook624f7972008-05-31 16:11:38 +00005905 sa->_sa_handler = TARGET_SIG_DFL;
Peter Maydell7ec87e02016-05-27 15:51:45 +01005906 }
bellard31e31b82003-02-18 22:55:36 +00005907 }
bellard66fb9762003-03-23 01:06:05 +00005908 if (q != &k->info)
pbrook624f7972008-05-31 16:11:38 +00005909 free_sigqueue(cpu_env, q);
bellard31e31b82003-02-18 22:55:36 +00005910}
Peter Maydelle902d582016-05-27 15:51:44 +01005911
5912void process_pending_signals(CPUArchState *cpu_env)
5913{
5914 CPUState *cpu = ENV_GET_CPU(cpu_env);
5915 int sig;
5916 TaskState *ts = cpu->opaque;
Peter Maydell3d3efba2016-05-27 15:51:49 +01005917 sigset_t set;
5918 sigset_t *blocked_set;
Peter Maydelle902d582016-05-27 15:51:44 +01005919
Peter Maydell3d3efba2016-05-27 15:51:49 +01005920 while (atomic_read(&ts->signal_pending)) {
5921 /* FIXME: This is not threadsafe. */
5922 sigfillset(&set);
5923 sigprocmask(SIG_SETMASK, &set, 0);
Peter Maydelle902d582016-05-27 15:51:44 +01005924
Peter Maydell3d3efba2016-05-27 15:51:49 +01005925 for (sig = 1; sig <= TARGET_NSIG; sig++) {
5926 blocked_set = ts->in_sigsuspend ?
5927 &ts->sigsuspend_mask : &ts->signal_mask;
5928
5929 if (ts->sigtab[sig - 1].pending &&
5930 (!sigismember(blocked_set,
5931 target_to_host_signal_table[sig])
5932 || sig == TARGET_SIGSEGV)) {
5933 handle_pending_signal(cpu_env, sig);
5934 /* Restart scan from the beginning */
5935 sig = 1;
5936 }
Peter Maydelle902d582016-05-27 15:51:44 +01005937 }
Peter Maydell3d3efba2016-05-27 15:51:49 +01005938
5939 /* if no signal is pending, unblock signals and recheck (the act
5940 * of unblocking might cause us to take another host signal which
5941 * will set signal_pending again).
5942 */
5943 atomic_set(&ts->signal_pending, 0);
5944 ts->in_sigsuspend = 0;
5945 set = ts->signal_mask;
5946 sigdelset(&set, SIGSEGV);
5947 sigdelset(&set, SIGBUS);
5948 sigprocmask(SIG_SETMASK, &set, 0);
Peter Maydelle902d582016-05-27 15:51:44 +01005949 }
Peter Maydell3d3efba2016-05-27 15:51:49 +01005950 ts->in_sigsuspend = 0;
Peter Maydelle902d582016-05-27 15:51:44 +01005951}