blob: 61c114544633e20613f91bb0063f370b7e21bc63 [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"
Peter Maydella70dadc2016-05-27 15:51:59 +010020#include "qemu/bitops.h"
bellard31e31b82003-02-18 22:55:36 +000021#include <sys/ucontext.h>
Mika Westerbergedf8e2a2009-04-07 09:57:11 +030022#include <sys/resource.h>
bellard31e31b82003-02-18 22:55:36 +000023
bellard3ef693a2003-03-23 20:17:16 +000024#include "qemu.h"
blueswir17d99a002009-01-14 19:00:36 +000025#include "qemu-common.h"
blueswir1992f48a2007-10-14 16:27:31 +000026#include "target_signal.h"
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +010027#include "trace.h"
bellard66fb9762003-03-23 01:06:05 +000028
blueswir1249c4c32008-10-05 11:09:37 +000029static struct target_sigaltstack target_sigaltstack_used = {
thsa04e1342007-09-27 13:57:58 +000030 .ss_sp = 0,
31 .ss_size = 0,
32 .ss_flags = TARGET_SS_DISABLE,
33};
34
pbrook624f7972008-05-31 16:11:38 +000035static struct target_sigaction sigact_table[TARGET_NSIG];
bellard31e31b82003-02-18 22:55:36 +000036
ths5fafdf22007-09-16 21:08:06 +000037static void host_signal_handler(int host_signum, siginfo_t *info,
bellard66fb9762003-03-23 01:06:05 +000038 void *puc);
39
Arnaud Patard3ca05582009-03-30 01:18:20 +020040static uint8_t host_to_target_signal_table[_NSIG] = {
bellard9e5f5282003-07-13 17:33:54 +000041 [SIGHUP] = TARGET_SIGHUP,
42 [SIGINT] = TARGET_SIGINT,
43 [SIGQUIT] = TARGET_SIGQUIT,
44 [SIGILL] = TARGET_SIGILL,
45 [SIGTRAP] = TARGET_SIGTRAP,
46 [SIGABRT] = TARGET_SIGABRT,
bellard01e3b762003-09-30 21:10:14 +000047/* [SIGIOT] = TARGET_SIGIOT,*/
bellard9e5f5282003-07-13 17:33:54 +000048 [SIGBUS] = TARGET_SIGBUS,
49 [SIGFPE] = TARGET_SIGFPE,
50 [SIGKILL] = TARGET_SIGKILL,
51 [SIGUSR1] = TARGET_SIGUSR1,
52 [SIGSEGV] = TARGET_SIGSEGV,
53 [SIGUSR2] = TARGET_SIGUSR2,
54 [SIGPIPE] = TARGET_SIGPIPE,
55 [SIGALRM] = TARGET_SIGALRM,
56 [SIGTERM] = TARGET_SIGTERM,
57#ifdef SIGSTKFLT
58 [SIGSTKFLT] = TARGET_SIGSTKFLT,
59#endif
60 [SIGCHLD] = TARGET_SIGCHLD,
61 [SIGCONT] = TARGET_SIGCONT,
62 [SIGSTOP] = TARGET_SIGSTOP,
63 [SIGTSTP] = TARGET_SIGTSTP,
64 [SIGTTIN] = TARGET_SIGTTIN,
65 [SIGTTOU] = TARGET_SIGTTOU,
66 [SIGURG] = TARGET_SIGURG,
67 [SIGXCPU] = TARGET_SIGXCPU,
68 [SIGXFSZ] = TARGET_SIGXFSZ,
69 [SIGVTALRM] = TARGET_SIGVTALRM,
70 [SIGPROF] = TARGET_SIGPROF,
71 [SIGWINCH] = TARGET_SIGWINCH,
72 [SIGIO] = TARGET_SIGIO,
73 [SIGPWR] = TARGET_SIGPWR,
74 [SIGSYS] = TARGET_SIGSYS,
75 /* next signals stay the same */
pbrook624f7972008-05-31 16:11:38 +000076 /* Nasty hack: Reverse SIGRTMIN and SIGRTMAX to avoid overlap with
Dong Xu Wangb4916d72011-11-22 18:06:17 +080077 host libpthread signals. This assumes no one actually uses SIGRTMAX :-/
pbrook624f7972008-05-31 16:11:38 +000078 To fix this properly we need to do manual signal delivery multiplexed
79 over a single host signal. */
80 [__SIGRTMIN] = __SIGRTMAX,
81 [__SIGRTMAX] = __SIGRTMIN,
bellard9e5f5282003-07-13 17:33:54 +000082};
Arnaud Patard3ca05582009-03-30 01:18:20 +020083static uint8_t target_to_host_signal_table[_NSIG];
bellard9e5f5282003-07-13 17:33:54 +000084
thsa04e1342007-09-27 13:57:58 +000085static inline int on_sig_stack(unsigned long sp)
86{
87 return (sp - target_sigaltstack_used.ss_sp
88 < target_sigaltstack_used.ss_size);
89}
90
91static inline int sas_ss_flags(unsigned long sp)
92{
93 return (target_sigaltstack_used.ss_size == 0 ? SS_DISABLE
94 : on_sig_stack(sp) ? SS_ONSTACK : 0);
95}
96
pbrook1d9d8b52009-04-16 15:17:02 +000097int host_to_target_signal(int sig)
bellard31e31b82003-02-18 22:55:36 +000098{
Andreas Schwab167c50d2013-07-02 14:04:12 +010099 if (sig < 0 || sig >= _NSIG)
pbrook4cb05962008-05-30 18:05:19 +0000100 return sig;
bellard9e5f5282003-07-13 17:33:54 +0000101 return host_to_target_signal_table[sig];
bellard31e31b82003-02-18 22:55:36 +0000102}
103
pbrook4cb05962008-05-30 18:05:19 +0000104int target_to_host_signal(int sig)
bellard31e31b82003-02-18 22:55:36 +0000105{
Andreas Schwab167c50d2013-07-02 14:04:12 +0100106 if (sig < 0 || sig >= _NSIG)
pbrook4cb05962008-05-30 18:05:19 +0000107 return sig;
bellard9e5f5282003-07-13 17:33:54 +0000108 return target_to_host_signal_table[sig];
bellard31e31b82003-02-18 22:55:36 +0000109}
110
Anthony Liguoric227f092009-10-01 16:12:16 -0500111static inline void target_sigemptyset(target_sigset_t *set)
pbrookf5545b52008-05-30 22:37:07 +0000112{
113 memset(set, 0, sizeof(*set));
114}
115
Anthony Liguoric227f092009-10-01 16:12:16 -0500116static inline void target_sigaddset(target_sigset_t *set, int signum)
pbrookf5545b52008-05-30 22:37:07 +0000117{
118 signum--;
119 abi_ulong mask = (abi_ulong)1 << (signum % TARGET_NSIG_BPW);
120 set->sig[signum / TARGET_NSIG_BPW] |= mask;
121}
122
Anthony Liguoric227f092009-10-01 16:12:16 -0500123static inline int target_sigismember(const target_sigset_t *set, int signum)
pbrookf5545b52008-05-30 22:37:07 +0000124{
125 signum--;
126 abi_ulong mask = (abi_ulong)1 << (signum % TARGET_NSIG_BPW);
127 return ((set->sig[signum / TARGET_NSIG_BPW] & mask) != 0);
128}
129
Anthony Liguoric227f092009-10-01 16:12:16 -0500130static void host_to_target_sigset_internal(target_sigset_t *d,
bellard92319442004-06-19 16:58:13 +0000131 const sigset_t *s)
bellard66fb9762003-03-23 01:06:05 +0000132{
133 int i;
pbrookf5545b52008-05-30 22:37:07 +0000134 target_sigemptyset(d);
135 for (i = 1; i <= TARGET_NSIG; i++) {
136 if (sigismember(s, i)) {
137 target_sigaddset(d, host_to_target_signal(i));
138 }
bellard9e5f5282003-07-13 17:33:54 +0000139 }
bellard66fb9762003-03-23 01:06:05 +0000140}
141
Anthony Liguoric227f092009-10-01 16:12:16 -0500142void host_to_target_sigset(target_sigset_t *d, const sigset_t *s)
bellard92319442004-06-19 16:58:13 +0000143{
Anthony Liguoric227f092009-10-01 16:12:16 -0500144 target_sigset_t d1;
bellard92319442004-06-19 16:58:13 +0000145 int i;
146
147 host_to_target_sigset_internal(&d1, s);
148 for(i = 0;i < TARGET_NSIG_WORDS; i++)
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200149 d->sig[i] = tswapal(d1.sig[i]);
bellard92319442004-06-19 16:58:13 +0000150}
151
blueswir18fcd3692008-08-17 20:26:25 +0000152static void target_to_host_sigset_internal(sigset_t *d,
Anthony Liguoric227f092009-10-01 16:12:16 -0500153 const target_sigset_t *s)
bellard66fb9762003-03-23 01:06:05 +0000154{
155 int i;
pbrookf5545b52008-05-30 22:37:07 +0000156 sigemptyset(d);
157 for (i = 1; i <= TARGET_NSIG; i++) {
158 if (target_sigismember(s, i)) {
159 sigaddset(d, target_to_host_signal(i));
160 }
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100161 }
bellard66fb9762003-03-23 01:06:05 +0000162}
163
Anthony Liguoric227f092009-10-01 16:12:16 -0500164void target_to_host_sigset(sigset_t *d, const target_sigset_t *s)
bellard92319442004-06-19 16:58:13 +0000165{
Anthony Liguoric227f092009-10-01 16:12:16 -0500166 target_sigset_t s1;
bellard92319442004-06-19 16:58:13 +0000167 int i;
168
169 for(i = 0;i < TARGET_NSIG_WORDS; i++)
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200170 s1.sig[i] = tswapal(s->sig[i]);
bellard92319442004-06-19 16:58:13 +0000171 target_to_host_sigset_internal(d, &s1);
172}
ths3b46e622007-09-17 08:09:54 +0000173
blueswir1992f48a2007-10-14 16:27:31 +0000174void host_to_target_old_sigset(abi_ulong *old_sigset,
bellard66fb9762003-03-23 01:06:05 +0000175 const sigset_t *sigset)
176{
Anthony Liguoric227f092009-10-01 16:12:16 -0500177 target_sigset_t d;
bellard9e5f5282003-07-13 17:33:54 +0000178 host_to_target_sigset(&d, sigset);
179 *old_sigset = d.sig[0];
bellard66fb9762003-03-23 01:06:05 +0000180}
181
ths5fafdf22007-09-16 21:08:06 +0000182void target_to_host_old_sigset(sigset_t *sigset,
blueswir1992f48a2007-10-14 16:27:31 +0000183 const abi_ulong *old_sigset)
bellard66fb9762003-03-23 01:06:05 +0000184{
Anthony Liguoric227f092009-10-01 16:12:16 -0500185 target_sigset_t d;
bellard9e5f5282003-07-13 17:33:54 +0000186 int i;
187
188 d.sig[0] = *old_sigset;
189 for(i = 1;i < TARGET_NSIG_WORDS; i++)
190 d.sig[i] = 0;
191 target_to_host_sigset(sigset, &d);
bellard66fb9762003-03-23 01:06:05 +0000192}
193
Peter Maydell3d3efba2016-05-27 15:51:49 +0100194int block_signals(void)
195{
196 TaskState *ts = (TaskState *)thread_cpu->opaque;
197 sigset_t set;
198 int pending;
199
200 /* It's OK to block everything including SIGSEGV, because we won't
201 * run any further guest code before unblocking signals in
202 * process_pending_signals().
203 */
204 sigfillset(&set);
205 sigprocmask(SIG_SETMASK, &set, 0);
206
207 pending = atomic_xchg(&ts->signal_pending, 1);
208
209 return pending;
210}
211
Alex Barcelo1c275922014-03-14 14:36:55 +0000212/* Wrapper for sigprocmask function
213 * Emulates a sigprocmask in a safe way for the guest. Note that set and oldset
Peter Maydell3d3efba2016-05-27 15:51:49 +0100214 * are host signal set, not guest ones. Returns -TARGET_ERESTARTSYS if
215 * a signal was already pending and the syscall must be restarted, or
216 * 0 on success.
217 * If set is NULL, this is guaranteed not to fail.
Alex Barcelo1c275922014-03-14 14:36:55 +0000218 */
219int do_sigprocmask(int how, const sigset_t *set, sigset_t *oldset)
220{
Peter Maydell3d3efba2016-05-27 15:51:49 +0100221 TaskState *ts = (TaskState *)thread_cpu->opaque;
222
223 if (oldset) {
224 *oldset = ts->signal_mask;
225 }
Peter Maydella7ec0f92014-03-14 14:36:56 +0000226
227 if (set) {
Peter Maydell3d3efba2016-05-27 15:51:49 +0100228 int i;
Peter Maydella7ec0f92014-03-14 14:36:56 +0000229
Peter Maydell3d3efba2016-05-27 15:51:49 +0100230 if (block_signals()) {
231 return -TARGET_ERESTARTSYS;
232 }
Peter Maydella7ec0f92014-03-14 14:36:56 +0000233
234 switch (how) {
235 case SIG_BLOCK:
Peter Maydell3d3efba2016-05-27 15:51:49 +0100236 sigorset(&ts->signal_mask, &ts->signal_mask, set);
Peter Maydella7ec0f92014-03-14 14:36:56 +0000237 break;
238 case SIG_UNBLOCK:
Peter Maydell3d3efba2016-05-27 15:51:49 +0100239 for (i = 1; i <= NSIG; ++i) {
240 if (sigismember(set, i)) {
241 sigdelset(&ts->signal_mask, i);
242 }
Peter Maydella7ec0f92014-03-14 14:36:56 +0000243 }
244 break;
245 case SIG_SETMASK:
Peter Maydell3d3efba2016-05-27 15:51:49 +0100246 ts->signal_mask = *set;
Peter Maydella7ec0f92014-03-14 14:36:56 +0000247 break;
248 default:
249 g_assert_not_reached();
250 }
Peter Maydell3d3efba2016-05-27 15:51:49 +0100251
252 /* Silently ignore attempts to change blocking status of KILL or STOP */
253 sigdelset(&ts->signal_mask, SIGKILL);
254 sigdelset(&ts->signal_mask, SIGSTOP);
Peter Maydella7ec0f92014-03-14 14:36:56 +0000255 }
Peter Maydell3d3efba2016-05-27 15:51:49 +0100256 return 0;
Alex Barcelo1c275922014-03-14 14:36:55 +0000257}
258
Peter Maydell9eede5b2016-05-27 15:51:46 +0100259#if !defined(TARGET_OPENRISC) && !defined(TARGET_UNICORE32) && \
260 !defined(TARGET_X86_64)
Peter Maydell3d3efba2016-05-27 15:51:49 +0100261/* Just set the guest's signal mask to the specified value; the
262 * caller is assumed to have called block_signals() already.
263 */
Peter Maydell9eede5b2016-05-27 15:51:46 +0100264static void set_sigmask(const sigset_t *set)
265{
Peter Maydell3d3efba2016-05-27 15:51:49 +0100266 TaskState *ts = (TaskState *)thread_cpu->opaque;
267
268 ts->signal_mask = *set;
Peter Maydell9eede5b2016-05-27 15:51:46 +0100269}
270#endif
271
bellard9de5e442003-03-23 16:49:39 +0000272/* siginfo conversion */
273
Anthony Liguoric227f092009-10-01 16:12:16 -0500274static inline void host_to_target_siginfo_noswap(target_siginfo_t *tinfo,
bellard9de5e442003-03-23 16:49:39 +0000275 const siginfo_t *info)
bellard66fb9762003-03-23 01:06:05 +0000276{
Richard Hendersona05c6402012-09-15 11:34:20 -0700277 int sig = host_to_target_signal(info->si_signo);
Peter Maydella70dadc2016-05-27 15:51:59 +0100278 int si_code = info->si_code;
279 int si_type;
bellard9de5e442003-03-23 16:49:39 +0000280 tinfo->si_signo = sig;
281 tinfo->si_errno = 0;
pbrookafd7cd92008-05-31 12:14:21 +0000282 tinfo->si_code = info->si_code;
Richard Hendersona05c6402012-09-15 11:34:20 -0700283
Peter Maydella70dadc2016-05-27 15:51:59 +0100284 /* This is awkward, because we have to use a combination of
285 * the si_code and si_signo to figure out which of the union's
286 * members are valid. (Within the host kernel it is always possible
287 * to tell, but the kernel carefully avoids giving userspace the
288 * high 16 bits of si_code, so we don't have the information to
289 * do this the easy way...) We therefore make our best guess,
290 * bearing in mind that a guest can spoof most of the si_codes
291 * via rt_sigqueueinfo() if it likes.
292 *
293 * Once we have made our guess, we record it in the top 16 bits of
294 * the si_code, so that tswap_siginfo() later can use it.
295 * tswap_siginfo() will strip these top bits out before writing
296 * si_code to the guest (sign-extending the lower bits).
297 */
298
299 switch (si_code) {
300 case SI_USER:
301 case SI_TKILL:
302 case SI_KERNEL:
303 /* Sent via kill(), tkill() or tgkill(), or direct from the kernel.
304 * These are the only unspoofable si_code values.
305 */
306 tinfo->_sifields._kill._pid = info->si_pid;
307 tinfo->_sifields._kill._uid = info->si_uid;
308 si_type = QEMU_SI_KILL;
309 break;
310 default:
311 /* Everything else is spoofable. Make best guess based on signal */
312 switch (sig) {
313 case TARGET_SIGCHLD:
314 tinfo->_sifields._sigchld._pid = info->si_pid;
315 tinfo->_sifields._sigchld._uid = info->si_uid;
316 tinfo->_sifields._sigchld._status
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100317 = host_to_target_waitstatus(info->si_status);
Peter Maydella70dadc2016-05-27 15:51:59 +0100318 tinfo->_sifields._sigchld._utime = info->si_utime;
319 tinfo->_sifields._sigchld._stime = info->si_stime;
320 si_type = QEMU_SI_CHLD;
321 break;
322 case TARGET_SIGIO:
323 tinfo->_sifields._sigpoll._band = info->si_band;
324 tinfo->_sifields._sigpoll._fd = info->si_fd;
325 si_type = QEMU_SI_POLL;
326 break;
327 default:
328 /* Assume a sigqueue()/mq_notify()/rt_sigqueueinfo() source. */
329 tinfo->_sifields._rt._pid = info->si_pid;
330 tinfo->_sifields._rt._uid = info->si_uid;
331 /* XXX: potential problem if 64 bit */
332 tinfo->_sifields._rt._sigval.sival_ptr
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100333 = (abi_ulong)(unsigned long)info->si_value.sival_ptr;
Peter Maydella70dadc2016-05-27 15:51:59 +0100334 si_type = QEMU_SI_RT;
335 break;
336 }
337 break;
bellard9de5e442003-03-23 16:49:39 +0000338 }
Peter Maydella70dadc2016-05-27 15:51:59 +0100339
340 tinfo->si_code = deposit32(si_code, 16, 16, si_type);
bellard66fb9762003-03-23 01:06:05 +0000341}
342
Anthony Liguoric227f092009-10-01 16:12:16 -0500343static void tswap_siginfo(target_siginfo_t *tinfo,
344 const target_siginfo_t *info)
bellard9de5e442003-03-23 16:49:39 +0000345{
Peter Maydella70dadc2016-05-27 15:51:59 +0100346 int si_type = extract32(info->si_code, 16, 16);
347 int si_code = sextract32(info->si_code, 0, 16);
Richard Hendersona05c6402012-09-15 11:34:20 -0700348
Peter Maydella70dadc2016-05-27 15:51:59 +0100349 __put_user(info->si_signo, &tinfo->si_signo);
350 __put_user(info->si_errno, &tinfo->si_errno);
351 __put_user(si_code, &tinfo->si_code);
352
353 /* We can use our internal marker of which fields in the structure
354 * are valid, rather than duplicating the guesswork of
355 * host_to_target_siginfo_noswap() here.
356 */
357 switch (si_type) {
358 case QEMU_SI_KILL:
359 __put_user(info->_sifields._kill._pid, &tinfo->_sifields._kill._pid);
360 __put_user(info->_sifields._kill._uid, &tinfo->_sifields._kill._uid);
361 break;
362 case QEMU_SI_TIMER:
363 __put_user(info->_sifields._timer._timer1,
364 &tinfo->_sifields._timer._timer1);
365 __put_user(info->_sifields._timer._timer2,
366 &tinfo->_sifields._timer._timer2);
367 break;
368 case QEMU_SI_POLL:
369 __put_user(info->_sifields._sigpoll._band,
370 &tinfo->_sifields._sigpoll._band);
371 __put_user(info->_sifields._sigpoll._fd,
372 &tinfo->_sifields._sigpoll._fd);
373 break;
374 case QEMU_SI_FAULT:
375 __put_user(info->_sifields._sigfault._addr,
376 &tinfo->_sifields._sigfault._addr);
377 break;
378 case QEMU_SI_CHLD:
379 __put_user(info->_sifields._sigchld._pid,
380 &tinfo->_sifields._sigchld._pid);
381 __put_user(info->_sifields._sigchld._uid,
382 &tinfo->_sifields._sigchld._uid);
383 __put_user(info->_sifields._sigchld._status,
384 &tinfo->_sifields._sigchld._status);
385 __put_user(info->_sifields._sigchld._utime,
386 &tinfo->_sifields._sigchld._utime);
387 __put_user(info->_sifields._sigchld._stime,
388 &tinfo->_sifields._sigchld._stime);
389 break;
390 case QEMU_SI_RT:
391 __put_user(info->_sifields._rt._pid, &tinfo->_sifields._rt._pid);
392 __put_user(info->_sifields._rt._uid, &tinfo->_sifields._rt._uid);
393 __put_user(info->_sifields._rt._sigval.sival_ptr,
394 &tinfo->_sifields._rt._sigval.sival_ptr);
395 break;
396 default:
397 g_assert_not_reached();
bellard9de5e442003-03-23 16:49:39 +0000398 }
399}
400
Anthony Liguoric227f092009-10-01 16:12:16 -0500401void host_to_target_siginfo(target_siginfo_t *tinfo, const siginfo_t *info)
bellard9de5e442003-03-23 16:49:39 +0000402{
403 host_to_target_siginfo_noswap(tinfo, info);
404 tswap_siginfo(tinfo, tinfo);
405}
406
407/* XXX: we support only POSIX RT signals are used. */
thsaa1f17c2007-07-11 22:48:58 +0000408/* XXX: find a solution for 64 bit (additional malloced data is needed) */
Anthony Liguoric227f092009-10-01 16:12:16 -0500409void target_to_host_siginfo(siginfo_t *info, const target_siginfo_t *tinfo)
bellard66fb9762003-03-23 01:06:05 +0000410{
Peter Maydell90c0f082016-05-27 15:52:01 +0100411 /* This conversion is used only for the rt_sigqueueinfo syscall,
412 * and so we know that the _rt fields are the valid ones.
413 */
414 abi_ulong sival_ptr;
415
416 __get_user(info->si_signo, &tinfo->si_signo);
417 __get_user(info->si_errno, &tinfo->si_errno);
418 __get_user(info->si_code, &tinfo->si_code);
419 __get_user(info->si_pid, &tinfo->_sifields._rt._pid);
420 __get_user(info->si_uid, &tinfo->_sifields._rt._uid);
421 __get_user(sival_ptr, &tinfo->_sifields._rt._sigval.sival_ptr);
422 info->si_value.sival_ptr = (void *)(long)sival_ptr;
bellard66fb9762003-03-23 01:06:05 +0000423}
424
aurel32ca587a82008-12-18 22:44:13 +0000425static int fatal_signal (int sig)
426{
427 switch (sig) {
428 case TARGET_SIGCHLD:
429 case TARGET_SIGURG:
430 case TARGET_SIGWINCH:
431 /* Ignored by default. */
432 return 0;
433 case TARGET_SIGCONT:
434 case TARGET_SIGSTOP:
435 case TARGET_SIGTSTP:
436 case TARGET_SIGTTIN:
437 case TARGET_SIGTTOU:
438 /* Job control signals. */
439 return 0;
440 default:
441 return 1;
442 }
443}
444
Mika Westerbergedf8e2a2009-04-07 09:57:11 +0300445/* returns 1 if given signal should dump core if not handled */
446static int core_dump_signal(int sig)
447{
448 switch (sig) {
449 case TARGET_SIGABRT:
450 case TARGET_SIGFPE:
451 case TARGET_SIGILL:
452 case TARGET_SIGQUIT:
453 case TARGET_SIGSEGV:
454 case TARGET_SIGTRAP:
455 case TARGET_SIGBUS:
456 return (1);
457 default:
458 return (0);
459 }
460}
461
bellard31e31b82003-02-18 22:55:36 +0000462void signal_init(void)
463{
Peter Maydell3d3efba2016-05-27 15:51:49 +0100464 TaskState *ts = (TaskState *)thread_cpu->opaque;
bellard31e31b82003-02-18 22:55:36 +0000465 struct sigaction act;
pbrook624f7972008-05-31 16:11:38 +0000466 struct sigaction oact;
bellard9e5f5282003-07-13 17:33:54 +0000467 int i, j;
pbrook624f7972008-05-31 16:11:38 +0000468 int host_sig;
bellard31e31b82003-02-18 22:55:36 +0000469
bellard9e5f5282003-07-13 17:33:54 +0000470 /* generate signal conversion tables */
Arnaud Patard3ca05582009-03-30 01:18:20 +0200471 for(i = 1; i < _NSIG; i++) {
bellard9e5f5282003-07-13 17:33:54 +0000472 if (host_to_target_signal_table[i] == 0)
473 host_to_target_signal_table[i] = i;
474 }
Arnaud Patard3ca05582009-03-30 01:18:20 +0200475 for(i = 1; i < _NSIG; i++) {
bellard9e5f5282003-07-13 17:33:54 +0000476 j = host_to_target_signal_table[i];
477 target_to_host_signal_table[j] = i;
478 }
ths3b46e622007-09-17 08:09:54 +0000479
Peter Maydell3d3efba2016-05-27 15:51:49 +0100480 /* Set the signal mask from the host mask. */
481 sigprocmask(0, 0, &ts->signal_mask);
482
bellard9de5e442003-03-23 16:49:39 +0000483 /* set all host signal handlers. ALL signals are blocked during
484 the handlers to serialize them. */
pbrook624f7972008-05-31 16:11:38 +0000485 memset(sigact_table, 0, sizeof(sigact_table));
486
bellard9de5e442003-03-23 16:49:39 +0000487 sigfillset(&act.sa_mask);
bellard31e31b82003-02-18 22:55:36 +0000488 act.sa_flags = SA_SIGINFO;
489 act.sa_sigaction = host_signal_handler;
pbrook624f7972008-05-31 16:11:38 +0000490 for(i = 1; i <= TARGET_NSIG; i++) {
491 host_sig = target_to_host_signal(i);
492 sigaction(host_sig, NULL, &oact);
493 if (oact.sa_sigaction == (void *)SIG_IGN) {
494 sigact_table[i - 1]._sa_handler = TARGET_SIG_IGN;
495 } else if (oact.sa_sigaction == (void *)SIG_DFL) {
496 sigact_table[i - 1]._sa_handler = TARGET_SIG_DFL;
497 }
498 /* If there's already a handler installed then something has
499 gone horribly wrong, so don't even try to handle that case. */
aurel32ca587a82008-12-18 22:44:13 +0000500 /* Install some handlers for our own use. We need at least
501 SIGSEGV and SIGBUS, to detect exceptions. We can not just
502 trap all signals because it affects syscall interrupt
503 behavior. But do trap all default-fatal signals. */
504 if (fatal_signal (i))
pbrook624f7972008-05-31 16:11:38 +0000505 sigaction(host_sig, &act, NULL);
bellard31e31b82003-02-18 22:55:36 +0000506 }
bellard31e31b82003-02-18 22:55:36 +0000507}
508
bellard66fb9762003-03-23 01:06:05 +0000509
bellard9de5e442003-03-23 16:49:39 +0000510/* abort execution with signal */
Riku Voipio66393fb2009-12-04 15:16:32 +0200511static void QEMU_NORETURN force_sig(int target_sig)
bellard66fb9762003-03-23 01:06:05 +0000512{
Andreas Färber0429a972013-08-26 18:14:44 +0200513 CPUState *cpu = thread_cpu;
514 CPUArchState *env = cpu->env_ptr;
515 TaskState *ts = (TaskState *)cpu->opaque;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +0300516 int host_sig, core_dumped = 0;
aurel32603e4fd2009-04-15 16:18:38 +0000517 struct sigaction act;
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +0100518
Riku Voipio66393fb2009-12-04 15:16:32 +0200519 host_sig = target_to_host_signal(target_sig);
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +0100520 trace_user_force_sig(env, target_sig, host_sig);
Andreas Färbera2247f82013-06-09 19:47:04 +0200521 gdb_signalled(env, target_sig);
aurel32603e4fd2009-04-15 16:18:38 +0000522
Mika Westerbergedf8e2a2009-04-07 09:57:11 +0300523 /* dump core if supported by target binary format */
Riku Voipio66393fb2009-12-04 15:16:32 +0200524 if (core_dump_signal(target_sig) && (ts->bprm->core_dump != NULL)) {
Mika Westerbergedf8e2a2009-04-07 09:57:11 +0300525 stop_all_tasks();
526 core_dumped =
Andreas Färbera2247f82013-06-09 19:47:04 +0200527 ((*ts->bprm->core_dump)(target_sig, env) == 0);
Mika Westerbergedf8e2a2009-04-07 09:57:11 +0300528 }
529 if (core_dumped) {
530 /* we already dumped the core of target process, we don't want
531 * a coredump of qemu itself */
532 struct rlimit nodump;
533 getrlimit(RLIMIT_CORE, &nodump);
534 nodump.rlim_cur=0;
535 setrlimit(RLIMIT_CORE, &nodump);
536 (void) fprintf(stderr, "qemu: uncaught target signal %d (%s) - %s\n",
Riku Voipio66393fb2009-12-04 15:16:32 +0200537 target_sig, strsignal(host_sig), "core dumped" );
Mika Westerbergedf8e2a2009-04-07 09:57:11 +0300538 }
539
Stefan Weil0c587512011-04-28 17:20:32 +0200540 /* The proper exit code for dying from an uncaught signal is
aurel32603e4fd2009-04-15 16:18:38 +0000541 * -<signal>. The kernel doesn't allow exit() or _exit() to pass
542 * a negative value. To get the proper exit code we need to
543 * actually die from an uncaught signal. Here the default signal
544 * handler is installed, we send ourself a signal and we wait for
545 * it to arrive. */
546 sigfillset(&act.sa_mask);
547 act.sa_handler = SIG_DFL;
Peter Maydell3a5d30b2014-02-17 18:55:32 +0000548 act.sa_flags = 0;
aurel32603e4fd2009-04-15 16:18:38 +0000549 sigaction(host_sig, &act, NULL);
550
551 /* For some reason raise(host_sig) doesn't send the signal when
552 * statically linked on x86-64. */
553 kill(getpid(), host_sig);
554
555 /* Make sure the signal isn't masked (just reuse the mask inside
556 of act) */
557 sigdelset(&act.sa_mask, host_sig);
558 sigsuspend(&act.sa_mask);
559
560 /* unreachable */
Blue Swirla6c6f762010-03-13 14:18:50 +0000561 abort();
bellard66fb9762003-03-23 01:06:05 +0000562}
563
bellard9de5e442003-03-23 16:49:39 +0000564/* queue a signal so that it will be send to the virtual CPU as soon
565 as possible */
Andreas Färber9349b4f2012-03-14 01:38:32 +0100566int queue_signal(CPUArchState *env, int sig, target_siginfo_t *info)
bellard31e31b82003-02-18 22:55:36 +0000567{
Andreas Färber0429a972013-08-26 18:14:44 +0200568 CPUState *cpu = ENV_GET_CPU(env);
569 TaskState *ts = cpu->opaque;
bellard66fb9762003-03-23 01:06:05 +0000570
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +0100571 trace_user_queue_signal(env, sig);
Peter Maydella7ec0f92014-03-14 14:36:56 +0000572
Peter Maydella70dadc2016-05-27 15:51:59 +0100573 /* Currently all callers define siginfo structures which
574 * use the _sifields._sigfault union member, so we can
575 * set the type here. If that changes we should push this
576 * out so the si_type is passed in by callers.
577 */
578 info->si_code = deposit32(info->si_code, 16, 16, QEMU_SI_FAULT);
579
Timothy E Baldwin655ed672016-05-27 15:51:53 +0100580 ts->sync_signal.info = *info;
581 ts->sync_signal.pending = sig;
Timothy E Baldwin907f5fd2016-05-27 15:51:52 +0100582 /* signal that a new signal is pending */
583 atomic_set(&ts->signal_pending, 1);
584 return 1; /* indicates that the signal was queued */
bellard9de5e442003-03-23 16:49:39 +0000585}
586
Timothy E Baldwin4d330ce2016-05-12 18:47:46 +0100587#ifndef HAVE_SAFE_SYSCALL
588static inline void rewind_if_in_safe_syscall(void *puc)
589{
590 /* Default version: never rewind */
591}
592#endif
593
ths5fafdf22007-09-16 21:08:06 +0000594static void host_signal_handler(int host_signum, siginfo_t *info,
bellard9de5e442003-03-23 16:49:39 +0000595 void *puc)
596{
Andreas Färbera2247f82013-06-09 19:47:04 +0200597 CPUArchState *env = thread_cpu->env_ptr;
Timothy E Baldwin655ed672016-05-27 15:51:53 +0100598 CPUState *cpu = ENV_GET_CPU(env);
599 TaskState *ts = cpu->opaque;
600
bellard9de5e442003-03-23 16:49:39 +0000601 int sig;
Anthony Liguoric227f092009-10-01 16:12:16 -0500602 target_siginfo_t tinfo;
Peter Maydell3d3efba2016-05-27 15:51:49 +0100603 ucontext_t *uc = puc;
Timothy E Baldwin655ed672016-05-27 15:51:53 +0100604 struct emulated_sigtable *k;
bellard9de5e442003-03-23 16:49:39 +0000605
606 /* the CPU emulator uses some host signals to detect exceptions,
aurel32eaa449b2009-01-03 13:14:52 +0000607 we forward to it some signals */
aurel32ca587a82008-12-18 22:44:13 +0000608 if ((host_signum == SIGSEGV || host_signum == SIGBUS)
aurel32eaa449b2009-01-03 13:14:52 +0000609 && info->si_code > 0) {
bellardb346ff42003-06-15 20:05:50 +0000610 if (cpu_signal_handler(host_signum, info, puc))
bellard9de5e442003-03-23 16:49:39 +0000611 return;
612 }
613
614 /* get target signal number */
615 sig = host_to_target_signal(host_signum);
616 if (sig < 1 || sig > TARGET_NSIG)
617 return;
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +0100618 trace_user_host_signal(env, host_signum, sig);
Timothy E Baldwin4d330ce2016-05-12 18:47:46 +0100619
620 rewind_if_in_safe_syscall(puc);
621
bellard9de5e442003-03-23 16:49:39 +0000622 host_to_target_siginfo_noswap(&tinfo, info);
Timothy E Baldwin655ed672016-05-27 15:51:53 +0100623 k = &ts->sigtab[sig - 1];
624 k->info = tinfo;
625 k->pending = sig;
626 ts->signal_pending = 1;
Peter Maydell3d3efba2016-05-27 15:51:49 +0100627
Timothy E Baldwin655ed672016-05-27 15:51:53 +0100628 /* Block host signals until target signal handler entered. We
629 * can't block SIGSEGV or SIGBUS while we're executing guest
630 * code in case the guest code provokes one in the window between
631 * now and it getting out to the main loop. Signals will be
632 * unblocked again in process_pending_signals().
633 */
634 sigfillset(&uc->uc_sigmask);
635 sigdelset(&uc->uc_sigmask, SIGSEGV);
636 sigdelset(&uc->uc_sigmask, SIGBUS);
637
638 /* interrupt the virtual CPU as soon as possible */
639 cpu_exit(thread_cpu);
bellard31e31b82003-02-18 22:55:36 +0000640}
641
ths0da46a62007-10-20 20:23:07 +0000642/* do_sigaltstack() returns target values and errnos. */
bellard579a97f2007-11-11 14:26:47 +0000643/* compare linux/kernel/signal.c:do_sigaltstack() */
644abi_long do_sigaltstack(abi_ulong uss_addr, abi_ulong uoss_addr, abi_ulong sp)
thsa04e1342007-09-27 13:57:58 +0000645{
646 int ret;
647 struct target_sigaltstack oss;
648
649 /* XXX: test errors */
bellard579a97f2007-11-11 14:26:47 +0000650 if(uoss_addr)
thsa04e1342007-09-27 13:57:58 +0000651 {
652 __put_user(target_sigaltstack_used.ss_sp, &oss.ss_sp);
653 __put_user(target_sigaltstack_used.ss_size, &oss.ss_size);
654 __put_user(sas_ss_flags(sp), &oss.ss_flags);
655 }
656
bellard579a97f2007-11-11 14:26:47 +0000657 if(uss_addr)
thsa04e1342007-09-27 13:57:58 +0000658 {
bellard579a97f2007-11-11 14:26:47 +0000659 struct target_sigaltstack *uss;
660 struct target_sigaltstack ss;
Tom Musta0903c8b2014-08-12 13:53:40 -0500661 size_t minstacksize = TARGET_MINSIGSTKSZ;
662
663#if defined(TARGET_PPC64)
664 /* ELF V2 for PPC64 has a 4K minimum stack size for signal handlers */
665 struct image_info *image = ((TaskState *)thread_cpu->opaque)->info;
666 if (get_ppc64_abi(image) > 1) {
667 minstacksize = 4096;
668 }
669#endif
thsa04e1342007-09-27 13:57:58 +0000670
ths0da46a62007-10-20 20:23:07 +0000671 ret = -TARGET_EFAULT;
Riku Voipio9eeb8302014-04-23 11:26:34 +0300672 if (!lock_user_struct(VERIFY_READ, uss, uss_addr, 1)) {
thsa04e1342007-09-27 13:57:58 +0000673 goto out;
Riku Voipio9eeb8302014-04-23 11:26:34 +0300674 }
675 __get_user(ss.ss_sp, &uss->ss_sp);
676 __get_user(ss.ss_size, &uss->ss_size);
677 __get_user(ss.ss_flags, &uss->ss_flags);
bellard579a97f2007-11-11 14:26:47 +0000678 unlock_user_struct(uss, uss_addr, 0);
thsa04e1342007-09-27 13:57:58 +0000679
ths0da46a62007-10-20 20:23:07 +0000680 ret = -TARGET_EPERM;
thsa04e1342007-09-27 13:57:58 +0000681 if (on_sig_stack(sp))
682 goto out;
683
ths0da46a62007-10-20 20:23:07 +0000684 ret = -TARGET_EINVAL;
thsa04e1342007-09-27 13:57:58 +0000685 if (ss.ss_flags != TARGET_SS_DISABLE
686 && ss.ss_flags != TARGET_SS_ONSTACK
687 && ss.ss_flags != 0)
688 goto out;
689
690 if (ss.ss_flags == TARGET_SS_DISABLE) {
691 ss.ss_size = 0;
692 ss.ss_sp = 0;
693 } else {
ths0da46a62007-10-20 20:23:07 +0000694 ret = -TARGET_ENOMEM;
Tom Musta0903c8b2014-08-12 13:53:40 -0500695 if (ss.ss_size < minstacksize) {
thsa04e1342007-09-27 13:57:58 +0000696 goto out;
Tom Musta0903c8b2014-08-12 13:53:40 -0500697 }
thsa04e1342007-09-27 13:57:58 +0000698 }
699
700 target_sigaltstack_used.ss_sp = ss.ss_sp;
701 target_sigaltstack_used.ss_size = ss.ss_size;
702 }
703
bellard579a97f2007-11-11 14:26:47 +0000704 if (uoss_addr) {
ths0da46a62007-10-20 20:23:07 +0000705 ret = -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +0000706 if (copy_to_user(uoss_addr, &oss, sizeof(oss)))
thsa04e1342007-09-27 13:57:58 +0000707 goto out;
thsa04e1342007-09-27 13:57:58 +0000708 }
709
710 ret = 0;
711out:
712 return ret;
713}
714
Timothy E Baldwinef6a7782016-05-27 15:51:54 +0100715/* do_sigaction() return target values and host errnos */
bellard66fb9762003-03-23 01:06:05 +0000716int do_sigaction(int sig, const struct target_sigaction *act,
717 struct target_sigaction *oact)
bellard31e31b82003-02-18 22:55:36 +0000718{
pbrook624f7972008-05-31 16:11:38 +0000719 struct target_sigaction *k;
bellard773b93e2004-01-04 17:15:59 +0000720 struct sigaction act1;
721 int host_sig;
ths0da46a62007-10-20 20:23:07 +0000722 int ret = 0;
bellard31e31b82003-02-18 22:55:36 +0000723
Timothy E Baldwinef6a7782016-05-27 15:51:54 +0100724 if (sig < 1 || sig > TARGET_NSIG || sig == TARGET_SIGKILL || sig == TARGET_SIGSTOP) {
725 return -TARGET_EINVAL;
726 }
727
728 if (block_signals()) {
729 return -TARGET_ERESTARTSYS;
730 }
731
bellard66fb9762003-03-23 01:06:05 +0000732 k = &sigact_table[sig - 1];
bellard66fb9762003-03-23 01:06:05 +0000733 if (oact) {
Richard Hendersond2565872013-01-04 16:39:32 -0800734 __put_user(k->_sa_handler, &oact->_sa_handler);
735 __put_user(k->sa_flags, &oact->sa_flags);
ths388bb212007-05-13 13:58:00 +0000736#if !defined(TARGET_MIPS)
Richard Hendersond2565872013-01-04 16:39:32 -0800737 __put_user(k->sa_restorer, &oact->sa_restorer);
ths388bb212007-05-13 13:58:00 +0000738#endif
Richard Hendersond2565872013-01-04 16:39:32 -0800739 /* Not swapped. */
pbrook624f7972008-05-31 16:11:38 +0000740 oact->sa_mask = k->sa_mask;
bellard66fb9762003-03-23 01:06:05 +0000741 }
742 if (act) {
pbrook624f7972008-05-31 16:11:38 +0000743 /* FIXME: This is not threadsafe. */
Richard Hendersond2565872013-01-04 16:39:32 -0800744 __get_user(k->_sa_handler, &act->_sa_handler);
745 __get_user(k->sa_flags, &act->sa_flags);
ths388bb212007-05-13 13:58:00 +0000746#if !defined(TARGET_MIPS)
Richard Hendersond2565872013-01-04 16:39:32 -0800747 __get_user(k->sa_restorer, &act->sa_restorer);
ths388bb212007-05-13 13:58:00 +0000748#endif
Richard Hendersond2565872013-01-04 16:39:32 -0800749 /* To be swapped in target_to_host_sigset. */
pbrook624f7972008-05-31 16:11:38 +0000750 k->sa_mask = act->sa_mask;
bellard773b93e2004-01-04 17:15:59 +0000751
752 /* we update the host linux signal state */
753 host_sig = target_to_host_signal(sig);
754 if (host_sig != SIGSEGV && host_sig != SIGBUS) {
755 sigfillset(&act1.sa_mask);
756 act1.sa_flags = SA_SIGINFO;
pbrook624f7972008-05-31 16:11:38 +0000757 if (k->sa_flags & TARGET_SA_RESTART)
bellard773b93e2004-01-04 17:15:59 +0000758 act1.sa_flags |= SA_RESTART;
759 /* NOTE: it is important to update the host kernel signal
760 ignore state to avoid getting unexpected interrupted
761 syscalls */
pbrook624f7972008-05-31 16:11:38 +0000762 if (k->_sa_handler == TARGET_SIG_IGN) {
bellard773b93e2004-01-04 17:15:59 +0000763 act1.sa_sigaction = (void *)SIG_IGN;
pbrook624f7972008-05-31 16:11:38 +0000764 } else if (k->_sa_handler == TARGET_SIG_DFL) {
aurel32ca587a82008-12-18 22:44:13 +0000765 if (fatal_signal (sig))
766 act1.sa_sigaction = host_signal_handler;
767 else
768 act1.sa_sigaction = (void *)SIG_DFL;
bellard773b93e2004-01-04 17:15:59 +0000769 } else {
770 act1.sa_sigaction = host_signal_handler;
771 }
ths0da46a62007-10-20 20:23:07 +0000772 ret = sigaction(host_sig, &act1, NULL);
bellard773b93e2004-01-04 17:15:59 +0000773 }
bellard66fb9762003-03-23 01:06:05 +0000774 }
ths0da46a62007-10-20 20:23:07 +0000775 return ret;
bellard66fb9762003-03-23 01:06:05 +0000776}
bellard31e31b82003-02-18 22:55:36 +0000777
bellard459a4012007-11-11 19:45:10 +0000778#if defined(TARGET_I386) && TARGET_ABI_BITS == 32
bellard66fb9762003-03-23 01:06:05 +0000779
780/* from the Linux kernel */
781
782struct target_fpreg {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100783 uint16_t significand[4];
784 uint16_t exponent;
bellard66fb9762003-03-23 01:06:05 +0000785};
786
787struct target_fpxreg {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100788 uint16_t significand[4];
789 uint16_t exponent;
790 uint16_t padding[3];
bellard66fb9762003-03-23 01:06:05 +0000791};
792
793struct target_xmmreg {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100794 abi_ulong element[4];
bellard66fb9762003-03-23 01:06:05 +0000795};
796
797struct target_fpstate {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100798 /* Regular FPU environment */
799 abi_ulong cw;
800 abi_ulong sw;
801 abi_ulong tag;
802 abi_ulong ipoff;
803 abi_ulong cssel;
804 abi_ulong dataoff;
805 abi_ulong datasel;
806 struct target_fpreg _st[8];
807 uint16_t status;
808 uint16_t magic; /* 0xffff = regular FPU data only */
bellard66fb9762003-03-23 01:06:05 +0000809
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100810 /* FXSR FPU environment */
811 abi_ulong _fxsr_env[6]; /* FXSR FPU env is ignored */
812 abi_ulong mxcsr;
813 abi_ulong reserved;
814 struct target_fpxreg _fxsr_st[8]; /* FXSR FPU reg data is ignored */
815 struct target_xmmreg _xmm[8];
816 abi_ulong padding[56];
bellard66fb9762003-03-23 01:06:05 +0000817};
818
819#define X86_FXSR_MAGIC 0x0000
820
821struct target_sigcontext {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100822 uint16_t gs, __gsh;
823 uint16_t fs, __fsh;
824 uint16_t es, __esh;
825 uint16_t ds, __dsh;
826 abi_ulong edi;
827 abi_ulong esi;
828 abi_ulong ebp;
829 abi_ulong esp;
830 abi_ulong ebx;
831 abi_ulong edx;
832 abi_ulong ecx;
833 abi_ulong eax;
834 abi_ulong trapno;
835 abi_ulong err;
836 abi_ulong eip;
837 uint16_t cs, __csh;
838 abi_ulong eflags;
839 abi_ulong esp_at_signal;
840 uint16_t ss, __ssh;
841 abi_ulong fpstate; /* pointer */
842 abi_ulong oldmask;
843 abi_ulong cr2;
bellard66fb9762003-03-23 01:06:05 +0000844};
845
bellard66fb9762003-03-23 01:06:05 +0000846struct target_ucontext {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100847 abi_ulong tuc_flags;
848 abi_ulong tuc_link;
849 target_stack_t tuc_stack;
850 struct target_sigcontext tuc_mcontext;
851 target_sigset_t tuc_sigmask; /* mask last for extensibility */
bellard66fb9762003-03-23 01:06:05 +0000852};
853
854struct sigframe
855{
blueswir1992f48a2007-10-14 16:27:31 +0000856 abi_ulong pretcode;
bellard66fb9762003-03-23 01:06:05 +0000857 int sig;
858 struct target_sigcontext sc;
859 struct target_fpstate fpstate;
blueswir1992f48a2007-10-14 16:27:31 +0000860 abi_ulong extramask[TARGET_NSIG_WORDS-1];
bellard66fb9762003-03-23 01:06:05 +0000861 char retcode[8];
862};
863
864struct rt_sigframe
865{
blueswir1992f48a2007-10-14 16:27:31 +0000866 abi_ulong pretcode;
bellard66fb9762003-03-23 01:06:05 +0000867 int sig;
blueswir1992f48a2007-10-14 16:27:31 +0000868 abi_ulong pinfo;
869 abi_ulong puc;
bellard66fb9762003-03-23 01:06:05 +0000870 struct target_siginfo info;
871 struct target_ucontext uc;
872 struct target_fpstate fpstate;
873 char retcode[8];
874};
875
876/*
877 * Set up a signal frame.
878 */
879
bellard66fb9762003-03-23 01:06:05 +0000880/* XXX: save x87 state */
Riku Voipio41ecc722014-04-23 11:01:00 +0300881static void setup_sigcontext(struct target_sigcontext *sc,
882 struct target_fpstate *fpstate, CPUX86State *env, abi_ulong mask,
883 abi_ulong fpstate_addr)
bellard66fb9762003-03-23 01:06:05 +0000884{
Andreas Färber27103422013-08-26 08:31:06 +0200885 CPUState *cs = CPU(x86_env_get_cpu(env));
Andreas Färber27103422013-08-26 08:31:06 +0200886 uint16_t magic;
bellard66fb9762003-03-23 01:06:05 +0000887
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100888 /* already locked in setup_frame() */
Riku Voipio1d8b5122014-04-23 10:26:05 +0300889 __put_user(env->segs[R_GS].selector, (unsigned int *)&sc->gs);
890 __put_user(env->segs[R_FS].selector, (unsigned int *)&sc->fs);
891 __put_user(env->segs[R_ES].selector, (unsigned int *)&sc->es);
892 __put_user(env->segs[R_DS].selector, (unsigned int *)&sc->ds);
893 __put_user(env->regs[R_EDI], &sc->edi);
894 __put_user(env->regs[R_ESI], &sc->esi);
895 __put_user(env->regs[R_EBP], &sc->ebp);
896 __put_user(env->regs[R_ESP], &sc->esp);
897 __put_user(env->regs[R_EBX], &sc->ebx);
898 __put_user(env->regs[R_EDX], &sc->edx);
899 __put_user(env->regs[R_ECX], &sc->ecx);
900 __put_user(env->regs[R_EAX], &sc->eax);
901 __put_user(cs->exception_index, &sc->trapno);
902 __put_user(env->error_code, &sc->err);
903 __put_user(env->eip, &sc->eip);
904 __put_user(env->segs[R_CS].selector, (unsigned int *)&sc->cs);
905 __put_user(env->eflags, &sc->eflags);
906 __put_user(env->regs[R_ESP], &sc->esp_at_signal);
907 __put_user(env->segs[R_SS].selector, (unsigned int *)&sc->ss);
bellarded2dcdf2003-05-29 20:06:27 +0000908
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100909 cpu_x86_fsave(env, fpstate_addr, 1);
910 fpstate->status = fpstate->sw;
911 magic = 0xffff;
Riku Voipio1d8b5122014-04-23 10:26:05 +0300912 __put_user(magic, &fpstate->magic);
913 __put_user(fpstate_addr, &sc->fpstate);
bellarded2dcdf2003-05-29 20:06:27 +0000914
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100915 /* non-iBCS2 extensions.. */
Riku Voipio1d8b5122014-04-23 10:26:05 +0300916 __put_user(mask, &sc->oldmask);
917 __put_user(env->cr[2], &sc->cr2);
bellard66fb9762003-03-23 01:06:05 +0000918}
919
920/*
921 * Determine which stack to use..
922 */
923
bellard579a97f2007-11-11 14:26:47 +0000924static inline abi_ulong
pbrook624f7972008-05-31 16:11:38 +0000925get_sigframe(struct target_sigaction *ka, CPUX86State *env, size_t frame_size)
bellard66fb9762003-03-23 01:06:05 +0000926{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100927 unsigned long esp;
bellard66fb9762003-03-23 01:06:05 +0000928
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100929 /* Default to using normal stack */
930 esp = env->regs[R_ESP];
931 /* This is the X/Open sanctioned signal stack switching. */
932 if (ka->sa_flags & TARGET_SA_ONSTACK) {
933 if (sas_ss_flags(esp) == 0) {
934 esp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
thsa04e1342007-09-27 13:57:58 +0000935 }
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100936 } else {
bellard66fb9762003-03-23 01:06:05 +0000937
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100938 /* This is the legacy signal stack switching. */
bellarda52c7572003-06-21 13:14:12 +0000939 if ((env->segs[R_SS].selector & 0xffff) != __USER_DS &&
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100940 !(ka->sa_flags & TARGET_SA_RESTORER) &&
941 ka->sa_restorer) {
pbrook624f7972008-05-31 16:11:38 +0000942 esp = (unsigned long) ka->sa_restorer;
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100943 }
944 }
945 return (esp - frame_size) & -8ul;
bellard66fb9762003-03-23 01:06:05 +0000946}
947
bellard579a97f2007-11-11 14:26:47 +0000948/* compare linux/arch/i386/kernel/signal.c:setup_frame() */
pbrook624f7972008-05-31 16:11:38 +0000949static void setup_frame(int sig, struct target_sigaction *ka,
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100950 target_sigset_t *set, CPUX86State *env)
bellard66fb9762003-03-23 01:06:05 +0000951{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100952 abi_ulong frame_addr;
953 struct sigframe *frame;
954 int i;
bellard66fb9762003-03-23 01:06:05 +0000955
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100956 frame_addr = get_sigframe(ka, env, sizeof(*frame));
957 trace_user_setup_frame(env, frame_addr);
bellard66fb9762003-03-23 01:06:05 +0000958
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100959 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
960 goto give_sigsegv;
bellard579a97f2007-11-11 14:26:47 +0000961
Peter Maydellb6e2c932015-01-08 12:19:43 +0000962 __put_user(sig, &frame->sig);
bellard66fb9762003-03-23 01:06:05 +0000963
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100964 setup_sigcontext(&frame->sc, &frame->fpstate, env, set->sig[0],
965 frame_addr + offsetof(struct sigframe, fpstate));
bellard66fb9762003-03-23 01:06:05 +0000966
Riku Voipio7df2fa32014-04-23 10:34:53 +0300967 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
968 __put_user(set->sig[i], &frame->extramask[i - 1]);
969 }
bellard66fb9762003-03-23 01:06:05 +0000970
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100971 /* Set up to return from userspace. If provided, use a stub
972 already in userspace. */
973 if (ka->sa_flags & TARGET_SA_RESTORER) {
Riku Voipio1d8b5122014-04-23 10:26:05 +0300974 __put_user(ka->sa_restorer, &frame->pretcode);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100975 } else {
976 uint16_t val16;
977 abi_ulong retcode_addr;
978 retcode_addr = frame_addr + offsetof(struct sigframe, retcode);
Riku Voipio1d8b5122014-04-23 10:26:05 +0300979 __put_user(retcode_addr, &frame->pretcode);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100980 /* This is popl %eax ; movl $,%eax ; int $0x80 */
981 val16 = 0xb858;
Riku Voipio1d8b5122014-04-23 10:26:05 +0300982 __put_user(val16, (uint16_t *)(frame->retcode+0));
983 __put_user(TARGET_NR_sigreturn, (int *)(frame->retcode+2));
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100984 val16 = 0x80cd;
Riku Voipio1d8b5122014-04-23 10:26:05 +0300985 __put_user(val16, (uint16_t *)(frame->retcode+6));
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100986 }
bellard66fb9762003-03-23 01:06:05 +0000987
bellard66fb9762003-03-23 01:06:05 +0000988
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100989 /* Set up registers for signal handler */
990 env->regs[R_ESP] = frame_addr;
991 env->eip = ka->_sa_handler;
bellard66fb9762003-03-23 01:06:05 +0000992
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100993 cpu_x86_load_seg(env, R_DS, __USER_DS);
994 cpu_x86_load_seg(env, R_ES, __USER_DS);
995 cpu_x86_load_seg(env, R_SS, __USER_DS);
996 cpu_x86_load_seg(env, R_CS, __USER_CS);
997 env->eflags &= ~TF_MASK;
bellard66fb9762003-03-23 01:06:05 +0000998
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100999 unlock_user_struct(frame, frame_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00001000
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001001 return;
bellard66fb9762003-03-23 01:06:05 +00001002
1003give_sigsegv:
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001004 if (sig == TARGET_SIGSEGV) {
1005 ka->_sa_handler = TARGET_SIG_DFL;
1006 }
1007 force_sig(TARGET_SIGSEGV /* , current */);
bellard66fb9762003-03-23 01:06:05 +00001008}
1009
bellard579a97f2007-11-11 14:26:47 +00001010/* compare linux/arch/i386/kernel/signal.c:setup_rt_frame() */
pbrook624f7972008-05-31 16:11:38 +00001011static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05001012 target_siginfo_t *info,
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001013 target_sigset_t *set, CPUX86State *env)
bellard66fb9762003-03-23 01:06:05 +00001014{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001015 abi_ulong frame_addr, addr;
1016 struct rt_sigframe *frame;
1017 int i;
bellard66fb9762003-03-23 01:06:05 +00001018
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001019 frame_addr = get_sigframe(ka, env, sizeof(*frame));
1020 trace_user_setup_rt_frame(env, frame_addr);
bellard66fb9762003-03-23 01:06:05 +00001021
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001022 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
1023 goto give_sigsegv;
bellard66fb9762003-03-23 01:06:05 +00001024
Peter Maydellb6e2c932015-01-08 12:19:43 +00001025 __put_user(sig, &frame->sig);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001026 addr = frame_addr + offsetof(struct rt_sigframe, info);
Riku Voipio1d8b5122014-04-23 10:26:05 +03001027 __put_user(addr, &frame->pinfo);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001028 addr = frame_addr + offsetof(struct rt_sigframe, uc);
Riku Voipio1d8b5122014-04-23 10:26:05 +03001029 __put_user(addr, &frame->puc);
Peter Maydellf6c7a052015-01-08 12:19:48 +00001030 tswap_siginfo(&frame->info, info);
bellard66fb9762003-03-23 01:06:05 +00001031
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001032 /* Create the ucontext. */
Riku Voipio1d8b5122014-04-23 10:26:05 +03001033 __put_user(0, &frame->uc.tuc_flags);
1034 __put_user(0, &frame->uc.tuc_link);
1035 __put_user(target_sigaltstack_used.ss_sp, &frame->uc.tuc_stack.ss_sp);
1036 __put_user(sas_ss_flags(get_sp_from_cpustate(env)),
1037 &frame->uc.tuc_stack.ss_flags);
1038 __put_user(target_sigaltstack_used.ss_size,
1039 &frame->uc.tuc_stack.ss_size);
Riku Voipio41ecc722014-04-23 11:01:00 +03001040 setup_sigcontext(&frame->uc.tuc_mcontext, &frame->fpstate, env,
1041 set->sig[0], frame_addr + offsetof(struct rt_sigframe, fpstate));
1042
Riku Voipio0188fad2014-04-23 13:34:15 +03001043 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
1044 __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
1045 }
bellard66fb9762003-03-23 01:06:05 +00001046
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001047 /* Set up to return from userspace. If provided, use a stub
1048 already in userspace. */
1049 if (ka->sa_flags & TARGET_SA_RESTORER) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03001050 __put_user(ka->sa_restorer, &frame->pretcode);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001051 } else {
1052 uint16_t val16;
1053 addr = frame_addr + offsetof(struct rt_sigframe, retcode);
Riku Voipio1d8b5122014-04-23 10:26:05 +03001054 __put_user(addr, &frame->pretcode);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001055 /* This is movl $,%eax ; int $0x80 */
Riku Voipio1d8b5122014-04-23 10:26:05 +03001056 __put_user(0xb8, (char *)(frame->retcode+0));
1057 __put_user(TARGET_NR_rt_sigreturn, (int *)(frame->retcode+1));
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001058 val16 = 0x80cd;
Riku Voipio1d8b5122014-04-23 10:26:05 +03001059 __put_user(val16, (uint16_t *)(frame->retcode+5));
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001060 }
bellard66fb9762003-03-23 01:06:05 +00001061
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001062 /* Set up registers for signal handler */
1063 env->regs[R_ESP] = frame_addr;
1064 env->eip = ka->_sa_handler;
bellard66fb9762003-03-23 01:06:05 +00001065
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001066 cpu_x86_load_seg(env, R_DS, __USER_DS);
1067 cpu_x86_load_seg(env, R_ES, __USER_DS);
1068 cpu_x86_load_seg(env, R_SS, __USER_DS);
1069 cpu_x86_load_seg(env, R_CS, __USER_CS);
1070 env->eflags &= ~TF_MASK;
bellard66fb9762003-03-23 01:06:05 +00001071
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001072 unlock_user_struct(frame, frame_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00001073
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001074 return;
bellard66fb9762003-03-23 01:06:05 +00001075
1076give_sigsegv:
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001077 if (sig == TARGET_SIGSEGV) {
1078 ka->_sa_handler = TARGET_SIG_DFL;
1079 }
1080 force_sig(TARGET_SIGSEGV /* , current */);
bellard66fb9762003-03-23 01:06:05 +00001081}
1082
1083static int
Timothy E Baldwin0284b032016-05-12 18:47:30 +01001084restore_sigcontext(CPUX86State *env, struct target_sigcontext *sc)
bellard66fb9762003-03-23 01:06:05 +00001085{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001086 unsigned int err = 0;
1087 abi_ulong fpstate_addr;
1088 unsigned int tmpflags;
bellard66fb9762003-03-23 01:06:05 +00001089
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001090 cpu_x86_load_seg(env, R_GS, tswap16(sc->gs));
1091 cpu_x86_load_seg(env, R_FS, tswap16(sc->fs));
1092 cpu_x86_load_seg(env, R_ES, tswap16(sc->es));
1093 cpu_x86_load_seg(env, R_DS, tswap16(sc->ds));
bellard66fb9762003-03-23 01:06:05 +00001094
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001095 env->regs[R_EDI] = tswapl(sc->edi);
1096 env->regs[R_ESI] = tswapl(sc->esi);
1097 env->regs[R_EBP] = tswapl(sc->ebp);
1098 env->regs[R_ESP] = tswapl(sc->esp);
1099 env->regs[R_EBX] = tswapl(sc->ebx);
1100 env->regs[R_EDX] = tswapl(sc->edx);
1101 env->regs[R_ECX] = tswapl(sc->ecx);
Timothy E Baldwin0284b032016-05-12 18:47:30 +01001102 env->regs[R_EAX] = tswapl(sc->eax);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001103 env->eip = tswapl(sc->eip);
bellard66fb9762003-03-23 01:06:05 +00001104
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001105 cpu_x86_load_seg(env, R_CS, lduw_p(&sc->cs) | 3);
1106 cpu_x86_load_seg(env, R_SS, lduw_p(&sc->ss) | 3);
ths5fafdf22007-09-16 21:08:06 +00001107
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001108 tmpflags = tswapl(sc->eflags);
1109 env->eflags = (env->eflags & ~0x40DD5) | (tmpflags & 0x40DD5);
1110 // regs->orig_eax = -1; /* disable syscall checks */
bellard28be6232007-11-11 22:23:38 +00001111
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001112 fpstate_addr = tswapl(sc->fpstate);
1113 if (fpstate_addr != 0) {
1114 if (!access_ok(VERIFY_READ, fpstate_addr,
1115 sizeof(struct target_fpstate)))
1116 goto badframe;
1117 cpu_x86_frstor(env, fpstate_addr, 1);
1118 }
bellard66fb9762003-03-23 01:06:05 +00001119
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001120 return err;
bellard66fb9762003-03-23 01:06:05 +00001121badframe:
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001122 return 1;
bellard66fb9762003-03-23 01:06:05 +00001123}
1124
1125long do_sigreturn(CPUX86State *env)
1126{
bellard579a97f2007-11-11 14:26:47 +00001127 struct sigframe *frame;
1128 abi_ulong frame_addr = env->regs[R_ESP] - 8;
Anthony Liguoric227f092009-10-01 16:12:16 -05001129 target_sigset_t target_set;
bellard66fb9762003-03-23 01:06:05 +00001130 sigset_t set;
Timothy E Baldwin0284b032016-05-12 18:47:30 +01001131 int i;
bellard66fb9762003-03-23 01:06:05 +00001132
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01001133 trace_user_do_sigreturn(env, frame_addr);
bellard579a97f2007-11-11 14:26:47 +00001134 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
1135 goto badframe;
bellard66fb9762003-03-23 01:06:05 +00001136 /* set blocked signals */
Riku Voipiof5f601a2014-04-23 13:00:17 +03001137 __get_user(target_set.sig[0], &frame->sc.oldmask);
bellard92319442004-06-19 16:58:13 +00001138 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
Riku Voipiof5f601a2014-04-23 13:00:17 +03001139 __get_user(target_set.sig[i], &frame->extramask[i - 1]);
bellard92319442004-06-19 16:58:13 +00001140 }
bellard66fb9762003-03-23 01:06:05 +00001141
bellard92319442004-06-19 16:58:13 +00001142 target_to_host_sigset_internal(&set, &target_set);
Peter Maydell9eede5b2016-05-27 15:51:46 +01001143 set_sigmask(&set);
ths3b46e622007-09-17 08:09:54 +00001144
bellard66fb9762003-03-23 01:06:05 +00001145 /* restore registers */
Timothy E Baldwin0284b032016-05-12 18:47:30 +01001146 if (restore_sigcontext(env, &frame->sc))
bellard66fb9762003-03-23 01:06:05 +00001147 goto badframe;
bellard579a97f2007-11-11 14:26:47 +00001148 unlock_user_struct(frame, frame_addr, 0);
Timothy E Baldwin0284b032016-05-12 18:47:30 +01001149 return -TARGET_QEMU_ESIGRETURN;
bellard66fb9762003-03-23 01:06:05 +00001150
1151badframe:
bellard579a97f2007-11-11 14:26:47 +00001152 unlock_user_struct(frame, frame_addr, 0);
bellard66fb9762003-03-23 01:06:05 +00001153 force_sig(TARGET_SIGSEGV);
1154 return 0;
1155}
1156
1157long do_rt_sigreturn(CPUX86State *env)
1158{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001159 abi_ulong frame_addr;
1160 struct rt_sigframe *frame;
1161 sigset_t set;
bellard66fb9762003-03-23 01:06:05 +00001162
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001163 frame_addr = env->regs[R_ESP] - 4;
1164 trace_user_do_rt_sigreturn(env, frame_addr);
1165 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
1166 goto badframe;
1167 target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
Peter Maydell9eede5b2016-05-27 15:51:46 +01001168 set_sigmask(&set);
ths5fafdf22007-09-16 21:08:06 +00001169
Timothy E Baldwin0284b032016-05-12 18:47:30 +01001170 if (restore_sigcontext(env, &frame->uc.tuc_mcontext)) {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001171 goto badframe;
1172 }
bellard66fb9762003-03-23 01:06:05 +00001173
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001174 if (do_sigaltstack(frame_addr + offsetof(struct rt_sigframe, uc.tuc_stack), 0,
1175 get_sp_from_cpustate(env)) == -EFAULT) {
1176 goto badframe;
1177 }
thsa04e1342007-09-27 13:57:58 +00001178
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001179 unlock_user_struct(frame, frame_addr, 0);
Timothy E Baldwin0284b032016-05-12 18:47:30 +01001180 return -TARGET_QEMU_ESIGRETURN;
bellard66fb9762003-03-23 01:06:05 +00001181
1182badframe:
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001183 unlock_user_struct(frame, frame_addr, 0);
1184 force_sig(TARGET_SIGSEGV);
1185 return 0;
bellard66fb9762003-03-23 01:06:05 +00001186}
1187
Andreas Schwab1744aea2013-09-03 20:12:16 +01001188#elif defined(TARGET_AARCH64)
1189
1190struct target_sigcontext {
1191 uint64_t fault_address;
1192 /* AArch64 registers */
1193 uint64_t regs[31];
1194 uint64_t sp;
1195 uint64_t pc;
1196 uint64_t pstate;
1197 /* 4K reserved for FP/SIMD state and future expansion */
1198 char __reserved[4096] __attribute__((__aligned__(16)));
1199};
1200
1201struct target_ucontext {
1202 abi_ulong tuc_flags;
1203 abi_ulong tuc_link;
1204 target_stack_t tuc_stack;
1205 target_sigset_t tuc_sigmask;
1206 /* glibc uses a 1024-bit sigset_t */
1207 char __unused[1024 / 8 - sizeof(target_sigset_t)];
1208 /* last for future expansion */
1209 struct target_sigcontext tuc_mcontext;
1210};
1211
1212/*
1213 * Header to be used at the beginning of structures extending the user
1214 * context. Such structures must be placed after the rt_sigframe on the stack
1215 * and be 16-byte aligned. The last structure must be a dummy one with the
1216 * magic and size set to 0.
1217 */
1218struct target_aarch64_ctx {
1219 uint32_t magic;
1220 uint32_t size;
1221};
1222
1223#define TARGET_FPSIMD_MAGIC 0x46508001
1224
1225struct target_fpsimd_context {
1226 struct target_aarch64_ctx head;
1227 uint32_t fpsr;
1228 uint32_t fpcr;
1229 uint64_t vregs[32 * 2]; /* really uint128_t vregs[32] */
1230};
1231
1232/*
1233 * Auxiliary context saved in the sigcontext.__reserved array. Not exported to
1234 * user space as it will change with the addition of new context. User space
1235 * should check the magic/size information.
1236 */
1237struct target_aux_context {
1238 struct target_fpsimd_context fpsimd;
1239 /* additional context to be added before "end" */
1240 struct target_aarch64_ctx end;
1241};
1242
1243struct target_rt_sigframe {
1244 struct target_siginfo info;
1245 struct target_ucontext uc;
1246 uint64_t fp;
1247 uint64_t lr;
1248 uint32_t tramp[2];
1249};
1250
1251static int target_setup_sigframe(struct target_rt_sigframe *sf,
1252 CPUARMState *env, target_sigset_t *set)
1253{
1254 int i;
1255 struct target_aux_context *aux =
1256 (struct target_aux_context *)sf->uc.tuc_mcontext.__reserved;
1257
1258 /* set up the stack frame for unwinding */
1259 __put_user(env->xregs[29], &sf->fp);
1260 __put_user(env->xregs[30], &sf->lr);
1261
1262 for (i = 0; i < 31; i++) {
1263 __put_user(env->xregs[i], &sf->uc.tuc_mcontext.regs[i]);
1264 }
1265 __put_user(env->xregs[31], &sf->uc.tuc_mcontext.sp);
1266 __put_user(env->pc, &sf->uc.tuc_mcontext.pc);
Peter Maydelld3563122013-12-17 19:42:30 +00001267 __put_user(pstate_read(env), &sf->uc.tuc_mcontext.pstate);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001268
Peter Maydell7af03922014-05-01 18:36:17 +01001269 __put_user(env->exception.vaddress, &sf->uc.tuc_mcontext.fault_address);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001270
1271 for (i = 0; i < TARGET_NSIG_WORDS; i++) {
1272 __put_user(set->sig[i], &sf->uc.tuc_sigmask.sig[i]);
1273 }
1274
1275 for (i = 0; i < 32; i++) {
1276#ifdef TARGET_WORDS_BIGENDIAN
1277 __put_user(env->vfp.regs[i * 2], &aux->fpsimd.vregs[i * 2 + 1]);
1278 __put_user(env->vfp.regs[i * 2 + 1], &aux->fpsimd.vregs[i * 2]);
1279#else
1280 __put_user(env->vfp.regs[i * 2], &aux->fpsimd.vregs[i * 2]);
1281 __put_user(env->vfp.regs[i * 2 + 1], &aux->fpsimd.vregs[i * 2 + 1]);
1282#endif
1283 }
Will Newtone0ee1382014-01-04 22:15:48 +00001284 __put_user(vfp_get_fpsr(env), &aux->fpsimd.fpsr);
1285 __put_user(vfp_get_fpcr(env), &aux->fpsimd.fpcr);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001286 __put_user(TARGET_FPSIMD_MAGIC, &aux->fpsimd.head.magic);
1287 __put_user(sizeof(struct target_fpsimd_context),
1288 &aux->fpsimd.head.size);
1289
1290 /* set the "end" magic */
1291 __put_user(0, &aux->end.magic);
1292 __put_user(0, &aux->end.size);
1293
1294 return 0;
1295}
1296
1297static int target_restore_sigframe(CPUARMState *env,
1298 struct target_rt_sigframe *sf)
1299{
1300 sigset_t set;
1301 int i;
1302 struct target_aux_context *aux =
1303 (struct target_aux_context *)sf->uc.tuc_mcontext.__reserved;
Will Newtone0ee1382014-01-04 22:15:48 +00001304 uint32_t magic, size, fpsr, fpcr;
Peter Maydelld3563122013-12-17 19:42:30 +00001305 uint64_t pstate;
Andreas Schwab1744aea2013-09-03 20:12:16 +01001306
1307 target_to_host_sigset(&set, &sf->uc.tuc_sigmask);
Peter Maydell9eede5b2016-05-27 15:51:46 +01001308 set_sigmask(&set);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001309
1310 for (i = 0; i < 31; i++) {
1311 __get_user(env->xregs[i], &sf->uc.tuc_mcontext.regs[i]);
1312 }
1313
1314 __get_user(env->xregs[31], &sf->uc.tuc_mcontext.sp);
1315 __get_user(env->pc, &sf->uc.tuc_mcontext.pc);
Peter Maydelld3563122013-12-17 19:42:30 +00001316 __get_user(pstate, &sf->uc.tuc_mcontext.pstate);
1317 pstate_write(env, pstate);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001318
1319 __get_user(magic, &aux->fpsimd.head.magic);
1320 __get_user(size, &aux->fpsimd.head.size);
1321
1322 if (magic != TARGET_FPSIMD_MAGIC
1323 || size != sizeof(struct target_fpsimd_context)) {
1324 return 1;
1325 }
1326
Peter Maydell4cf23482014-03-02 19:36:38 +00001327 for (i = 0; i < 32; i++) {
1328#ifdef TARGET_WORDS_BIGENDIAN
1329 __get_user(env->vfp.regs[i * 2], &aux->fpsimd.vregs[i * 2 + 1]);
1330 __get_user(env->vfp.regs[i * 2 + 1], &aux->fpsimd.vregs[i * 2]);
1331#else
1332 __get_user(env->vfp.regs[i * 2], &aux->fpsimd.vregs[i * 2]);
1333 __get_user(env->vfp.regs[i * 2 + 1], &aux->fpsimd.vregs[i * 2 + 1]);
1334#endif
Andreas Schwab1744aea2013-09-03 20:12:16 +01001335 }
Will Newtone0ee1382014-01-04 22:15:48 +00001336 __get_user(fpsr, &aux->fpsimd.fpsr);
1337 vfp_set_fpsr(env, fpsr);
1338 __get_user(fpcr, &aux->fpsimd.fpcr);
1339 vfp_set_fpcr(env, fpcr);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001340
1341 return 0;
1342}
1343
1344static abi_ulong get_sigframe(struct target_sigaction *ka, CPUARMState *env)
1345{
1346 abi_ulong sp;
1347
1348 sp = env->xregs[31];
1349
1350 /*
1351 * This is the X/Open sanctioned signal stack switching.
1352 */
Riku Voipiob545f632014-07-15 17:01:55 +03001353 if ((ka->sa_flags & TARGET_SA_ONSTACK) && !sas_ss_flags(sp)) {
Andreas Schwab1744aea2013-09-03 20:12:16 +01001354 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
1355 }
1356
1357 sp = (sp - sizeof(struct target_rt_sigframe)) & ~15;
1358
1359 return sp;
1360}
1361
1362static void target_setup_frame(int usig, struct target_sigaction *ka,
1363 target_siginfo_t *info, target_sigset_t *set,
1364 CPUARMState *env)
1365{
1366 struct target_rt_sigframe *frame;
Michael Matz8a3ae912014-03-02 19:36:39 +00001367 abi_ulong frame_addr, return_addr;
Andreas Schwab1744aea2013-09-03 20:12:16 +01001368
1369 frame_addr = get_sigframe(ka, env);
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01001370 trace_user_setup_frame(env, frame_addr);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001371 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
1372 goto give_sigsegv;
1373 }
1374
1375 __put_user(0, &frame->uc.tuc_flags);
1376 __put_user(0, &frame->uc.tuc_link);
1377
1378 __put_user(target_sigaltstack_used.ss_sp,
1379 &frame->uc.tuc_stack.ss_sp);
1380 __put_user(sas_ss_flags(env->xregs[31]),
1381 &frame->uc.tuc_stack.ss_flags);
1382 __put_user(target_sigaltstack_used.ss_size,
1383 &frame->uc.tuc_stack.ss_size);
1384 target_setup_sigframe(frame, env, set);
Michael Matz8a3ae912014-03-02 19:36:39 +00001385 if (ka->sa_flags & TARGET_SA_RESTORER) {
1386 return_addr = ka->sa_restorer;
1387 } else {
1388 /* mov x8,#__NR_rt_sigreturn; svc #0 */
1389 __put_user(0xd2801168, &frame->tramp[0]);
1390 __put_user(0xd4000001, &frame->tramp[1]);
1391 return_addr = frame_addr + offsetof(struct target_rt_sigframe, tramp);
1392 }
Andreas Schwab1744aea2013-09-03 20:12:16 +01001393 env->xregs[0] = usig;
1394 env->xregs[31] = frame_addr;
1395 env->xregs[29] = env->xregs[31] + offsetof(struct target_rt_sigframe, fp);
1396 env->pc = ka->_sa_handler;
Michael Matz8a3ae912014-03-02 19:36:39 +00001397 env->xregs[30] = return_addr;
Andreas Schwab1744aea2013-09-03 20:12:16 +01001398 if (info) {
Peter Maydellf6c7a052015-01-08 12:19:48 +00001399 tswap_siginfo(&frame->info, info);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001400 env->xregs[1] = frame_addr + offsetof(struct target_rt_sigframe, info);
1401 env->xregs[2] = frame_addr + offsetof(struct target_rt_sigframe, uc);
1402 }
1403
1404 unlock_user_struct(frame, frame_addr, 1);
1405 return;
1406
1407 give_sigsegv:
1408 unlock_user_struct(frame, frame_addr, 1);
1409 force_sig(TARGET_SIGSEGV);
1410}
1411
1412static void setup_rt_frame(int sig, struct target_sigaction *ka,
1413 target_siginfo_t *info, target_sigset_t *set,
1414 CPUARMState *env)
1415{
1416 target_setup_frame(sig, ka, info, set, env);
1417}
1418
1419static void setup_frame(int sig, struct target_sigaction *ka,
1420 target_sigset_t *set, CPUARMState *env)
1421{
1422 target_setup_frame(sig, ka, 0, set, env);
1423}
1424
1425long do_rt_sigreturn(CPUARMState *env)
1426{
Peter Maydell7f72cd22014-03-12 13:06:00 +00001427 struct target_rt_sigframe *frame = NULL;
Andreas Schwab1744aea2013-09-03 20:12:16 +01001428 abi_ulong frame_addr = env->xregs[31];
1429
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01001430 trace_user_do_rt_sigreturn(env, frame_addr);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001431 if (frame_addr & 15) {
1432 goto badframe;
1433 }
1434
1435 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
1436 goto badframe;
1437 }
1438
1439 if (target_restore_sigframe(env, frame)) {
1440 goto badframe;
1441 }
1442
1443 if (do_sigaltstack(frame_addr +
1444 offsetof(struct target_rt_sigframe, uc.tuc_stack),
1445 0, get_sp_from_cpustate(env)) == -EFAULT) {
1446 goto badframe;
1447 }
1448
1449 unlock_user_struct(frame, frame_addr, 0);
Timothy E Baldwinf0267ef2016-05-12 18:47:31 +01001450 return -TARGET_QEMU_ESIGRETURN;
Andreas Schwab1744aea2013-09-03 20:12:16 +01001451
1452 badframe:
1453 unlock_user_struct(frame, frame_addr, 0);
1454 force_sig(TARGET_SIGSEGV);
1455 return 0;
1456}
1457
1458long do_sigreturn(CPUARMState *env)
1459{
1460 return do_rt_sigreturn(env);
1461}
1462
bellard43fff232003-07-09 19:31:39 +00001463#elif defined(TARGET_ARM)
1464
1465struct target_sigcontext {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001466 abi_ulong trap_no;
1467 abi_ulong error_code;
1468 abi_ulong oldmask;
1469 abi_ulong arm_r0;
1470 abi_ulong arm_r1;
1471 abi_ulong arm_r2;
1472 abi_ulong arm_r3;
1473 abi_ulong arm_r4;
1474 abi_ulong arm_r5;
1475 abi_ulong arm_r6;
1476 abi_ulong arm_r7;
1477 abi_ulong arm_r8;
1478 abi_ulong arm_r9;
1479 abi_ulong arm_r10;
1480 abi_ulong arm_fp;
1481 abi_ulong arm_ip;
1482 abi_ulong arm_sp;
1483 abi_ulong arm_lr;
1484 abi_ulong arm_pc;
1485 abi_ulong arm_cpsr;
1486 abi_ulong fault_address;
bellard43fff232003-07-09 19:31:39 +00001487};
1488
pbrooka745ec62008-05-06 15:36:17 +00001489struct target_ucontext_v1 {
blueswir1992f48a2007-10-14 16:27:31 +00001490 abi_ulong tuc_flags;
1491 abi_ulong tuc_link;
Anthony Liguoric227f092009-10-01 16:12:16 -05001492 target_stack_t tuc_stack;
bellardb8076a72005-04-07 22:20:31 +00001493 struct target_sigcontext tuc_mcontext;
Anthony Liguoric227f092009-10-01 16:12:16 -05001494 target_sigset_t tuc_sigmask; /* mask last for extensibility */
bellard43fff232003-07-09 19:31:39 +00001495};
1496
pbrooka745ec62008-05-06 15:36:17 +00001497struct target_ucontext_v2 {
1498 abi_ulong tuc_flags;
1499 abi_ulong tuc_link;
Anthony Liguoric227f092009-10-01 16:12:16 -05001500 target_stack_t tuc_stack;
pbrooka745ec62008-05-06 15:36:17 +00001501 struct target_sigcontext tuc_mcontext;
Anthony Liguoric227f092009-10-01 16:12:16 -05001502 target_sigset_t tuc_sigmask; /* mask last for extensibility */
Peter Maydell5f0b7c82010-11-24 15:20:03 +00001503 char __unused[128 - sizeof(target_sigset_t)];
pbrooka745ec62008-05-06 15:36:17 +00001504 abi_ulong tuc_regspace[128] __attribute__((__aligned__(8)));
1505};
1506
Peter Maydell0d871bd2010-11-24 15:20:05 +00001507struct target_user_vfp {
1508 uint64_t fpregs[32];
1509 abi_ulong fpscr;
1510};
1511
1512struct target_user_vfp_exc {
1513 abi_ulong fpexc;
1514 abi_ulong fpinst;
1515 abi_ulong fpinst2;
1516};
1517
1518struct target_vfp_sigframe {
1519 abi_ulong magic;
1520 abi_ulong size;
1521 struct target_user_vfp ufp;
1522 struct target_user_vfp_exc ufp_exc;
1523} __attribute__((__aligned__(8)));
1524
Peter Maydell08e11252010-11-24 15:20:07 +00001525struct target_iwmmxt_sigframe {
1526 abi_ulong magic;
1527 abi_ulong size;
1528 uint64_t regs[16];
1529 /* Note that not all the coprocessor control registers are stored here */
1530 uint32_t wcssf;
1531 uint32_t wcasf;
1532 uint32_t wcgr0;
1533 uint32_t wcgr1;
1534 uint32_t wcgr2;
1535 uint32_t wcgr3;
1536} __attribute__((__aligned__(8)));
1537
Peter Maydell0d871bd2010-11-24 15:20:05 +00001538#define TARGET_VFP_MAGIC 0x56465001
Peter Maydell08e11252010-11-24 15:20:07 +00001539#define TARGET_IWMMXT_MAGIC 0x12ef842a
Peter Maydell0d871bd2010-11-24 15:20:05 +00001540
pbrooka8c33202008-05-07 23:22:46 +00001541struct sigframe_v1
bellard43fff232003-07-09 19:31:39 +00001542{
1543 struct target_sigcontext sc;
blueswir1992f48a2007-10-14 16:27:31 +00001544 abi_ulong extramask[TARGET_NSIG_WORDS-1];
1545 abi_ulong retcode;
bellard43fff232003-07-09 19:31:39 +00001546};
1547
pbrooka8c33202008-05-07 23:22:46 +00001548struct sigframe_v2
1549{
1550 struct target_ucontext_v2 uc;
1551 abi_ulong retcode;
1552};
1553
pbrooka745ec62008-05-06 15:36:17 +00001554struct rt_sigframe_v1
bellard43fff232003-07-09 19:31:39 +00001555{
bellardf8b0aa22007-11-11 23:03:42 +00001556 abi_ulong pinfo;
1557 abi_ulong puc;
bellard43fff232003-07-09 19:31:39 +00001558 struct target_siginfo info;
pbrooka745ec62008-05-06 15:36:17 +00001559 struct target_ucontext_v1 uc;
1560 abi_ulong retcode;
1561};
1562
1563struct rt_sigframe_v2
1564{
1565 struct target_siginfo info;
1566 struct target_ucontext_v2 uc;
blueswir1992f48a2007-10-14 16:27:31 +00001567 abi_ulong retcode;
bellard43fff232003-07-09 19:31:39 +00001568};
1569
1570#define TARGET_CONFIG_CPU_32 1
1571
1572/*
1573 * For ARM syscalls, we encode the syscall number into the instruction.
1574 */
1575#define SWI_SYS_SIGRETURN (0xef000000|(TARGET_NR_sigreturn + ARM_SYSCALL_BASE))
1576#define SWI_SYS_RT_SIGRETURN (0xef000000|(TARGET_NR_rt_sigreturn + ARM_SYSCALL_BASE))
1577
1578/*
1579 * For Thumb syscalls, we pass the syscall number via r7. We therefore
1580 * need two 16-bit instructions.
1581 */
1582#define SWI_THUMB_SIGRETURN (0xdf00 << 16 | 0x2700 | (TARGET_NR_sigreturn))
1583#define SWI_THUMB_RT_SIGRETURN (0xdf00 << 16 | 0x2700 | (TARGET_NR_rt_sigreturn))
1584
blueswir1992f48a2007-10-14 16:27:31 +00001585static const abi_ulong retcodes[4] = {
bellard43fff232003-07-09 19:31:39 +00001586 SWI_SYS_SIGRETURN, SWI_THUMB_SIGRETURN,
1587 SWI_SYS_RT_SIGRETURN, SWI_THUMB_RT_SIGRETURN
1588};
1589
1590
Andreas Färber05390242012-02-25 03:37:53 +01001591static inline int valid_user_regs(CPUARMState *regs)
bellard43fff232003-07-09 19:31:39 +00001592{
1593 return 1;
1594}
1595
pbrooka8c33202008-05-07 23:22:46 +00001596static void
bellard43fff232003-07-09 19:31:39 +00001597setup_sigcontext(struct target_sigcontext *sc, /*struct _fpstate *fpstate,*/
Andreas Färber05390242012-02-25 03:37:53 +01001598 CPUARMState *env, abi_ulong mask)
bellard43fff232003-07-09 19:31:39 +00001599{
Paolo Bonzinia0e1e6d2016-03-04 11:30:18 +00001600 __put_user(env->regs[0], &sc->arm_r0);
1601 __put_user(env->regs[1], &sc->arm_r1);
1602 __put_user(env->regs[2], &sc->arm_r2);
1603 __put_user(env->regs[3], &sc->arm_r3);
1604 __put_user(env->regs[4], &sc->arm_r4);
1605 __put_user(env->regs[5], &sc->arm_r5);
1606 __put_user(env->regs[6], &sc->arm_r6);
1607 __put_user(env->regs[7], &sc->arm_r7);
1608 __put_user(env->regs[8], &sc->arm_r8);
1609 __put_user(env->regs[9], &sc->arm_r9);
1610 __put_user(env->regs[10], &sc->arm_r10);
1611 __put_user(env->regs[11], &sc->arm_fp);
1612 __put_user(env->regs[12], &sc->arm_ip);
1613 __put_user(env->regs[13], &sc->arm_sp);
1614 __put_user(env->regs[14], &sc->arm_lr);
1615 __put_user(env->regs[15], &sc->arm_pc);
bellard43fff232003-07-09 19:31:39 +00001616#ifdef TARGET_CONFIG_CPU_32
Paolo Bonzinia0e1e6d2016-03-04 11:30:18 +00001617 __put_user(cpsr_read(env), &sc->arm_cpsr);
bellard43fff232003-07-09 19:31:39 +00001618#endif
1619
Paolo Bonzinia0e1e6d2016-03-04 11:30:18 +00001620 __put_user(/* current->thread.trap_no */ 0, &sc->trap_no);
1621 __put_user(/* current->thread.error_code */ 0, &sc->error_code);
1622 __put_user(/* current->thread.address */ 0, &sc->fault_address);
1623 __put_user(mask, &sc->oldmask);
bellard43fff232003-07-09 19:31:39 +00001624}
1625
bellard579a97f2007-11-11 14:26:47 +00001626static inline abi_ulong
Andreas Färber05390242012-02-25 03:37:53 +01001627get_sigframe(struct target_sigaction *ka, CPUARMState *regs, int framesize)
bellard43fff232003-07-09 19:31:39 +00001628{
Paolo Bonzinia0e1e6d2016-03-04 11:30:18 +00001629 unsigned long sp = regs->regs[13];
bellard43fff232003-07-09 19:31:39 +00001630
Paolo Bonzinia0e1e6d2016-03-04 11:30:18 +00001631 /*
1632 * This is the X/Open sanctioned signal stack switching.
1633 */
1634 if ((ka->sa_flags & TARGET_SA_ONSTACK) && !sas_ss_flags(sp)) {
1635 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
1636 }
1637 /*
1638 * ATPCS B01 mandates 8-byte alignment
1639 */
1640 return (sp - framesize) & ~7;
bellard43fff232003-07-09 19:31:39 +00001641}
1642
Riku Voipio0188fad2014-04-23 13:34:15 +03001643static void
Andreas Färber05390242012-02-25 03:37:53 +01001644setup_return(CPUARMState *env, struct target_sigaction *ka,
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001645 abi_ulong *rc, abi_ulong frame_addr, int usig, abi_ulong rc_addr)
bellard43fff232003-07-09 19:31:39 +00001646{
Paolo Bonzinia0e1e6d2016-03-04 11:30:18 +00001647 abi_ulong handler = ka->_sa_handler;
1648 abi_ulong retcode;
1649 int thumb = handler & 1;
1650 uint32_t cpsr = cpsr_read(env);
Peter Maydell964413d2011-01-14 20:39:19 +01001651
Paolo Bonzinia0e1e6d2016-03-04 11:30:18 +00001652 cpsr &= ~CPSR_IT;
1653 if (thumb) {
1654 cpsr |= CPSR_T;
1655 } else {
1656 cpsr &= ~CPSR_T;
1657 }
bellard43fff232003-07-09 19:31:39 +00001658
Paolo Bonzinia0e1e6d2016-03-04 11:30:18 +00001659 if (ka->sa_flags & TARGET_SA_RESTORER) {
1660 retcode = ka->sa_restorer;
1661 } else {
1662 unsigned int idx = thumb;
bellard43fff232003-07-09 19:31:39 +00001663
Paolo Bonzinia0e1e6d2016-03-04 11:30:18 +00001664 if (ka->sa_flags & TARGET_SA_SIGINFO) {
1665 idx += 2;
1666 }
bellard43fff232003-07-09 19:31:39 +00001667
Riku Voipio0188fad2014-04-23 13:34:15 +03001668 __put_user(retcodes[idx], rc);
Stefan Weilca8a2772011-10-03 22:43:19 +02001669
Paolo Bonzinia0e1e6d2016-03-04 11:30:18 +00001670 retcode = rc_addr + thumb;
1671 }
bellard43fff232003-07-09 19:31:39 +00001672
Paolo Bonzinia0e1e6d2016-03-04 11:30:18 +00001673 env->regs[0] = usig;
1674 env->regs[13] = frame_addr;
1675 env->regs[14] = retcode;
1676 env->regs[15] = handler & (thumb ? ~1 : ~3);
1677 cpsr_write(env, cpsr, CPSR_IT | CPSR_T, CPSRWriteByInstr);
bellard43fff232003-07-09 19:31:39 +00001678}
1679
Andreas Färber05390242012-02-25 03:37:53 +01001680static abi_ulong *setup_sigframe_v2_vfp(abi_ulong *regspace, CPUARMState *env)
Peter Maydell0d871bd2010-11-24 15:20:05 +00001681{
1682 int i;
1683 struct target_vfp_sigframe *vfpframe;
1684 vfpframe = (struct target_vfp_sigframe *)regspace;
1685 __put_user(TARGET_VFP_MAGIC, &vfpframe->magic);
1686 __put_user(sizeof(*vfpframe), &vfpframe->size);
1687 for (i = 0; i < 32; i++) {
Peter Maydell005e1a02011-02-10 13:59:35 +00001688 __put_user(float64_val(env->vfp.regs[i]), &vfpframe->ufp.fpregs[i]);
Peter Maydell0d871bd2010-11-24 15:20:05 +00001689 }
1690 __put_user(vfp_get_fpscr(env), &vfpframe->ufp.fpscr);
1691 __put_user(env->vfp.xregs[ARM_VFP_FPEXC], &vfpframe->ufp_exc.fpexc);
1692 __put_user(env->vfp.xregs[ARM_VFP_FPINST], &vfpframe->ufp_exc.fpinst);
1693 __put_user(env->vfp.xregs[ARM_VFP_FPINST2], &vfpframe->ufp_exc.fpinst2);
1694 return (abi_ulong*)(vfpframe+1);
1695}
1696
Andreas Färber05390242012-02-25 03:37:53 +01001697static abi_ulong *setup_sigframe_v2_iwmmxt(abi_ulong *regspace,
1698 CPUARMState *env)
Peter Maydell08e11252010-11-24 15:20:07 +00001699{
1700 int i;
1701 struct target_iwmmxt_sigframe *iwmmxtframe;
1702 iwmmxtframe = (struct target_iwmmxt_sigframe *)regspace;
1703 __put_user(TARGET_IWMMXT_MAGIC, &iwmmxtframe->magic);
1704 __put_user(sizeof(*iwmmxtframe), &iwmmxtframe->size);
1705 for (i = 0; i < 16; i++) {
1706 __put_user(env->iwmmxt.regs[i], &iwmmxtframe->regs[i]);
1707 }
1708 __put_user(env->vfp.xregs[ARM_IWMMXT_wCSSF], &iwmmxtframe->wcssf);
1709 __put_user(env->vfp.xregs[ARM_IWMMXT_wCASF], &iwmmxtframe->wcssf);
1710 __put_user(env->vfp.xregs[ARM_IWMMXT_wCGR0], &iwmmxtframe->wcgr0);
1711 __put_user(env->vfp.xregs[ARM_IWMMXT_wCGR1], &iwmmxtframe->wcgr1);
1712 __put_user(env->vfp.xregs[ARM_IWMMXT_wCGR2], &iwmmxtframe->wcgr2);
1713 __put_user(env->vfp.xregs[ARM_IWMMXT_wCGR3], &iwmmxtframe->wcgr3);
1714 return (abi_ulong*)(iwmmxtframe+1);
1715}
1716
pbrooka8c33202008-05-07 23:22:46 +00001717static void setup_sigframe_v2(struct target_ucontext_v2 *uc,
Andreas Färber05390242012-02-25 03:37:53 +01001718 target_sigset_t *set, CPUARMState *env)
bellard43fff232003-07-09 19:31:39 +00001719{
pbrooka8c33202008-05-07 23:22:46 +00001720 struct target_sigaltstack stack;
1721 int i;
Peter Maydell0d871bd2010-11-24 15:20:05 +00001722 abi_ulong *regspace;
pbrooka8c33202008-05-07 23:22:46 +00001723
1724 /* Clear all the bits of the ucontext we don't use. */
1725 memset(uc, 0, offsetof(struct target_ucontext_v2, tuc_mcontext));
1726
1727 memset(&stack, 0, sizeof(stack));
1728 __put_user(target_sigaltstack_used.ss_sp, &stack.ss_sp);
1729 __put_user(target_sigaltstack_used.ss_size, &stack.ss_size);
1730 __put_user(sas_ss_flags(get_sp_from_cpustate(env)), &stack.ss_flags);
1731 memcpy(&uc->tuc_stack, &stack, sizeof(stack));
1732
1733 setup_sigcontext(&uc->tuc_mcontext, env, set->sig[0]);
Peter Maydell0d871bd2010-11-24 15:20:05 +00001734 /* Save coprocessor signal frame. */
1735 regspace = uc->tuc_regspace;
1736 if (arm_feature(env, ARM_FEATURE_VFP)) {
1737 regspace = setup_sigframe_v2_vfp(regspace, env);
1738 }
Peter Maydell08e11252010-11-24 15:20:07 +00001739 if (arm_feature(env, ARM_FEATURE_IWMMXT)) {
1740 regspace = setup_sigframe_v2_iwmmxt(regspace, env);
1741 }
1742
Peter Maydell0d871bd2010-11-24 15:20:05 +00001743 /* Write terminating magic word */
1744 __put_user(0, regspace);
1745
pbrooka8c33202008-05-07 23:22:46 +00001746 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
1747 __put_user(set->sig[i], &uc->tuc_sigmask.sig[i]);
1748 }
1749}
1750
1751/* compare linux/arch/arm/kernel/signal.c:setup_frame() */
pbrook624f7972008-05-31 16:11:38 +00001752static void setup_frame_v1(int usig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01001753 target_sigset_t *set, CPUARMState *regs)
pbrooka8c33202008-05-07 23:22:46 +00001754{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001755 struct sigframe_v1 *frame;
1756 abi_ulong frame_addr = get_sigframe(ka, regs, sizeof(*frame));
1757 int i;
bellard43fff232003-07-09 19:31:39 +00001758
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001759 trace_user_setup_frame(regs, frame_addr);
1760 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
1761 return;
1762 }
bellard579a97f2007-11-11 14:26:47 +00001763
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001764 setup_sigcontext(&frame->sc, regs, set->sig[0]);
bellard43fff232003-07-09 19:31:39 +00001765
Riku Voipio0188fad2014-04-23 13:34:15 +03001766 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
1767 __put_user(set->sig[i], &frame->extramask[i - 1]);
1768 }
bellard43fff232003-07-09 19:31:39 +00001769
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001770 setup_return(regs, ka, &frame->retcode, frame_addr, usig,
1771 frame_addr + offsetof(struct sigframe_v1, retcode));
bellard579a97f2007-11-11 14:26:47 +00001772
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001773 unlock_user_struct(frame, frame_addr, 1);
pbrooka8c33202008-05-07 23:22:46 +00001774}
1775
pbrook624f7972008-05-31 16:11:38 +00001776static void setup_frame_v2(int usig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01001777 target_sigset_t *set, CPUARMState *regs)
pbrooka8c33202008-05-07 23:22:46 +00001778{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001779 struct sigframe_v2 *frame;
1780 abi_ulong frame_addr = get_sigframe(ka, regs, sizeof(*frame));
pbrooka8c33202008-05-07 23:22:46 +00001781
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001782 trace_user_setup_frame(regs, frame_addr);
1783 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
1784 return;
1785 }
pbrooka8c33202008-05-07 23:22:46 +00001786
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001787 setup_sigframe_v2(&frame->uc, set, regs);
pbrooka8c33202008-05-07 23:22:46 +00001788
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001789 setup_return(regs, ka, &frame->retcode, frame_addr, usig,
1790 frame_addr + offsetof(struct sigframe_v2, retcode));
pbrooka8c33202008-05-07 23:22:46 +00001791
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001792 unlock_user_struct(frame, frame_addr, 1);
pbrooka8c33202008-05-07 23:22:46 +00001793}
1794
pbrook624f7972008-05-31 16:11:38 +00001795static void setup_frame(int usig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01001796 target_sigset_t *set, CPUARMState *regs)
pbrooka8c33202008-05-07 23:22:46 +00001797{
1798 if (get_osversion() >= 0x020612) {
1799 setup_frame_v2(usig, ka, set, regs);
1800 } else {
1801 setup_frame_v1(usig, ka, set, regs);
1802 }
bellard43fff232003-07-09 19:31:39 +00001803}
1804
bellard579a97f2007-11-11 14:26:47 +00001805/* compare linux/arch/arm/kernel/signal.c:setup_rt_frame() */
pbrook624f7972008-05-31 16:11:38 +00001806static void setup_rt_frame_v1(int usig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05001807 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01001808 target_sigset_t *set, CPUARMState *env)
bellard43fff232003-07-09 19:31:39 +00001809{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001810 struct rt_sigframe_v1 *frame;
1811 abi_ulong frame_addr = get_sigframe(ka, env, sizeof(*frame));
1812 struct target_sigaltstack stack;
1813 int i;
1814 abi_ulong info_addr, uc_addr;
bellard43fff232003-07-09 19:31:39 +00001815
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001816 trace_user_setup_rt_frame(env, frame_addr);
1817 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
1818 return /* 1 */;
1819 }
bellardedf779f2004-02-22 13:40:13 +00001820
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001821 info_addr = frame_addr + offsetof(struct rt_sigframe_v1, info);
1822 __put_user(info_addr, &frame->pinfo);
1823 uc_addr = frame_addr + offsetof(struct rt_sigframe_v1, uc);
1824 __put_user(uc_addr, &frame->puc);
1825 tswap_siginfo(&frame->info, info);
bellard43fff232003-07-09 19:31:39 +00001826
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001827 /* Clear all the bits of the ucontext we don't use. */
1828 memset(&frame->uc, 0, offsetof(struct target_ucontext_v1, tuc_mcontext));
bellard43fff232003-07-09 19:31:39 +00001829
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001830 memset(&stack, 0, sizeof(stack));
1831 __put_user(target_sigaltstack_used.ss_sp, &stack.ss_sp);
1832 __put_user(target_sigaltstack_used.ss_size, &stack.ss_size);
1833 __put_user(sas_ss_flags(get_sp_from_cpustate(env)), &stack.ss_flags);
1834 memcpy(&frame->uc.tuc_stack, &stack, sizeof(stack));
thsa04e1342007-09-27 13:57:58 +00001835
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001836 setup_sigcontext(&frame->uc.tuc_mcontext, env, set->sig[0]);
1837 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
1838 __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
1839 }
bellard43fff232003-07-09 19:31:39 +00001840
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001841 setup_return(env, ka, &frame->retcode, frame_addr, usig,
1842 frame_addr + offsetof(struct rt_sigframe_v1, retcode));
pbrooka745ec62008-05-06 15:36:17 +00001843
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001844 env->regs[1] = info_addr;
1845 env->regs[2] = uc_addr;
pbrooka745ec62008-05-06 15:36:17 +00001846
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001847 unlock_user_struct(frame, frame_addr, 1);
pbrooka745ec62008-05-06 15:36:17 +00001848}
1849
pbrook624f7972008-05-31 16:11:38 +00001850static void setup_rt_frame_v2(int usig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05001851 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01001852 target_sigset_t *set, CPUARMState *env)
pbrooka745ec62008-05-06 15:36:17 +00001853{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001854 struct rt_sigframe_v2 *frame;
1855 abi_ulong frame_addr = get_sigframe(ka, env, sizeof(*frame));
1856 abi_ulong info_addr, uc_addr;
pbrooka745ec62008-05-06 15:36:17 +00001857
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001858 trace_user_setup_rt_frame(env, frame_addr);
1859 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
1860 return /* 1 */;
1861 }
pbrooka745ec62008-05-06 15:36:17 +00001862
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001863 info_addr = frame_addr + offsetof(struct rt_sigframe_v2, info);
1864 uc_addr = frame_addr + offsetof(struct rt_sigframe_v2, uc);
1865 tswap_siginfo(&frame->info, info);
pbrooka745ec62008-05-06 15:36:17 +00001866
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001867 setup_sigframe_v2(&frame->uc, set, env);
pbrooka745ec62008-05-06 15:36:17 +00001868
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001869 setup_return(env, ka, &frame->retcode, frame_addr, usig,
1870 frame_addr + offsetof(struct rt_sigframe_v2, retcode));
pbrooka745ec62008-05-06 15:36:17 +00001871
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001872 env->regs[1] = info_addr;
1873 env->regs[2] = uc_addr;
pbrooka745ec62008-05-06 15:36:17 +00001874
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001875 unlock_user_struct(frame, frame_addr, 1);
bellard43fff232003-07-09 19:31:39 +00001876}
1877
pbrook624f7972008-05-31 16:11:38 +00001878static void setup_rt_frame(int usig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05001879 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01001880 target_sigset_t *set, CPUARMState *env)
pbrooka745ec62008-05-06 15:36:17 +00001881{
1882 if (get_osversion() >= 0x020612) {
1883 setup_rt_frame_v2(usig, ka, info, set, env);
1884 } else {
1885 setup_rt_frame_v1(usig, ka, info, set, env);
1886 }
1887}
1888
bellard43fff232003-07-09 19:31:39 +00001889static int
Andreas Färber05390242012-02-25 03:37:53 +01001890restore_sigcontext(CPUARMState *env, struct target_sigcontext *sc)
bellard43fff232003-07-09 19:31:39 +00001891{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001892 int err = 0;
1893 uint32_t cpsr;
bellard43fff232003-07-09 19:31:39 +00001894
Riku Voipio1d8b5122014-04-23 10:26:05 +03001895 __get_user(env->regs[0], &sc->arm_r0);
1896 __get_user(env->regs[1], &sc->arm_r1);
1897 __get_user(env->regs[2], &sc->arm_r2);
1898 __get_user(env->regs[3], &sc->arm_r3);
1899 __get_user(env->regs[4], &sc->arm_r4);
1900 __get_user(env->regs[5], &sc->arm_r5);
1901 __get_user(env->regs[6], &sc->arm_r6);
1902 __get_user(env->regs[7], &sc->arm_r7);
1903 __get_user(env->regs[8], &sc->arm_r8);
1904 __get_user(env->regs[9], &sc->arm_r9);
1905 __get_user(env->regs[10], &sc->arm_r10);
1906 __get_user(env->regs[11], &sc->arm_fp);
1907 __get_user(env->regs[12], &sc->arm_ip);
1908 __get_user(env->regs[13], &sc->arm_sp);
1909 __get_user(env->regs[14], &sc->arm_lr);
1910 __get_user(env->regs[15], &sc->arm_pc);
bellard43fff232003-07-09 19:31:39 +00001911#ifdef TARGET_CONFIG_CPU_32
Riku Voipio1d8b5122014-04-23 10:26:05 +03001912 __get_user(cpsr, &sc->arm_cpsr);
Peter Maydell50866ba2016-02-23 15:36:43 +00001913 cpsr_write(env, cpsr, CPSR_USER | CPSR_EXEC, CPSRWriteByInstr);
bellard43fff232003-07-09 19:31:39 +00001914#endif
1915
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001916 err |= !valid_user_regs(env);
bellard43fff232003-07-09 19:31:39 +00001917
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001918 return err;
bellard43fff232003-07-09 19:31:39 +00001919}
1920
Andreas Färber05390242012-02-25 03:37:53 +01001921static long do_sigreturn_v1(CPUARMState *env)
bellard43fff232003-07-09 19:31:39 +00001922{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001923 abi_ulong frame_addr;
1924 struct sigframe_v1 *frame = NULL;
1925 target_sigset_t set;
1926 sigset_t host_set;
1927 int i;
bellard43fff232003-07-09 19:31:39 +00001928
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001929 /*
1930 * Since we stacked the signal on a 64-bit boundary,
1931 * then 'sp' should be word aligned here. If it's
1932 * not, then the user is trying to mess with us.
1933 */
1934 frame_addr = env->regs[13];
1935 trace_user_do_sigreturn(env, frame_addr);
1936 if (frame_addr & 7) {
1937 goto badframe;
1938 }
Peter Maydell978fae92013-07-29 12:00:32 +01001939
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001940 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
1941 goto badframe;
1942 }
bellard43fff232003-07-09 19:31:39 +00001943
Riku Voipiof5f601a2014-04-23 13:00:17 +03001944 __get_user(set.sig[0], &frame->sc.oldmask);
1945 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
1946 __get_user(set.sig[i], &frame->extramask[i - 1]);
1947 }
bellard43fff232003-07-09 19:31:39 +00001948
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001949 target_to_host_sigset_internal(&host_set, &set);
Peter Maydell9eede5b2016-05-27 15:51:46 +01001950 set_sigmask(&host_set);
bellard43fff232003-07-09 19:31:39 +00001951
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001952 if (restore_sigcontext(env, &frame->sc)) {
1953 goto badframe;
1954 }
bellard43fff232003-07-09 19:31:39 +00001955
1956#if 0
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001957 /* Send SIGTRAP if we're single-stepping */
1958 if (ptrace_cancel_bpt(current))
1959 send_sig(SIGTRAP, current, 1);
bellard43fff232003-07-09 19:31:39 +00001960#endif
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001961 unlock_user_struct(frame, frame_addr, 0);
Timothy E Baldwinf0267ef2016-05-12 18:47:31 +01001962 return -TARGET_QEMU_ESIGRETURN;
bellard43fff232003-07-09 19:31:39 +00001963
1964badframe:
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001965 force_sig(TARGET_SIGSEGV /* , current */);
1966 return 0;
bellard43fff232003-07-09 19:31:39 +00001967}
1968
Andreas Färber05390242012-02-25 03:37:53 +01001969static abi_ulong *restore_sigframe_v2_vfp(CPUARMState *env, abi_ulong *regspace)
Peter Maydell5f9099d2010-11-24 15:20:06 +00001970{
1971 int i;
1972 abi_ulong magic, sz;
1973 uint32_t fpscr, fpexc;
1974 struct target_vfp_sigframe *vfpframe;
1975 vfpframe = (struct target_vfp_sigframe *)regspace;
1976
1977 __get_user(magic, &vfpframe->magic);
1978 __get_user(sz, &vfpframe->size);
1979 if (magic != TARGET_VFP_MAGIC || sz != sizeof(*vfpframe)) {
1980 return 0;
1981 }
1982 for (i = 0; i < 32; i++) {
Peter Maydell005e1a02011-02-10 13:59:35 +00001983 __get_user(float64_val(env->vfp.regs[i]), &vfpframe->ufp.fpregs[i]);
Peter Maydell5f9099d2010-11-24 15:20:06 +00001984 }
1985 __get_user(fpscr, &vfpframe->ufp.fpscr);
1986 vfp_set_fpscr(env, fpscr);
1987 __get_user(fpexc, &vfpframe->ufp_exc.fpexc);
1988 /* Sanitise FPEXC: ensure VFP is enabled, FPINST2 is invalid
1989 * and the exception flag is cleared
1990 */
1991 fpexc |= (1 << 30);
1992 fpexc &= ~((1 << 31) | (1 << 28));
1993 env->vfp.xregs[ARM_VFP_FPEXC] = fpexc;
1994 __get_user(env->vfp.xregs[ARM_VFP_FPINST], &vfpframe->ufp_exc.fpinst);
1995 __get_user(env->vfp.xregs[ARM_VFP_FPINST2], &vfpframe->ufp_exc.fpinst2);
1996 return (abi_ulong*)(vfpframe + 1);
1997}
1998
Andreas Färber05390242012-02-25 03:37:53 +01001999static abi_ulong *restore_sigframe_v2_iwmmxt(CPUARMState *env,
2000 abi_ulong *regspace)
Peter Maydella59d69d2010-11-24 15:20:08 +00002001{
2002 int i;
2003 abi_ulong magic, sz;
2004 struct target_iwmmxt_sigframe *iwmmxtframe;
2005 iwmmxtframe = (struct target_iwmmxt_sigframe *)regspace;
2006
2007 __get_user(magic, &iwmmxtframe->magic);
2008 __get_user(sz, &iwmmxtframe->size);
2009 if (magic != TARGET_IWMMXT_MAGIC || sz != sizeof(*iwmmxtframe)) {
2010 return 0;
2011 }
2012 for (i = 0; i < 16; i++) {
2013 __get_user(env->iwmmxt.regs[i], &iwmmxtframe->regs[i]);
2014 }
2015 __get_user(env->vfp.xregs[ARM_IWMMXT_wCSSF], &iwmmxtframe->wcssf);
2016 __get_user(env->vfp.xregs[ARM_IWMMXT_wCASF], &iwmmxtframe->wcssf);
2017 __get_user(env->vfp.xregs[ARM_IWMMXT_wCGR0], &iwmmxtframe->wcgr0);
2018 __get_user(env->vfp.xregs[ARM_IWMMXT_wCGR1], &iwmmxtframe->wcgr1);
2019 __get_user(env->vfp.xregs[ARM_IWMMXT_wCGR2], &iwmmxtframe->wcgr2);
2020 __get_user(env->vfp.xregs[ARM_IWMMXT_wCGR3], &iwmmxtframe->wcgr3);
2021 return (abi_ulong*)(iwmmxtframe + 1);
2022}
2023
Andreas Färber05390242012-02-25 03:37:53 +01002024static int do_sigframe_return_v2(CPUARMState *env, target_ulong frame_addr,
pbrooka8c33202008-05-07 23:22:46 +00002025 struct target_ucontext_v2 *uc)
2026{
2027 sigset_t host_set;
Peter Maydell5f9099d2010-11-24 15:20:06 +00002028 abi_ulong *regspace;
pbrooka8c33202008-05-07 23:22:46 +00002029
2030 target_to_host_sigset(&host_set, &uc->tuc_sigmask);
Peter Maydell9eede5b2016-05-27 15:51:46 +01002031 set_sigmask(&host_set);
pbrooka8c33202008-05-07 23:22:46 +00002032
2033 if (restore_sigcontext(env, &uc->tuc_mcontext))
2034 return 1;
2035
Peter Maydell5f9099d2010-11-24 15:20:06 +00002036 /* Restore coprocessor signal frame */
2037 regspace = uc->tuc_regspace;
2038 if (arm_feature(env, ARM_FEATURE_VFP)) {
2039 regspace = restore_sigframe_v2_vfp(env, regspace);
2040 if (!regspace) {
2041 return 1;
2042 }
2043 }
Peter Maydella59d69d2010-11-24 15:20:08 +00002044 if (arm_feature(env, ARM_FEATURE_IWMMXT)) {
2045 regspace = restore_sigframe_v2_iwmmxt(env, regspace);
2046 if (!regspace) {
2047 return 1;
2048 }
2049 }
Peter Maydell5f9099d2010-11-24 15:20:06 +00002050
pbrooka8c33202008-05-07 23:22:46 +00002051 if (do_sigaltstack(frame_addr + offsetof(struct target_ucontext_v2, tuc_stack), 0, get_sp_from_cpustate(env)) == -EFAULT)
2052 return 1;
2053
2054#if 0
2055 /* Send SIGTRAP if we're single-stepping */
2056 if (ptrace_cancel_bpt(current))
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002057 send_sig(SIGTRAP, current, 1);
pbrooka8c33202008-05-07 23:22:46 +00002058#endif
2059
2060 return 0;
2061}
2062
Andreas Färber05390242012-02-25 03:37:53 +01002063static long do_sigreturn_v2(CPUARMState *env)
pbrooka8c33202008-05-07 23:22:46 +00002064{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002065 abi_ulong frame_addr;
2066 struct sigframe_v2 *frame = NULL;
pbrooka8c33202008-05-07 23:22:46 +00002067
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002068 /*
2069 * Since we stacked the signal on a 64-bit boundary,
2070 * then 'sp' should be word aligned here. If it's
2071 * not, then the user is trying to mess with us.
2072 */
2073 frame_addr = env->regs[13];
2074 trace_user_do_sigreturn(env, frame_addr);
2075 if (frame_addr & 7) {
2076 goto badframe;
2077 }
Peter Maydell978fae92013-07-29 12:00:32 +01002078
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002079 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
2080 goto badframe;
2081 }
pbrooka8c33202008-05-07 23:22:46 +00002082
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002083 if (do_sigframe_return_v2(env, frame_addr, &frame->uc)) {
2084 goto badframe;
2085 }
pbrooka8c33202008-05-07 23:22:46 +00002086
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002087 unlock_user_struct(frame, frame_addr, 0);
Timothy E Baldwinf0267ef2016-05-12 18:47:31 +01002088 return -TARGET_QEMU_ESIGRETURN;
pbrooka8c33202008-05-07 23:22:46 +00002089
2090badframe:
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002091 unlock_user_struct(frame, frame_addr, 0);
2092 force_sig(TARGET_SIGSEGV /* , current */);
2093 return 0;
pbrooka8c33202008-05-07 23:22:46 +00002094}
2095
Andreas Färber05390242012-02-25 03:37:53 +01002096long do_sigreturn(CPUARMState *env)
pbrooka8c33202008-05-07 23:22:46 +00002097{
2098 if (get_osversion() >= 0x020612) {
2099 return do_sigreturn_v2(env);
2100 } else {
2101 return do_sigreturn_v1(env);
2102 }
2103}
2104
Andreas Färber05390242012-02-25 03:37:53 +01002105static long do_rt_sigreturn_v1(CPUARMState *env)
bellard43fff232003-07-09 19:31:39 +00002106{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002107 abi_ulong frame_addr;
2108 struct rt_sigframe_v1 *frame = NULL;
2109 sigset_t host_set;
bellard43fff232003-07-09 19:31:39 +00002110
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002111 /*
2112 * Since we stacked the signal on a 64-bit boundary,
2113 * then 'sp' should be word aligned here. If it's
2114 * not, then the user is trying to mess with us.
2115 */
2116 frame_addr = env->regs[13];
2117 trace_user_do_rt_sigreturn(env, frame_addr);
2118 if (frame_addr & 7) {
2119 goto badframe;
2120 }
Peter Maydell978fae92013-07-29 12:00:32 +01002121
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002122 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
2123 goto badframe;
2124 }
bellard43fff232003-07-09 19:31:39 +00002125
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002126 target_to_host_sigset(&host_set, &frame->uc.tuc_sigmask);
Peter Maydell9eede5b2016-05-27 15:51:46 +01002127 set_sigmask(&host_set);
bellard43fff232003-07-09 19:31:39 +00002128
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002129 if (restore_sigcontext(env, &frame->uc.tuc_mcontext)) {
2130 goto badframe;
2131 }
bellard43fff232003-07-09 19:31:39 +00002132
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002133 if (do_sigaltstack(frame_addr + offsetof(struct rt_sigframe_v1, uc.tuc_stack), 0, get_sp_from_cpustate(env)) == -EFAULT)
2134 goto badframe;
thsa04e1342007-09-27 13:57:58 +00002135
bellard43fff232003-07-09 19:31:39 +00002136#if 0
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002137 /* Send SIGTRAP if we're single-stepping */
2138 if (ptrace_cancel_bpt(current))
2139 send_sig(SIGTRAP, current, 1);
bellard43fff232003-07-09 19:31:39 +00002140#endif
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002141 unlock_user_struct(frame, frame_addr, 0);
Timothy E Baldwinf0267ef2016-05-12 18:47:31 +01002142 return -TARGET_QEMU_ESIGRETURN;
bellard43fff232003-07-09 19:31:39 +00002143
2144badframe:
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002145 unlock_user_struct(frame, frame_addr, 0);
2146 force_sig(TARGET_SIGSEGV /* , current */);
2147 return 0;
bellard43fff232003-07-09 19:31:39 +00002148}
2149
Andreas Färber05390242012-02-25 03:37:53 +01002150static long do_rt_sigreturn_v2(CPUARMState *env)
pbrooka745ec62008-05-06 15:36:17 +00002151{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002152 abi_ulong frame_addr;
2153 struct rt_sigframe_v2 *frame = NULL;
pbrooka745ec62008-05-06 15:36:17 +00002154
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002155 /*
2156 * Since we stacked the signal on a 64-bit boundary,
2157 * then 'sp' should be word aligned here. If it's
2158 * not, then the user is trying to mess with us.
2159 */
2160 frame_addr = env->regs[13];
2161 trace_user_do_rt_sigreturn(env, frame_addr);
2162 if (frame_addr & 7) {
2163 goto badframe;
2164 }
Peter Maydell978fae92013-07-29 12:00:32 +01002165
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002166 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
2167 goto badframe;
2168 }
pbrooka745ec62008-05-06 15:36:17 +00002169
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002170 if (do_sigframe_return_v2(env, frame_addr, &frame->uc)) {
2171 goto badframe;
2172 }
pbrooka745ec62008-05-06 15:36:17 +00002173
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002174 unlock_user_struct(frame, frame_addr, 0);
Timothy E Baldwinf0267ef2016-05-12 18:47:31 +01002175 return -TARGET_QEMU_ESIGRETURN;
pbrooka745ec62008-05-06 15:36:17 +00002176
2177badframe:
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002178 unlock_user_struct(frame, frame_addr, 0);
2179 force_sig(TARGET_SIGSEGV /* , current */);
2180 return 0;
pbrooka745ec62008-05-06 15:36:17 +00002181}
2182
Andreas Färber05390242012-02-25 03:37:53 +01002183long do_rt_sigreturn(CPUARMState *env)
pbrooka745ec62008-05-06 15:36:17 +00002184{
2185 if (get_osversion() >= 0x020612) {
2186 return do_rt_sigreturn_v2(env);
2187 } else {
2188 return do_rt_sigreturn_v1(env);
2189 }
2190}
2191
bellard6d5e2162004-09-30 22:04:13 +00002192#elif defined(TARGET_SPARC)
bellard80a9d032005-01-03 23:31:27 +00002193
bellard6d5e2162004-09-30 22:04:13 +00002194#define __SUNOS_MAXWIN 31
2195
2196/* This is what SunOS does, so shall I. */
2197struct target_sigcontext {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002198 abi_ulong sigc_onstack; /* state to restore */
bellard6d5e2162004-09-30 22:04:13 +00002199
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002200 abi_ulong sigc_mask; /* sigmask to restore */
2201 abi_ulong sigc_sp; /* stack pointer */
2202 abi_ulong sigc_pc; /* program counter */
2203 abi_ulong sigc_npc; /* next program counter */
2204 abi_ulong sigc_psr; /* for condition codes etc */
2205 abi_ulong sigc_g1; /* User uses these two registers */
2206 abi_ulong sigc_o0; /* within the trampoline code. */
bellard6d5e2162004-09-30 22:04:13 +00002207
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002208 /* Now comes information regarding the users window set
bellard6d5e2162004-09-30 22:04:13 +00002209 * at the time of the signal.
2210 */
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002211 abi_ulong sigc_oswins; /* outstanding windows */
bellard6d5e2162004-09-30 22:04:13 +00002212
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002213 /* stack ptrs for each regwin buf */
2214 char *sigc_spbuf[__SUNOS_MAXWIN];
bellard6d5e2162004-09-30 22:04:13 +00002215
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002216 /* Windows to restore after signal */
2217 struct {
2218 abi_ulong locals[8];
2219 abi_ulong ins[8];
2220 } sigc_wbuf[__SUNOS_MAXWIN];
bellard6d5e2162004-09-30 22:04:13 +00002221};
2222/* A Sparc stack frame */
2223struct sparc_stackf {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002224 abi_ulong locals[8];
2225 abi_ulong ins[8];
2226 /* It's simpler to treat fp and callers_pc as elements of ins[]
Peter Maydelle321c342011-02-01 15:54:52 +00002227 * since we never need to access them ourselves.
2228 */
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002229 char *structptr;
2230 abi_ulong xargs[6];
2231 abi_ulong xxargs[1];
bellard6d5e2162004-09-30 22:04:13 +00002232};
2233
2234typedef struct {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002235 struct {
2236 abi_ulong psr;
2237 abi_ulong pc;
2238 abi_ulong npc;
2239 abi_ulong y;
2240 abi_ulong u_regs[16]; /* globals and ins */
2241 } si_regs;
2242 int si_mask;
bellard6d5e2162004-09-30 22:04:13 +00002243} __siginfo_t;
2244
2245typedef struct {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002246 abi_ulong si_float_regs[32];
2247 unsigned long si_fsr;
2248 unsigned long si_fpqdepth;
2249 struct {
2250 unsigned long *insn_addr;
2251 unsigned long insn;
2252 } si_fpqueue [16];
Anthony Liguoric227f092009-10-01 16:12:16 -05002253} qemu_siginfo_fpu_t;
bellard6d5e2162004-09-30 22:04:13 +00002254
2255
2256struct target_signal_frame {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002257 struct sparc_stackf ss;
2258 __siginfo_t info;
2259 abi_ulong fpu_save;
2260 abi_ulong insns[2] __attribute__ ((aligned (8)));
2261 abi_ulong extramask[TARGET_NSIG_WORDS - 1];
2262 abi_ulong extra_size; /* Should be 0 */
2263 qemu_siginfo_fpu_t fpu_state;
bellard6d5e2162004-09-30 22:04:13 +00002264};
2265struct target_rt_signal_frame {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002266 struct sparc_stackf ss;
2267 siginfo_t info;
2268 abi_ulong regs[20];
2269 sigset_t mask;
2270 abi_ulong fpu_save;
2271 unsigned int insns[2];
2272 stack_t stack;
2273 unsigned int extra_size; /* Should be 0 */
2274 qemu_siginfo_fpu_t fpu_state;
bellard6d5e2162004-09-30 22:04:13 +00002275};
2276
bellarde80cfcf2004-12-19 23:18:01 +00002277#define UREG_O0 16
2278#define UREG_O6 22
2279#define UREG_I0 0
2280#define UREG_I1 1
2281#define UREG_I2 2
blueswir15bfb56b2007-10-05 17:01:51 +00002282#define UREG_I3 3
2283#define UREG_I4 4
2284#define UREG_I5 5
bellarde80cfcf2004-12-19 23:18:01 +00002285#define UREG_I6 6
2286#define UREG_I7 7
2287#define UREG_L0 8
bellard6d5e2162004-09-30 22:04:13 +00002288#define UREG_FP UREG_I6
2289#define UREG_SP UREG_O6
2290
pbrook624f7972008-05-31 16:11:38 +00002291static inline abi_ulong get_sigframe(struct target_sigaction *sa,
Andreas Färber05390242012-02-25 03:37:53 +01002292 CPUSPARCState *env,
2293 unsigned long framesize)
bellard6d5e2162004-09-30 22:04:13 +00002294{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002295 abi_ulong sp;
bellard6d5e2162004-09-30 22:04:13 +00002296
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002297 sp = env->regwptr[UREG_FP];
bellard6d5e2162004-09-30 22:04:13 +00002298
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002299 /* This is the X/Open sanctioned signal stack switching. */
2300 if (sa->sa_flags & TARGET_SA_ONSTACK) {
2301 if (!on_sig_stack(sp)
2302 && !((target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size) & 7)) {
2303 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
2304 }
2305 }
2306 return sp - framesize;
bellard6d5e2162004-09-30 22:04:13 +00002307}
2308
2309static int
Andreas Färber05390242012-02-25 03:37:53 +01002310setup___siginfo(__siginfo_t *si, CPUSPARCState *env, abi_ulong mask)
bellard6d5e2162004-09-30 22:04:13 +00002311{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002312 int err = 0, i;
bellard6d5e2162004-09-30 22:04:13 +00002313
Riku Voipio1d8b5122014-04-23 10:26:05 +03002314 __put_user(env->psr, &si->si_regs.psr);
2315 __put_user(env->pc, &si->si_regs.pc);
2316 __put_user(env->npc, &si->si_regs.npc);
2317 __put_user(env->y, &si->si_regs.y);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002318 for (i=0; i < 8; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002319 __put_user(env->gregs[i], &si->si_regs.u_regs[i]);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002320 }
2321 for (i=0; i < 8; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002322 __put_user(env->regwptr[UREG_I0 + i], &si->si_regs.u_regs[i+8]);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002323 }
Riku Voipio1d8b5122014-04-23 10:26:05 +03002324 __put_user(mask, &si->si_mask);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002325 return err;
bellard6d5e2162004-09-30 22:04:13 +00002326}
bellarde80cfcf2004-12-19 23:18:01 +00002327
bellard80a9d032005-01-03 23:31:27 +00002328#if 0
bellard6d5e2162004-09-30 22:04:13 +00002329static int
2330setup_sigcontext(struct target_sigcontext *sc, /*struct _fpstate *fpstate,*/
Andreas Färber05390242012-02-25 03:37:53 +01002331 CPUSPARCState *env, unsigned long mask)
bellard6d5e2162004-09-30 22:04:13 +00002332{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002333 int err = 0;
bellard6d5e2162004-09-30 22:04:13 +00002334
Riku Voipio1d8b5122014-04-23 10:26:05 +03002335 __put_user(mask, &sc->sigc_mask);
2336 __put_user(env->regwptr[UREG_SP], &sc->sigc_sp);
2337 __put_user(env->pc, &sc->sigc_pc);
2338 __put_user(env->npc, &sc->sigc_npc);
2339 __put_user(env->psr, &sc->sigc_psr);
2340 __put_user(env->gregs[1], &sc->sigc_g1);
2341 __put_user(env->regwptr[UREG_O0], &sc->sigc_o0);
bellard6d5e2162004-09-30 22:04:13 +00002342
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002343 return err;
bellard6d5e2162004-09-30 22:04:13 +00002344}
bellard80a9d032005-01-03 23:31:27 +00002345#endif
bellard6d5e2162004-09-30 22:04:13 +00002346#define NF_ALIGNEDSZ (((sizeof(struct target_signal_frame) + 7) & (~7)))
2347
pbrook624f7972008-05-31 16:11:38 +00002348static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01002349 target_sigset_t *set, CPUSPARCState *env)
bellard6d5e2162004-09-30 22:04:13 +00002350{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002351 abi_ulong sf_addr;
2352 struct target_signal_frame *sf;
2353 int sigframe_size, err, i;
bellard6d5e2162004-09-30 22:04:13 +00002354
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002355 /* 1. Make sure everything is clean */
2356 //synchronize_user_stack();
bellard6d5e2162004-09-30 22:04:13 +00002357
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002358 sigframe_size = NF_ALIGNEDSZ;
2359 sf_addr = get_sigframe(ka, env, sigframe_size);
2360 trace_user_setup_frame(env, sf_addr);
bellard6d5e2162004-09-30 22:04:13 +00002361
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002362 sf = lock_user(VERIFY_WRITE, sf_addr,
2363 sizeof(struct target_signal_frame), 0);
2364 if (!sf) {
2365 goto sigsegv;
2366 }
bellard6d5e2162004-09-30 22:04:13 +00002367#if 0
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002368 if (invalid_frame_pointer(sf, sigframe_size))
2369 goto sigill_and_return;
bellard6d5e2162004-09-30 22:04:13 +00002370#endif
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002371 /* 2. Save the current process state */
2372 err = setup___siginfo(&sf->info, env, set->sig[0]);
Riku Voipio1d8b5122014-04-23 10:26:05 +03002373 __put_user(0, &sf->extra_size);
bellard6d5e2162004-09-30 22:04:13 +00002374
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002375 //save_fpu_state(regs, &sf->fpu_state);
2376 //__put_user(&sf->fpu_state, &sf->fpu_save);
bellard6d5e2162004-09-30 22:04:13 +00002377
Riku Voipio1d8b5122014-04-23 10:26:05 +03002378 __put_user(set->sig[0], &sf->info.si_mask);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002379 for (i = 0; i < TARGET_NSIG_WORDS - 1; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002380 __put_user(set->sig[i + 1], &sf->extramask[i]);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002381 }
bellard6d5e2162004-09-30 22:04:13 +00002382
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002383 for (i = 0; i < 8; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002384 __put_user(env->regwptr[i + UREG_L0], &sf->ss.locals[i]);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002385 }
2386 for (i = 0; i < 8; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002387 __put_user(env->regwptr[i + UREG_I0], &sf->ss.ins[i]);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002388 }
2389 if (err)
2390 goto sigsegv;
bellard6d5e2162004-09-30 22:04:13 +00002391
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002392 /* 3. signal handler back-trampoline and parameters */
2393 env->regwptr[UREG_FP] = sf_addr;
2394 env->regwptr[UREG_I0] = sig;
2395 env->regwptr[UREG_I1] = sf_addr +
2396 offsetof(struct target_signal_frame, info);
2397 env->regwptr[UREG_I2] = sf_addr +
2398 offsetof(struct target_signal_frame, info);
bellard6d5e2162004-09-30 22:04:13 +00002399
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002400 /* 4. signal handler */
2401 env->pc = ka->_sa_handler;
2402 env->npc = (env->pc + 4);
2403 /* 5. return to kernel instructions */
2404 if (ka->sa_restorer) {
2405 env->regwptr[UREG_I7] = ka->sa_restorer;
2406 } else {
2407 uint32_t val32;
bellard459a4012007-11-11 19:45:10 +00002408
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002409 env->regwptr[UREG_I7] = sf_addr +
2410 offsetof(struct target_signal_frame, insns) - 2 * 4;
bellard6d5e2162004-09-30 22:04:13 +00002411
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002412 /* mov __NR_sigreturn, %g1 */
2413 val32 = 0x821020d8;
Riku Voipio1d8b5122014-04-23 10:26:05 +03002414 __put_user(val32, &sf->insns[0]);
bellard6d5e2162004-09-30 22:04:13 +00002415
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002416 /* t 0x10 */
2417 val32 = 0x91d02010;
Riku Voipio1d8b5122014-04-23 10:26:05 +03002418 __put_user(val32, &sf->insns[1]);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002419 if (err)
2420 goto sigsegv;
bellard6d5e2162004-09-30 22:04:13 +00002421
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002422 /* Flush instruction space. */
2423 // flush_sig_insns(current->mm, (unsigned long) &(sf->insns[0]));
2424 // tb_flush(env);
2425 }
2426 unlock_user(sf, sf_addr, sizeof(struct target_signal_frame));
2427 return;
bellard459a4012007-11-11 19:45:10 +00002428#if 0
2429sigill_and_return:
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002430 force_sig(TARGET_SIGILL);
bellard459a4012007-11-11 19:45:10 +00002431#endif
bellard6d5e2162004-09-30 22:04:13 +00002432sigsegv:
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002433 unlock_user(sf, sf_addr, sizeof(struct target_signal_frame));
2434 force_sig(TARGET_SIGSEGV);
bellard6d5e2162004-09-30 22:04:13 +00002435}
bellard6d5e2162004-09-30 22:04:13 +00002436
pbrook624f7972008-05-31 16:11:38 +00002437static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05002438 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01002439 target_sigset_t *set, CPUSPARCState *env)
bellard6d5e2162004-09-30 22:04:13 +00002440{
2441 fprintf(stderr, "setup_rt_frame: not implemented\n");
2442}
2443
Andreas Färber05390242012-02-25 03:37:53 +01002444long do_sigreturn(CPUSPARCState *env)
bellard6d5e2162004-09-30 22:04:13 +00002445{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002446 abi_ulong sf_addr;
2447 struct target_signal_frame *sf;
2448 uint32_t up_psr, pc, npc;
2449 target_sigset_t set;
2450 sigset_t host_set;
2451 int err=0, i;
bellard6d5e2162004-09-30 22:04:13 +00002452
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002453 sf_addr = env->regwptr[UREG_FP];
2454 trace_user_do_sigreturn(env, sf_addr);
2455 if (!lock_user_struct(VERIFY_READ, sf, sf_addr, 1)) {
2456 goto segv_and_exit;
2457 }
bellard6d5e2162004-09-30 22:04:13 +00002458
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002459 /* 1. Make sure we are not getting garbage from the user */
bellard6d5e2162004-09-30 22:04:13 +00002460
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002461 if (sf_addr & 3)
2462 goto segv_and_exit;
bellard6d5e2162004-09-30 22:04:13 +00002463
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002464 __get_user(pc, &sf->info.si_regs.pc);
2465 __get_user(npc, &sf->info.si_regs.npc);
bellard6d5e2162004-09-30 22:04:13 +00002466
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002467 if ((pc | npc) & 3) {
2468 goto segv_and_exit;
2469 }
bellard6d5e2162004-09-30 22:04:13 +00002470
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002471 /* 2. Restore the state */
2472 __get_user(up_psr, &sf->info.si_regs.psr);
bellarde80cfcf2004-12-19 23:18:01 +00002473
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002474 /* User can only change condition codes and FPU enabling in %psr. */
2475 env->psr = (up_psr & (PSR_ICC /* | PSR_EF */))
2476 | (env->psr & ~(PSR_ICC /* | PSR_EF */));
bellarda315a142005-01-30 22:59:18 +00002477
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002478 env->pc = pc;
2479 env->npc = npc;
2480 __get_user(env->y, &sf->info.si_regs.y);
2481 for (i=0; i < 8; i++) {
2482 __get_user(env->gregs[i], &sf->info.si_regs.u_regs[i]);
2483 }
2484 for (i=0; i < 8; i++) {
2485 __get_user(env->regwptr[i + UREG_I0], &sf->info.si_regs.u_regs[i+8]);
2486 }
bellard6d5e2162004-09-30 22:04:13 +00002487
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002488 /* FIXME: implement FPU save/restore:
Peter Maydell2aec3a22011-06-16 17:37:14 +01002489 * __get_user(fpu_save, &sf->fpu_save);
2490 * if (fpu_save)
2491 * err |= restore_fpu_state(env, fpu_save);
2492 */
bellard6d5e2162004-09-30 22:04:13 +00002493
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002494 /* This is pretty much atomic, no amount locking would prevent
bellard6d5e2162004-09-30 22:04:13 +00002495 * the races which exist anyways.
2496 */
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002497 __get_user(set.sig[0], &sf->info.si_mask);
2498 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
2499 __get_user(set.sig[i], &sf->extramask[i - 1]);
2500 }
bellarde80cfcf2004-12-19 23:18:01 +00002501
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002502 target_to_host_sigset_internal(&host_set, &set);
Peter Maydell9eede5b2016-05-27 15:51:46 +01002503 set_sigmask(&host_set);
bellard6d5e2162004-09-30 22:04:13 +00002504
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002505 if (err) {
2506 goto segv_and_exit;
2507 }
2508 unlock_user_struct(sf, sf_addr, 0);
Timothy E Baldwinc0bea682016-05-12 18:47:34 +01002509 return -TARGET_QEMU_ESIGRETURN;
bellard6d5e2162004-09-30 22:04:13 +00002510
2511segv_and_exit:
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002512 unlock_user_struct(sf, sf_addr, 0);
2513 force_sig(TARGET_SIGSEGV);
bellard6d5e2162004-09-30 22:04:13 +00002514}
2515
Andreas Färber05390242012-02-25 03:37:53 +01002516long do_rt_sigreturn(CPUSPARCState *env)
bellard6d5e2162004-09-30 22:04:13 +00002517{
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01002518 trace_user_do_rt_sigreturn(env, 0);
bellard6d5e2162004-09-30 22:04:13 +00002519 fprintf(stderr, "do_rt_sigreturn: not implemented\n");
bellardf8b0aa22007-11-11 23:03:42 +00002520 return -TARGET_ENOSYS;
bellard6d5e2162004-09-30 22:04:13 +00002521}
2522
bellard459a4012007-11-11 19:45:10 +00002523#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
blueswir15bfb56b2007-10-05 17:01:51 +00002524#define MC_TSTATE 0
2525#define MC_PC 1
2526#define MC_NPC 2
2527#define MC_Y 3
2528#define MC_G1 4
2529#define MC_G2 5
2530#define MC_G3 6
2531#define MC_G4 7
2532#define MC_G5 8
2533#define MC_G6 9
2534#define MC_G7 10
2535#define MC_O0 11
2536#define MC_O1 12
2537#define MC_O2 13
2538#define MC_O3 14
2539#define MC_O4 15
2540#define MC_O5 16
2541#define MC_O6 17
2542#define MC_O7 18
2543#define MC_NGREG 19
2544
Anthony Liguoric227f092009-10-01 16:12:16 -05002545typedef abi_ulong target_mc_greg_t;
2546typedef target_mc_greg_t target_mc_gregset_t[MC_NGREG];
blueswir15bfb56b2007-10-05 17:01:51 +00002547
2548struct target_mc_fq {
blueswir1992f48a2007-10-14 16:27:31 +00002549 abi_ulong *mcfq_addr;
blueswir15bfb56b2007-10-05 17:01:51 +00002550 uint32_t mcfq_insn;
2551};
2552
2553struct target_mc_fpu {
2554 union {
2555 uint32_t sregs[32];
2556 uint64_t dregs[32];
2557 //uint128_t qregs[16];
2558 } mcfpu_fregs;
blueswir1992f48a2007-10-14 16:27:31 +00002559 abi_ulong mcfpu_fsr;
2560 abi_ulong mcfpu_fprs;
2561 abi_ulong mcfpu_gsr;
blueswir15bfb56b2007-10-05 17:01:51 +00002562 struct target_mc_fq *mcfpu_fq;
2563 unsigned char mcfpu_qcnt;
2564 unsigned char mcfpu_qentsz;
2565 unsigned char mcfpu_enab;
2566};
Anthony Liguoric227f092009-10-01 16:12:16 -05002567typedef struct target_mc_fpu target_mc_fpu_t;
blueswir15bfb56b2007-10-05 17:01:51 +00002568
2569typedef struct {
Anthony Liguoric227f092009-10-01 16:12:16 -05002570 target_mc_gregset_t mc_gregs;
2571 target_mc_greg_t mc_fp;
2572 target_mc_greg_t mc_i7;
2573 target_mc_fpu_t mc_fpregs;
2574} target_mcontext_t;
blueswir15bfb56b2007-10-05 17:01:51 +00002575
2576struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02002577 struct target_ucontext *tuc_link;
2578 abi_ulong tuc_flags;
2579 target_sigset_t tuc_sigmask;
2580 target_mcontext_t tuc_mcontext;
blueswir15bfb56b2007-10-05 17:01:51 +00002581};
2582
2583/* A V9 register window */
2584struct target_reg_window {
blueswir1992f48a2007-10-14 16:27:31 +00002585 abi_ulong locals[8];
2586 abi_ulong ins[8];
blueswir15bfb56b2007-10-05 17:01:51 +00002587};
2588
2589#define TARGET_STACK_BIAS 2047
2590
2591/* {set, get}context() needed for 64-bit SparcLinux userland. */
2592void sparc64_set_context(CPUSPARCState *env)
2593{
bellard459a4012007-11-11 19:45:10 +00002594 abi_ulong ucp_addr;
2595 struct target_ucontext *ucp;
Anthony Liguoric227f092009-10-01 16:12:16 -05002596 target_mc_gregset_t *grp;
blueswir1992f48a2007-10-14 16:27:31 +00002597 abi_ulong pc, npc, tstate;
bellard459a4012007-11-11 19:45:10 +00002598 abi_ulong fp, i7, w_addr;
blueswir15bfb56b2007-10-05 17:01:51 +00002599 unsigned int i;
blueswir15bfb56b2007-10-05 17:01:51 +00002600
bellard459a4012007-11-11 19:45:10 +00002601 ucp_addr = env->regwptr[UREG_I0];
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002602 if (!lock_user_struct(VERIFY_READ, ucp, ucp_addr, 1)) {
bellard459a4012007-11-11 19:45:10 +00002603 goto do_sigsegv;
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002604 }
Aurelien Jarno60e99242010-03-29 02:12:51 +02002605 grp = &ucp->tuc_mcontext.mc_gregs;
Riku Voipio1d8b5122014-04-23 10:26:05 +03002606 __get_user(pc, &((*grp)[MC_PC]));
2607 __get_user(npc, &((*grp)[MC_NPC]));
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002608 if ((pc | npc) & 3) {
blueswir15bfb56b2007-10-05 17:01:51 +00002609 goto do_sigsegv;
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002610 }
blueswir15bfb56b2007-10-05 17:01:51 +00002611 if (env->regwptr[UREG_I1]) {
Anthony Liguoric227f092009-10-01 16:12:16 -05002612 target_sigset_t target_set;
blueswir15bfb56b2007-10-05 17:01:51 +00002613 sigset_t set;
2614
2615 if (TARGET_NSIG_WORDS == 1) {
Riku Voipiobe3ef5c2014-04-23 14:02:36 +03002616 __get_user(target_set.sig[0], &ucp->tuc_sigmask.sig[0]);
blueswir15bfb56b2007-10-05 17:01:51 +00002617 } else {
bellard459a4012007-11-11 19:45:10 +00002618 abi_ulong *src, *dst;
Aurelien Jarno60e99242010-03-29 02:12:51 +02002619 src = ucp->tuc_sigmask.sig;
bellard459a4012007-11-11 19:45:10 +00002620 dst = target_set.sig;
Stefan Weil0d9e61c2013-12-07 14:48:08 +01002621 for (i = 0; i < TARGET_NSIG_WORDS; i++, dst++, src++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002622 __get_user(*dst, src);
Stefan Weil0d9e61c2013-12-07 14:48:08 +01002623 }
blueswir15bfb56b2007-10-05 17:01:51 +00002624 }
2625 target_to_host_sigset_internal(&set, &target_set);
Peter Maydell9eede5b2016-05-27 15:51:46 +01002626 set_sigmask(&set);
blueswir15bfb56b2007-10-05 17:01:51 +00002627 }
2628 env->pc = pc;
2629 env->npc = npc;
Riku Voipio1d8b5122014-04-23 10:26:05 +03002630 __get_user(env->y, &((*grp)[MC_Y]));
2631 __get_user(tstate, &((*grp)[MC_TSTATE]));
blueswir15bfb56b2007-10-05 17:01:51 +00002632 env->asi = (tstate >> 24) & 0xff;
Blue Swirl5a834bb2010-05-09 20:19:04 +00002633 cpu_put_ccr(env, tstate >> 32);
2634 cpu_put_cwp64(env, tstate & 0x1f);
Riku Voipio1d8b5122014-04-23 10:26:05 +03002635 __get_user(env->gregs[1], (&(*grp)[MC_G1]));
2636 __get_user(env->gregs[2], (&(*grp)[MC_G2]));
2637 __get_user(env->gregs[3], (&(*grp)[MC_G3]));
2638 __get_user(env->gregs[4], (&(*grp)[MC_G4]));
2639 __get_user(env->gregs[5], (&(*grp)[MC_G5]));
2640 __get_user(env->gregs[6], (&(*grp)[MC_G6]));
2641 __get_user(env->gregs[7], (&(*grp)[MC_G7]));
2642 __get_user(env->regwptr[UREG_I0], (&(*grp)[MC_O0]));
2643 __get_user(env->regwptr[UREG_I1], (&(*grp)[MC_O1]));
2644 __get_user(env->regwptr[UREG_I2], (&(*grp)[MC_O2]));
2645 __get_user(env->regwptr[UREG_I3], (&(*grp)[MC_O3]));
2646 __get_user(env->regwptr[UREG_I4], (&(*grp)[MC_O4]));
2647 __get_user(env->regwptr[UREG_I5], (&(*grp)[MC_O5]));
2648 __get_user(env->regwptr[UREG_I6], (&(*grp)[MC_O6]));
2649 __get_user(env->regwptr[UREG_I7], (&(*grp)[MC_O7]));
blueswir15bfb56b2007-10-05 17:01:51 +00002650
Riku Voipio1d8b5122014-04-23 10:26:05 +03002651 __get_user(fp, &(ucp->tuc_mcontext.mc_fp));
2652 __get_user(i7, &(ucp->tuc_mcontext.mc_i7));
blueswir15bfb56b2007-10-05 17:01:51 +00002653
bellard459a4012007-11-11 19:45:10 +00002654 w_addr = TARGET_STACK_BIAS+env->regwptr[UREG_I6];
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002655 if (put_user(fp, w_addr + offsetof(struct target_reg_window, ins[6]),
2656 abi_ulong) != 0) {
bellard459a4012007-11-11 19:45:10 +00002657 goto do_sigsegv;
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002658 }
2659 if (put_user(i7, w_addr + offsetof(struct target_reg_window, ins[7]),
2660 abi_ulong) != 0) {
bellard459a4012007-11-11 19:45:10 +00002661 goto do_sigsegv;
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002662 }
Peter Maydellc7b016b2011-06-16 17:37:15 +01002663 /* FIXME this does not match how the kernel handles the FPU in
2664 * its sparc64_set_context implementation. In particular the FPU
2665 * is only restored if fenab is non-zero in:
2666 * __get_user(fenab, &(ucp->tuc_mcontext.mc_fpregs.mcfpu_enab));
2667 */
Riku Voipiobe3ef5c2014-04-23 14:02:36 +03002668 __get_user(env->fprs, &(ucp->tuc_mcontext.mc_fpregs.mcfpu_fprs));
bellard459a4012007-11-11 19:45:10 +00002669 {
Richard Henderson30038fd2011-10-17 10:42:49 -07002670 uint32_t *src = ucp->tuc_mcontext.mc_fpregs.mcfpu_fregs.sregs;
2671 for (i = 0; i < 64; i++, src++) {
2672 if (i & 1) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002673 __get_user(env->fpr[i/2].l.lower, src);
Richard Henderson30038fd2011-10-17 10:42:49 -07002674 } else {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002675 __get_user(env->fpr[i/2].l.upper, src);
Richard Henderson30038fd2011-10-17 10:42:49 -07002676 }
2677 }
bellard459a4012007-11-11 19:45:10 +00002678 }
Riku Voipio1d8b5122014-04-23 10:26:05 +03002679 __get_user(env->fsr,
2680 &(ucp->tuc_mcontext.mc_fpregs.mcfpu_fsr));
2681 __get_user(env->gsr,
2682 &(ucp->tuc_mcontext.mc_fpregs.mcfpu_gsr));
bellard459a4012007-11-11 19:45:10 +00002683 unlock_user_struct(ucp, ucp_addr, 0);
blueswir15bfb56b2007-10-05 17:01:51 +00002684 return;
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002685do_sigsegv:
bellard459a4012007-11-11 19:45:10 +00002686 unlock_user_struct(ucp, ucp_addr, 0);
Riku Voipio66393fb2009-12-04 15:16:32 +02002687 force_sig(TARGET_SIGSEGV);
blueswir15bfb56b2007-10-05 17:01:51 +00002688}
2689
2690void sparc64_get_context(CPUSPARCState *env)
2691{
bellard459a4012007-11-11 19:45:10 +00002692 abi_ulong ucp_addr;
2693 struct target_ucontext *ucp;
Anthony Liguoric227f092009-10-01 16:12:16 -05002694 target_mc_gregset_t *grp;
2695 target_mcontext_t *mcp;
bellard459a4012007-11-11 19:45:10 +00002696 abi_ulong fp, i7, w_addr;
blueswir15bfb56b2007-10-05 17:01:51 +00002697 int err;
2698 unsigned int i;
Anthony Liguoric227f092009-10-01 16:12:16 -05002699 target_sigset_t target_set;
blueswir15bfb56b2007-10-05 17:01:51 +00002700 sigset_t set;
2701
bellard459a4012007-11-11 19:45:10 +00002702 ucp_addr = env->regwptr[UREG_I0];
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002703 if (!lock_user_struct(VERIFY_WRITE, ucp, ucp_addr, 0)) {
bellard459a4012007-11-11 19:45:10 +00002704 goto do_sigsegv;
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002705 }
bellard459a4012007-11-11 19:45:10 +00002706
Aurelien Jarno60e99242010-03-29 02:12:51 +02002707 mcp = &ucp->tuc_mcontext;
blueswir15bfb56b2007-10-05 17:01:51 +00002708 grp = &mcp->mc_gregs;
2709
2710 /* Skip over the trap instruction, first. */
2711 env->pc = env->npc;
2712 env->npc += 4;
2713
Peter Maydell3d3efba2016-05-27 15:51:49 +01002714 /* If we're only reading the signal mask then do_sigprocmask()
2715 * is guaranteed not to fail, which is important because we don't
2716 * have any way to signal a failure or restart this operation since
2717 * this is not a normal syscall.
2718 */
2719 err = do_sigprocmask(0, NULL, &set);
2720 assert(err == 0);
blueswir15bfb56b2007-10-05 17:01:51 +00002721 host_to_target_sigset_internal(&target_set, &set);
bellard459a4012007-11-11 19:45:10 +00002722 if (TARGET_NSIG_WORDS == 1) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002723 __put_user(target_set.sig[0],
2724 (abi_ulong *)&ucp->tuc_sigmask);
bellard459a4012007-11-11 19:45:10 +00002725 } else {
2726 abi_ulong *src, *dst;
2727 src = target_set.sig;
Aurelien Jarno60e99242010-03-29 02:12:51 +02002728 dst = ucp->tuc_sigmask.sig;
Stefan Weil0d9e61c2013-12-07 14:48:08 +01002729 for (i = 0; i < TARGET_NSIG_WORDS; i++, dst++, src++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002730 __put_user(*src, dst);
Stefan Weil0d9e61c2013-12-07 14:48:08 +01002731 }
blueswir15bfb56b2007-10-05 17:01:51 +00002732 if (err)
2733 goto do_sigsegv;
2734 }
2735
bellard459a4012007-11-11 19:45:10 +00002736 /* XXX: tstate must be saved properly */
Riku Voipio1d8b5122014-04-23 10:26:05 +03002737 // __put_user(env->tstate, &((*grp)[MC_TSTATE]));
2738 __put_user(env->pc, &((*grp)[MC_PC]));
2739 __put_user(env->npc, &((*grp)[MC_NPC]));
2740 __put_user(env->y, &((*grp)[MC_Y]));
2741 __put_user(env->gregs[1], &((*grp)[MC_G1]));
2742 __put_user(env->gregs[2], &((*grp)[MC_G2]));
2743 __put_user(env->gregs[3], &((*grp)[MC_G3]));
2744 __put_user(env->gregs[4], &((*grp)[MC_G4]));
2745 __put_user(env->gregs[5], &((*grp)[MC_G5]));
2746 __put_user(env->gregs[6], &((*grp)[MC_G6]));
2747 __put_user(env->gregs[7], &((*grp)[MC_G7]));
2748 __put_user(env->regwptr[UREG_I0], &((*grp)[MC_O0]));
2749 __put_user(env->regwptr[UREG_I1], &((*grp)[MC_O1]));
2750 __put_user(env->regwptr[UREG_I2], &((*grp)[MC_O2]));
2751 __put_user(env->regwptr[UREG_I3], &((*grp)[MC_O3]));
2752 __put_user(env->regwptr[UREG_I4], &((*grp)[MC_O4]));
2753 __put_user(env->regwptr[UREG_I5], &((*grp)[MC_O5]));
2754 __put_user(env->regwptr[UREG_I6], &((*grp)[MC_O6]));
2755 __put_user(env->regwptr[UREG_I7], &((*grp)[MC_O7]));
blueswir15bfb56b2007-10-05 17:01:51 +00002756
bellard459a4012007-11-11 19:45:10 +00002757 w_addr = TARGET_STACK_BIAS+env->regwptr[UREG_I6];
2758 fp = i7 = 0;
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002759 if (get_user(fp, w_addr + offsetof(struct target_reg_window, ins[6]),
2760 abi_ulong) != 0) {
bellard459a4012007-11-11 19:45:10 +00002761 goto do_sigsegv;
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002762 }
2763 if (get_user(i7, w_addr + offsetof(struct target_reg_window, ins[7]),
2764 abi_ulong) != 0) {
bellard459a4012007-11-11 19:45:10 +00002765 goto do_sigsegv;
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002766 }
Riku Voipio1d8b5122014-04-23 10:26:05 +03002767 __put_user(fp, &(mcp->mc_fp));
2768 __put_user(i7, &(mcp->mc_i7));
blueswir15bfb56b2007-10-05 17:01:51 +00002769
bellard459a4012007-11-11 19:45:10 +00002770 {
Richard Henderson30038fd2011-10-17 10:42:49 -07002771 uint32_t *dst = ucp->tuc_mcontext.mc_fpregs.mcfpu_fregs.sregs;
2772 for (i = 0; i < 64; i++, dst++) {
2773 if (i & 1) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002774 __put_user(env->fpr[i/2].l.lower, dst);
Richard Henderson30038fd2011-10-17 10:42:49 -07002775 } else {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002776 __put_user(env->fpr[i/2].l.upper, dst);
Richard Henderson30038fd2011-10-17 10:42:49 -07002777 }
2778 }
bellard459a4012007-11-11 19:45:10 +00002779 }
Riku Voipio1d8b5122014-04-23 10:26:05 +03002780 __put_user(env->fsr, &(mcp->mc_fpregs.mcfpu_fsr));
2781 __put_user(env->gsr, &(mcp->mc_fpregs.mcfpu_gsr));
2782 __put_user(env->fprs, &(mcp->mc_fpregs.mcfpu_fprs));
blueswir15bfb56b2007-10-05 17:01:51 +00002783
2784 if (err)
2785 goto do_sigsegv;
bellard459a4012007-11-11 19:45:10 +00002786 unlock_user_struct(ucp, ucp_addr, 1);
blueswir15bfb56b2007-10-05 17:01:51 +00002787 return;
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002788do_sigsegv:
bellard459a4012007-11-11 19:45:10 +00002789 unlock_user_struct(ucp, ucp_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02002790 force_sig(TARGET_SIGSEGV);
blueswir15bfb56b2007-10-05 17:01:51 +00002791}
2792#endif
Richard Hendersonff970902013-02-10 10:30:42 -08002793#elif defined(TARGET_MIPS) || defined(TARGET_MIPS64)
bellard106ec872006-06-27 21:08:10 +00002794
Richard Hendersonff970902013-02-10 10:30:42 -08002795# if defined(TARGET_ABI_MIPSO32)
bellard106ec872006-06-27 21:08:10 +00002796struct target_sigcontext {
2797 uint32_t sc_regmask; /* Unused */
2798 uint32_t sc_status;
2799 uint64_t sc_pc;
2800 uint64_t sc_regs[32];
2801 uint64_t sc_fpregs[32];
2802 uint32_t sc_ownedfp; /* Unused */
2803 uint32_t sc_fpc_csr;
2804 uint32_t sc_fpc_eir; /* Unused */
2805 uint32_t sc_used_math;
2806 uint32_t sc_dsp; /* dsp status, was sc_ssflags */
Paul Brook94c54952009-07-09 18:40:15 +01002807 uint32_t pad0;
bellard106ec872006-06-27 21:08:10 +00002808 uint64_t sc_mdhi;
2809 uint64_t sc_mdlo;
2810 target_ulong sc_hi1; /* Was sc_cause */
2811 target_ulong sc_lo1; /* Was sc_badvaddr */
2812 target_ulong sc_hi2; /* Was sc_sigset[4] */
2813 target_ulong sc_lo2;
2814 target_ulong sc_hi3;
2815 target_ulong sc_lo3;
2816};
Richard Hendersonff970902013-02-10 10:30:42 -08002817# else /* N32 || N64 */
2818struct target_sigcontext {
2819 uint64_t sc_regs[32];
2820 uint64_t sc_fpregs[32];
2821 uint64_t sc_mdhi;
2822 uint64_t sc_hi1;
2823 uint64_t sc_hi2;
2824 uint64_t sc_hi3;
2825 uint64_t sc_mdlo;
2826 uint64_t sc_lo1;
2827 uint64_t sc_lo2;
2828 uint64_t sc_lo3;
2829 uint64_t sc_pc;
2830 uint32_t sc_fpc_csr;
2831 uint32_t sc_used_math;
2832 uint32_t sc_dsp;
2833 uint32_t sc_reserved;
2834};
2835# endif /* O32 */
bellard106ec872006-06-27 21:08:10 +00002836
2837struct sigframe {
2838 uint32_t sf_ass[4]; /* argument save space for o32 */
2839 uint32_t sf_code[2]; /* signal trampoline */
2840 struct target_sigcontext sf_sc;
Anthony Liguoric227f092009-10-01 16:12:16 -05002841 target_sigset_t sf_mask;
bellard106ec872006-06-27 21:08:10 +00002842};
2843
pbrook0b1bcb02009-04-21 01:41:10 +00002844struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02002845 target_ulong tuc_flags;
2846 target_ulong tuc_link;
2847 target_stack_t tuc_stack;
Paul Brook94c54952009-07-09 18:40:15 +01002848 target_ulong pad0;
Aurelien Jarno60e99242010-03-29 02:12:51 +02002849 struct target_sigcontext tuc_mcontext;
2850 target_sigset_t tuc_sigmask;
pbrook0b1bcb02009-04-21 01:41:10 +00002851};
2852
2853struct target_rt_sigframe {
2854 uint32_t rs_ass[4]; /* argument save space for o32 */
2855 uint32_t rs_code[2]; /* signal trampoline */
2856 struct target_siginfo rs_info;
2857 struct target_ucontext rs_uc;
2858};
2859
bellard106ec872006-06-27 21:08:10 +00002860/* Install trampoline to jump back from signal handler */
2861static inline int install_sigtramp(unsigned int *tramp, unsigned int syscall)
2862{
Richard Henderson084d0492013-02-10 10:30:44 -08002863 int err = 0;
bellard106ec872006-06-27 21:08:10 +00002864
2865 /*
Richard Henderson084d0492013-02-10 10:30:44 -08002866 * Set up the return code ...
2867 *
2868 * li v0, __NR__foo_sigreturn
2869 * syscall
2870 */
bellard106ec872006-06-27 21:08:10 +00002871
Riku Voipio1d8b5122014-04-23 10:26:05 +03002872 __put_user(0x24020000 + syscall, tramp + 0);
2873 __put_user(0x0000000c , tramp + 1);
bellard106ec872006-06-27 21:08:10 +00002874 return err;
2875}
2876
Riku Voipio41ecc722014-04-23 11:01:00 +03002877static inline void setup_sigcontext(CPUMIPSState *regs,
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002878 struct target_sigcontext *sc)
bellard106ec872006-06-27 21:08:10 +00002879{
Richard Henderson084d0492013-02-10 10:30:44 -08002880 int i;
bellard106ec872006-06-27 21:08:10 +00002881
Riku Voipio1d8b5122014-04-23 10:26:05 +03002882 __put_user(exception_resume_pc(regs), &sc->sc_pc);
Kwok Cheung Yeung1239b472013-05-17 14:51:21 -07002883 regs->hflags &= ~MIPS_HFLAG_BMASK;
bellard106ec872006-06-27 21:08:10 +00002884
Richard Henderson084d0492013-02-10 10:30:44 -08002885 __put_user(0, &sc->sc_regs[0]);
2886 for (i = 1; i < 32; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002887 __put_user(regs->active_tc.gpr[i], &sc->sc_regs[i]);
Richard Henderson084d0492013-02-10 10:30:44 -08002888 }
bellard106ec872006-06-27 21:08:10 +00002889
Riku Voipio1d8b5122014-04-23 10:26:05 +03002890 __put_user(regs->active_tc.HI[0], &sc->sc_mdhi);
2891 __put_user(regs->active_tc.LO[0], &sc->sc_mdlo);
bellard106ec872006-06-27 21:08:10 +00002892
Richard Henderson084d0492013-02-10 10:30:44 -08002893 /* Rather than checking for dsp existence, always copy. The storage
2894 would just be garbage otherwise. */
Riku Voipio1d8b5122014-04-23 10:26:05 +03002895 __put_user(regs->active_tc.HI[1], &sc->sc_hi1);
2896 __put_user(regs->active_tc.HI[2], &sc->sc_hi2);
2897 __put_user(regs->active_tc.HI[3], &sc->sc_hi3);
2898 __put_user(regs->active_tc.LO[1], &sc->sc_lo1);
2899 __put_user(regs->active_tc.LO[2], &sc->sc_lo2);
2900 __put_user(regs->active_tc.LO[3], &sc->sc_lo3);
Richard Henderson084d0492013-02-10 10:30:44 -08002901 {
2902 uint32_t dsp = cpu_rddsp(0x3ff, regs);
Riku Voipio1d8b5122014-04-23 10:26:05 +03002903 __put_user(dsp, &sc->sc_dsp);
bellard106ec872006-06-27 21:08:10 +00002904 }
Richard Henderson084d0492013-02-10 10:30:44 -08002905
Riku Voipio1d8b5122014-04-23 10:26:05 +03002906 __put_user(1, &sc->sc_used_math);
Richard Henderson084d0492013-02-10 10:30:44 -08002907
2908 for (i = 0; i < 32; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002909 __put_user(regs->active_fpu.fpr[i].d, &sc->sc_fpregs[i]);
bellard106ec872006-06-27 21:08:10 +00002910 }
bellard106ec872006-06-27 21:08:10 +00002911}
2912
Riku Voipio016d2e12014-04-23 11:19:48 +03002913static inline void
Andreas Färber05390242012-02-25 03:37:53 +01002914restore_sigcontext(CPUMIPSState *regs, struct target_sigcontext *sc)
bellard106ec872006-06-27 21:08:10 +00002915{
Richard Henderson084d0492013-02-10 10:30:44 -08002916 int i;
bellard106ec872006-06-27 21:08:10 +00002917
Riku Voipio1d8b5122014-04-23 10:26:05 +03002918 __get_user(regs->CP0_EPC, &sc->sc_pc);
bellard106ec872006-06-27 21:08:10 +00002919
Riku Voipio1d8b5122014-04-23 10:26:05 +03002920 __get_user(regs->active_tc.HI[0], &sc->sc_mdhi);
2921 __get_user(regs->active_tc.LO[0], &sc->sc_mdlo);
bellard106ec872006-06-27 21:08:10 +00002922
Richard Henderson084d0492013-02-10 10:30:44 -08002923 for (i = 1; i < 32; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002924 __get_user(regs->active_tc.gpr[i], &sc->sc_regs[i]);
bellard106ec872006-06-27 21:08:10 +00002925 }
2926
Riku Voipio1d8b5122014-04-23 10:26:05 +03002927 __get_user(regs->active_tc.HI[1], &sc->sc_hi1);
2928 __get_user(regs->active_tc.HI[2], &sc->sc_hi2);
2929 __get_user(regs->active_tc.HI[3], &sc->sc_hi3);
2930 __get_user(regs->active_tc.LO[1], &sc->sc_lo1);
2931 __get_user(regs->active_tc.LO[2], &sc->sc_lo2);
2932 __get_user(regs->active_tc.LO[3], &sc->sc_lo3);
Richard Henderson084d0492013-02-10 10:30:44 -08002933 {
2934 uint32_t dsp;
Riku Voipio1d8b5122014-04-23 10:26:05 +03002935 __get_user(dsp, &sc->sc_dsp);
Richard Henderson084d0492013-02-10 10:30:44 -08002936 cpu_wrdsp(dsp, 0x3ff, regs);
2937 }
2938
2939 for (i = 0; i < 32; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002940 __get_user(regs->active_fpu.fpr[i].d, &sc->sc_fpregs[i]);
Richard Henderson084d0492013-02-10 10:30:44 -08002941 }
bellard106ec872006-06-27 21:08:10 +00002942}
Richard Hendersonff970902013-02-10 10:30:42 -08002943
bellard106ec872006-06-27 21:08:10 +00002944/*
2945 * Determine which stack to use..
2946 */
bellard579a97f2007-11-11 14:26:47 +00002947static inline abi_ulong
Andreas Färber05390242012-02-25 03:37:53 +01002948get_sigframe(struct target_sigaction *ka, CPUMIPSState *regs, size_t frame_size)
bellard106ec872006-06-27 21:08:10 +00002949{
2950 unsigned long sp;
2951
2952 /* Default to using normal stack */
thsb5dc7732008-06-27 10:02:35 +00002953 sp = regs->active_tc.gpr[29];
bellard106ec872006-06-27 21:08:10 +00002954
2955 /*
Stefan Weil93148aa2012-02-26 18:46:12 +01002956 * FPU emulator may have its own trampoline active just
bellard106ec872006-06-27 21:08:10 +00002957 * above the user stack, 16-bytes before the next lowest
2958 * 16 byte boundary. Try to avoid trashing it.
2959 */
2960 sp -= 32;
2961
bellard106ec872006-06-27 21:08:10 +00002962 /* This is the X/Open sanctioned signal stack switching. */
pbrook624f7972008-05-31 16:11:38 +00002963 if ((ka->sa_flags & TARGET_SA_ONSTACK) && (sas_ss_flags (sp) == 0)) {
thsa04e1342007-09-27 13:57:58 +00002964 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
2965 }
bellard106ec872006-06-27 21:08:10 +00002966
bellard579a97f2007-11-11 14:26:47 +00002967 return (sp - frame_size) & ~7;
bellard106ec872006-06-27 21:08:10 +00002968}
2969
Kwok Cheung Yeungea3164a2013-05-17 14:51:20 -07002970static void mips_set_hflags_isa_mode_from_pc(CPUMIPSState *env)
2971{
2972 if (env->insn_flags & (ASE_MIPS16 | ASE_MICROMIPS)) {
2973 env->hflags &= ~MIPS_HFLAG_M16;
2974 env->hflags |= (env->active_tc.PC & 1) << MIPS_HFLAG_M16_SHIFT;
2975 env->active_tc.PC &= ~(target_ulong) 1;
2976 }
2977}
2978
Richard Hendersonff970902013-02-10 10:30:42 -08002979# if defined(TARGET_ABI_MIPSO32)
bellard579a97f2007-11-11 14:26:47 +00002980/* compare linux/arch/mips/kernel/signal.c:setup_frame() */
pbrook624f7972008-05-31 16:11:38 +00002981static void setup_frame(int sig, struct target_sigaction * ka,
Andreas Färber05390242012-02-25 03:37:53 +01002982 target_sigset_t *set, CPUMIPSState *regs)
bellard106ec872006-06-27 21:08:10 +00002983{
2984 struct sigframe *frame;
bellard579a97f2007-11-11 14:26:47 +00002985 abi_ulong frame_addr;
bellard106ec872006-06-27 21:08:10 +00002986 int i;
2987
bellard579a97f2007-11-11 14:26:47 +00002988 frame_addr = get_sigframe(ka, regs, sizeof(*frame));
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01002989 trace_user_setup_frame(regs, frame_addr);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002990 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
2991 goto give_sigsegv;
2992 }
bellard106ec872006-06-27 21:08:10 +00002993
2994 install_sigtramp(frame->sf_code, TARGET_NR_sigreturn);
2995
Riku Voipio41ecc722014-04-23 11:01:00 +03002996 setup_sigcontext(regs, &frame->sf_sc);
bellard106ec872006-06-27 21:08:10 +00002997
2998 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
Riku Voipio0188fad2014-04-23 13:34:15 +03002999 __put_user(set->sig[i], &frame->sf_mask.sig[i]);
bellard106ec872006-06-27 21:08:10 +00003000 }
3001
3002 /*
3003 * Arguments to signal handler:
3004 *
3005 * a0 = signal number
3006 * a1 = 0 (should be cause)
3007 * a2 = pointer to struct sigcontext
3008 *
3009 * $25 and PC point to the signal handler, $29 points to the
3010 * struct sigframe.
3011 */
thsb5dc7732008-06-27 10:02:35 +00003012 regs->active_tc.gpr[ 4] = sig;
3013 regs->active_tc.gpr[ 5] = 0;
3014 regs->active_tc.gpr[ 6] = frame_addr + offsetof(struct sigframe, sf_sc);
3015 regs->active_tc.gpr[29] = frame_addr;
3016 regs->active_tc.gpr[31] = frame_addr + offsetof(struct sigframe, sf_code);
bellard106ec872006-06-27 21:08:10 +00003017 /* The original kernel code sets CP0_EPC to the handler
3018 * since it returns to userland using eret
3019 * we cannot do this here, and we must set PC directly */
thsb5dc7732008-06-27 10:02:35 +00003020 regs->active_tc.PC = regs->active_tc.gpr[25] = ka->_sa_handler;
Kwok Cheung Yeungea3164a2013-05-17 14:51:20 -07003021 mips_set_hflags_isa_mode_from_pc(regs);
bellard579a97f2007-11-11 14:26:47 +00003022 unlock_user_struct(frame, frame_addr, 1);
bellard106ec872006-06-27 21:08:10 +00003023 return;
3024
3025give_sigsegv:
3026 force_sig(TARGET_SIGSEGV/*, current*/);
bellard106ec872006-06-27 21:08:10 +00003027}
3028
Andreas Färber05390242012-02-25 03:37:53 +01003029long do_sigreturn(CPUMIPSState *regs)
bellard106ec872006-06-27 21:08:10 +00003030{
ths388bb212007-05-13 13:58:00 +00003031 struct sigframe *frame;
bellard579a97f2007-11-11 14:26:47 +00003032 abi_ulong frame_addr;
ths388bb212007-05-13 13:58:00 +00003033 sigset_t blocked;
Anthony Liguoric227f092009-10-01 16:12:16 -05003034 target_sigset_t target_set;
ths388bb212007-05-13 13:58:00 +00003035 int i;
bellard106ec872006-06-27 21:08:10 +00003036
thsb5dc7732008-06-27 10:02:35 +00003037 frame_addr = regs->active_tc.gpr[29];
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01003038 trace_user_do_sigreturn(regs, frame_addr);
bellard579a97f2007-11-11 14:26:47 +00003039 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003040 goto badframe;
bellard106ec872006-06-27 21:08:10 +00003041
ths388bb212007-05-13 13:58:00 +00003042 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
Riku Voipiof5f601a2014-04-23 13:00:17 +03003043 __get_user(target_set.sig[i], &frame->sf_mask.sig[i]);
ths388bb212007-05-13 13:58:00 +00003044 }
bellard106ec872006-06-27 21:08:10 +00003045
ths388bb212007-05-13 13:58:00 +00003046 target_to_host_sigset_internal(&blocked, &target_set);
Peter Maydell9eede5b2016-05-27 15:51:46 +01003047 set_sigmask(&blocked);
bellard106ec872006-06-27 21:08:10 +00003048
Riku Voipio016d2e12014-04-23 11:19:48 +03003049 restore_sigcontext(regs, &frame->sf_sc);
bellard106ec872006-06-27 21:08:10 +00003050
3051#if 0
ths388bb212007-05-13 13:58:00 +00003052 /*
3053 * Don't let your children do this ...
3054 */
3055 __asm__ __volatile__(
bellard106ec872006-06-27 21:08:10 +00003056 "move\t$29, %0\n\t"
3057 "j\tsyscall_exit"
3058 :/* no outputs */
3059 :"r" (&regs));
ths388bb212007-05-13 13:58:00 +00003060 /* Unreached */
bellard106ec872006-06-27 21:08:10 +00003061#endif
ths3b46e622007-09-17 08:09:54 +00003062
thsb5dc7732008-06-27 10:02:35 +00003063 regs->active_tc.PC = regs->CP0_EPC;
Kwok Cheung Yeungea3164a2013-05-17 14:51:20 -07003064 mips_set_hflags_isa_mode_from_pc(regs);
ths388bb212007-05-13 13:58:00 +00003065 /* I am not sure this is right, but it seems to work
bellard106ec872006-06-27 21:08:10 +00003066 * maybe a problem with nested signals ? */
3067 regs->CP0_EPC = 0;
pbrook0b1bcb02009-04-21 01:41:10 +00003068 return -TARGET_QEMU_ESIGRETURN;
bellard106ec872006-06-27 21:08:10 +00003069
3070badframe:
ths388bb212007-05-13 13:58:00 +00003071 force_sig(TARGET_SIGSEGV/*, current*/);
3072 return 0;
bellard106ec872006-06-27 21:08:10 +00003073}
Richard Hendersonff970902013-02-10 10:30:42 -08003074# endif /* O32 */
bellard106ec872006-06-27 21:08:10 +00003075
pbrook624f7972008-05-31 16:11:38 +00003076static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05003077 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01003078 target_sigset_t *set, CPUMIPSState *env)
bellard106ec872006-06-27 21:08:10 +00003079{
pbrook0b1bcb02009-04-21 01:41:10 +00003080 struct target_rt_sigframe *frame;
3081 abi_ulong frame_addr;
3082 int i;
3083
3084 frame_addr = get_sigframe(ka, env, sizeof(*frame));
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01003085 trace_user_setup_rt_frame(env, frame_addr);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003086 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
3087 goto give_sigsegv;
3088 }
pbrook0b1bcb02009-04-21 01:41:10 +00003089
3090 install_sigtramp(frame->rs_code, TARGET_NR_rt_sigreturn);
3091
Peter Maydellf6c7a052015-01-08 12:19:48 +00003092 tswap_siginfo(&frame->rs_info, info);
pbrook0b1bcb02009-04-21 01:41:10 +00003093
Aurelien Jarno60e99242010-03-29 02:12:51 +02003094 __put_user(0, &frame->rs_uc.tuc_flags);
3095 __put_user(0, &frame->rs_uc.tuc_link);
3096 __put_user(target_sigaltstack_used.ss_sp, &frame->rs_uc.tuc_stack.ss_sp);
3097 __put_user(target_sigaltstack_used.ss_size, &frame->rs_uc.tuc_stack.ss_size);
pbrook0b1bcb02009-04-21 01:41:10 +00003098 __put_user(sas_ss_flags(get_sp_from_cpustate(env)),
Aurelien Jarno60e99242010-03-29 02:12:51 +02003099 &frame->rs_uc.tuc_stack.ss_flags);
pbrook0b1bcb02009-04-21 01:41:10 +00003100
Aurelien Jarno60e99242010-03-29 02:12:51 +02003101 setup_sigcontext(env, &frame->rs_uc.tuc_mcontext);
pbrook0b1bcb02009-04-21 01:41:10 +00003102
3103 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
Aurelien Jarno60e99242010-03-29 02:12:51 +02003104 __put_user(set->sig[i], &frame->rs_uc.tuc_sigmask.sig[i]);
pbrook0b1bcb02009-04-21 01:41:10 +00003105 }
3106
3107 /*
3108 * Arguments to signal handler:
3109 *
3110 * a0 = signal number
Richard W.M. Jones02d2bd52012-07-05 03:32:44 +00003111 * a1 = pointer to siginfo_t
pbrook0b1bcb02009-04-21 01:41:10 +00003112 * a2 = pointer to struct ucontext
3113 *
3114 * $25 and PC point to the signal handler, $29 points to the
3115 * struct sigframe.
3116 */
3117 env->active_tc.gpr[ 4] = sig;
3118 env->active_tc.gpr[ 5] = frame_addr
3119 + offsetof(struct target_rt_sigframe, rs_info);
3120 env->active_tc.gpr[ 6] = frame_addr
3121 + offsetof(struct target_rt_sigframe, rs_uc);
3122 env->active_tc.gpr[29] = frame_addr;
3123 env->active_tc.gpr[31] = frame_addr
3124 + offsetof(struct target_rt_sigframe, rs_code);
3125 /* The original kernel code sets CP0_EPC to the handler
3126 * since it returns to userland using eret
3127 * we cannot do this here, and we must set PC directly */
3128 env->active_tc.PC = env->active_tc.gpr[25] = ka->_sa_handler;
Kwok Cheung Yeungea3164a2013-05-17 14:51:20 -07003129 mips_set_hflags_isa_mode_from_pc(env);
pbrook0b1bcb02009-04-21 01:41:10 +00003130 unlock_user_struct(frame, frame_addr, 1);
3131 return;
3132
3133give_sigsegv:
3134 unlock_user_struct(frame, frame_addr, 1);
3135 force_sig(TARGET_SIGSEGV/*, current*/);
bellard106ec872006-06-27 21:08:10 +00003136}
3137
Andreas Färber05390242012-02-25 03:37:53 +01003138long do_rt_sigreturn(CPUMIPSState *env)
bellard106ec872006-06-27 21:08:10 +00003139{
pbrook0b1bcb02009-04-21 01:41:10 +00003140 struct target_rt_sigframe *frame;
3141 abi_ulong frame_addr;
3142 sigset_t blocked;
3143
pbrook0b1bcb02009-04-21 01:41:10 +00003144 frame_addr = env->active_tc.gpr[29];
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01003145 trace_user_do_rt_sigreturn(env, frame_addr);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003146 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
3147 goto badframe;
3148 }
pbrook0b1bcb02009-04-21 01:41:10 +00003149
Aurelien Jarno60e99242010-03-29 02:12:51 +02003150 target_to_host_sigset(&blocked, &frame->rs_uc.tuc_sigmask);
Peter Maydell9eede5b2016-05-27 15:51:46 +01003151 set_sigmask(&blocked);
pbrook0b1bcb02009-04-21 01:41:10 +00003152
Riku Voipio016d2e12014-04-23 11:19:48 +03003153 restore_sigcontext(env, &frame->rs_uc.tuc_mcontext);
pbrook0b1bcb02009-04-21 01:41:10 +00003154
3155 if (do_sigaltstack(frame_addr +
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003156 offsetof(struct target_rt_sigframe, rs_uc.tuc_stack),
3157 0, get_sp_from_cpustate(env)) == -EFAULT)
pbrook0b1bcb02009-04-21 01:41:10 +00003158 goto badframe;
3159
3160 env->active_tc.PC = env->CP0_EPC;
Kwok Cheung Yeungea3164a2013-05-17 14:51:20 -07003161 mips_set_hflags_isa_mode_from_pc(env);
pbrook0b1bcb02009-04-21 01:41:10 +00003162 /* I am not sure this is right, but it seems to work
3163 * maybe a problem with nested signals ? */
3164 env->CP0_EPC = 0;
3165 return -TARGET_QEMU_ESIGRETURN;
3166
3167badframe:
3168 force_sig(TARGET_SIGSEGV/*, current*/);
3169 return 0;
bellard106ec872006-06-27 21:08:10 +00003170}
bellard6d5e2162004-09-30 22:04:13 +00003171
thsc3b5bc82007-12-02 06:31:25 +00003172#elif defined(TARGET_SH4)
3173
3174/*
3175 * code and data structures from linux kernel:
3176 * include/asm-sh/sigcontext.h
3177 * arch/sh/kernel/signal.c
3178 */
3179
3180struct target_sigcontext {
3181 target_ulong oldmask;
3182
3183 /* CPU registers */
3184 target_ulong sc_gregs[16];
3185 target_ulong sc_pc;
3186 target_ulong sc_pr;
3187 target_ulong sc_sr;
3188 target_ulong sc_gbr;
3189 target_ulong sc_mach;
3190 target_ulong sc_macl;
3191
3192 /* FPU registers */
3193 target_ulong sc_fpregs[16];
3194 target_ulong sc_xfpregs[16];
3195 unsigned int sc_fpscr;
3196 unsigned int sc_fpul;
3197 unsigned int sc_ownedfp;
3198};
3199
3200struct target_sigframe
3201{
3202 struct target_sigcontext sc;
3203 target_ulong extramask[TARGET_NSIG_WORDS-1];
3204 uint16_t retcode[3];
3205};
3206
3207
3208struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02003209 target_ulong tuc_flags;
3210 struct target_ucontext *tuc_link;
3211 target_stack_t tuc_stack;
3212 struct target_sigcontext tuc_mcontext;
3213 target_sigset_t tuc_sigmask; /* mask last for extensibility */
thsc3b5bc82007-12-02 06:31:25 +00003214};
3215
3216struct target_rt_sigframe
3217{
3218 struct target_siginfo info;
3219 struct target_ucontext uc;
3220 uint16_t retcode[3];
3221};
3222
3223
3224#define MOVW(n) (0x9300|((n)-2)) /* Move mem word at PC+n to R3 */
3225#define TRAP_NOARG 0xc310 /* Syscall w/no args (NR in R3) SH3/4 */
3226
pbrook624f7972008-05-31 16:11:38 +00003227static abi_ulong get_sigframe(struct target_sigaction *ka,
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003228 unsigned long sp, size_t frame_size)
thsc3b5bc82007-12-02 06:31:25 +00003229{
pbrook624f7972008-05-31 16:11:38 +00003230 if ((ka->sa_flags & TARGET_SA_ONSTACK) && (sas_ss_flags(sp) == 0)) {
thsc3b5bc82007-12-02 06:31:25 +00003231 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
3232 }
3233
3234 return (sp - frame_size) & -8ul;
3235}
3236
Riku Voipio41ecc722014-04-23 11:01:00 +03003237static void setup_sigcontext(struct target_sigcontext *sc,
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003238 CPUSH4State *regs, unsigned long mask)
thsc3b5bc82007-12-02 06:31:25 +00003239{
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003240 int i;
thsc3b5bc82007-12-02 06:31:25 +00003241
Riku Voipio1d8b5122014-04-23 10:26:05 +03003242#define COPY(x) __put_user(regs->x, &sc->sc_##x)
thsc3b5bc82007-12-02 06:31:25 +00003243 COPY(gregs[0]); COPY(gregs[1]);
3244 COPY(gregs[2]); COPY(gregs[3]);
3245 COPY(gregs[4]); COPY(gregs[5]);
3246 COPY(gregs[6]); COPY(gregs[7]);
3247 COPY(gregs[8]); COPY(gregs[9]);
3248 COPY(gregs[10]); COPY(gregs[11]);
3249 COPY(gregs[12]); COPY(gregs[13]);
3250 COPY(gregs[14]); COPY(gregs[15]);
3251 COPY(gbr); COPY(mach);
3252 COPY(macl); COPY(pr);
3253 COPY(sr); COPY(pc);
3254#undef COPY
3255
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003256 for (i=0; i<16; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03003257 __put_user(regs->fregs[i], &sc->sc_fpregs[i]);
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003258 }
Riku Voipio1d8b5122014-04-23 10:26:05 +03003259 __put_user(regs->fpscr, &sc->sc_fpscr);
3260 __put_user(regs->fpul, &sc->sc_fpul);
thsc3b5bc82007-12-02 06:31:25 +00003261
3262 /* non-iBCS2 extensions.. */
Riku Voipio1d8b5122014-04-23 10:26:05 +03003263 __put_user(mask, &sc->oldmask);
thsc3b5bc82007-12-02 06:31:25 +00003264}
3265
Timothy E Baldwinba412492016-05-12 18:47:35 +01003266static void restore_sigcontext(CPUSH4State *regs, struct target_sigcontext *sc)
thsc3b5bc82007-12-02 06:31:25 +00003267{
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003268 int i;
thsc3b5bc82007-12-02 06:31:25 +00003269
Riku Voipio1d8b5122014-04-23 10:26:05 +03003270#define COPY(x) __get_user(regs->x, &sc->sc_##x)
Timothy E Baldwinba412492016-05-12 18:47:35 +01003271 COPY(gregs[0]); COPY(gregs[1]);
thsc3b5bc82007-12-02 06:31:25 +00003272 COPY(gregs[2]); COPY(gregs[3]);
3273 COPY(gregs[4]); COPY(gregs[5]);
3274 COPY(gregs[6]); COPY(gregs[7]);
3275 COPY(gregs[8]); COPY(gregs[9]);
3276 COPY(gregs[10]); COPY(gregs[11]);
3277 COPY(gregs[12]); COPY(gregs[13]);
3278 COPY(gregs[14]); COPY(gregs[15]);
3279 COPY(gbr); COPY(mach);
3280 COPY(macl); COPY(pr);
3281 COPY(sr); COPY(pc);
3282#undef COPY
3283
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003284 for (i=0; i<16; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03003285 __get_user(regs->fregs[i], &sc->sc_fpregs[i]);
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003286 }
Riku Voipio1d8b5122014-04-23 10:26:05 +03003287 __get_user(regs->fpscr, &sc->sc_fpscr);
3288 __get_user(regs->fpul, &sc->sc_fpul);
thsc3b5bc82007-12-02 06:31:25 +00003289
3290 regs->tra = -1; /* disable syscall checks */
thsc3b5bc82007-12-02 06:31:25 +00003291}
3292
pbrook624f7972008-05-31 16:11:38 +00003293static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01003294 target_sigset_t *set, CPUSH4State *regs)
thsc3b5bc82007-12-02 06:31:25 +00003295{
3296 struct target_sigframe *frame;
3297 abi_ulong frame_addr;
3298 int i;
thsc3b5bc82007-12-02 06:31:25 +00003299
3300 frame_addr = get_sigframe(ka, regs->gregs[15], sizeof(*frame));
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01003301 trace_user_setup_frame(regs, frame_addr);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003302 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
3303 goto give_sigsegv;
3304 }
thsc3b5bc82007-12-02 06:31:25 +00003305
Riku Voipio41ecc722014-04-23 11:01:00 +03003306 setup_sigcontext(&frame->sc, regs, set->sig[0]);
thsc3b5bc82007-12-02 06:31:25 +00003307
3308 for (i = 0; i < TARGET_NSIG_WORDS - 1; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03003309 __put_user(set->sig[i + 1], &frame->extramask[i]);
thsc3b5bc82007-12-02 06:31:25 +00003310 }
3311
3312 /* Set up to return from userspace. If provided, use a stub
3313 already in userspace. */
pbrook624f7972008-05-31 16:11:38 +00003314 if (ka->sa_flags & TARGET_SA_RESTORER) {
3315 regs->pr = (unsigned long) ka->sa_restorer;
thsc3b5bc82007-12-02 06:31:25 +00003316 } else {
3317 /* Generate return code (system call to sigreturn) */
Laurent Vivier2a0fa682015-11-23 11:38:26 +01003318 abi_ulong retcode_addr = frame_addr +
3319 offsetof(struct target_sigframe, retcode);
Riku Voipio1d8b5122014-04-23 10:26:05 +03003320 __put_user(MOVW(2), &frame->retcode[0]);
3321 __put_user(TRAP_NOARG, &frame->retcode[1]);
3322 __put_user((TARGET_NR_sigreturn), &frame->retcode[2]);
Laurent Vivier2a0fa682015-11-23 11:38:26 +01003323 regs->pr = (unsigned long) retcode_addr;
thsc3b5bc82007-12-02 06:31:25 +00003324 }
3325
thsc3b5bc82007-12-02 06:31:25 +00003326 /* Set up registers for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003327 regs->gregs[15] = frame_addr;
Peter Maydellb6e2c932015-01-08 12:19:43 +00003328 regs->gregs[4] = sig; /* Arg for signal handler */
thsc3b5bc82007-12-02 06:31:25 +00003329 regs->gregs[5] = 0;
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003330 regs->gregs[6] = frame_addr += offsetof(typeof(*frame), sc);
pbrook624f7972008-05-31 16:11:38 +00003331 regs->pc = (unsigned long) ka->_sa_handler;
thsc3b5bc82007-12-02 06:31:25 +00003332
3333 unlock_user_struct(frame, frame_addr, 1);
3334 return;
3335
3336give_sigsegv:
3337 unlock_user_struct(frame, frame_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02003338 force_sig(TARGET_SIGSEGV);
thsc3b5bc82007-12-02 06:31:25 +00003339}
3340
pbrook624f7972008-05-31 16:11:38 +00003341static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05003342 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01003343 target_sigset_t *set, CPUSH4State *regs)
thsc3b5bc82007-12-02 06:31:25 +00003344{
3345 struct target_rt_sigframe *frame;
3346 abi_ulong frame_addr;
3347 int i;
thsc3b5bc82007-12-02 06:31:25 +00003348
3349 frame_addr = get_sigframe(ka, regs->gregs[15], sizeof(*frame));
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01003350 trace_user_setup_rt_frame(regs, frame_addr);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003351 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
3352 goto give_sigsegv;
3353 }
thsc3b5bc82007-12-02 06:31:25 +00003354
Peter Maydellf6c7a052015-01-08 12:19:48 +00003355 tswap_siginfo(&frame->info, info);
thsc3b5bc82007-12-02 06:31:25 +00003356
3357 /* Create the ucontext. */
Riku Voipio1d8b5122014-04-23 10:26:05 +03003358 __put_user(0, &frame->uc.tuc_flags);
3359 __put_user(0, (unsigned long *)&frame->uc.tuc_link);
3360 __put_user((unsigned long)target_sigaltstack_used.ss_sp,
3361 &frame->uc.tuc_stack.ss_sp);
3362 __put_user(sas_ss_flags(regs->gregs[15]),
3363 &frame->uc.tuc_stack.ss_flags);
3364 __put_user(target_sigaltstack_used.ss_size,
3365 &frame->uc.tuc_stack.ss_size);
3366 setup_sigcontext(&frame->uc.tuc_mcontext,
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003367 regs, set->sig[0]);
thsc3b5bc82007-12-02 06:31:25 +00003368 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03003369 __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
thsc3b5bc82007-12-02 06:31:25 +00003370 }
3371
3372 /* Set up to return from userspace. If provided, use a stub
3373 already in userspace. */
pbrook624f7972008-05-31 16:11:38 +00003374 if (ka->sa_flags & TARGET_SA_RESTORER) {
3375 regs->pr = (unsigned long) ka->sa_restorer;
thsc3b5bc82007-12-02 06:31:25 +00003376 } else {
3377 /* Generate return code (system call to sigreturn) */
Laurent Vivier2a0fa682015-11-23 11:38:26 +01003378 abi_ulong retcode_addr = frame_addr +
3379 offsetof(struct target_rt_sigframe, retcode);
Riku Voipio1d8b5122014-04-23 10:26:05 +03003380 __put_user(MOVW(2), &frame->retcode[0]);
3381 __put_user(TRAP_NOARG, &frame->retcode[1]);
3382 __put_user((TARGET_NR_rt_sigreturn), &frame->retcode[2]);
Laurent Vivier2a0fa682015-11-23 11:38:26 +01003383 regs->pr = (unsigned long) retcode_addr;
thsc3b5bc82007-12-02 06:31:25 +00003384 }
3385
thsc3b5bc82007-12-02 06:31:25 +00003386 /* Set up registers for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003387 regs->gregs[15] = frame_addr;
Peter Maydellb6e2c932015-01-08 12:19:43 +00003388 regs->gregs[4] = sig; /* Arg for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003389 regs->gregs[5] = frame_addr + offsetof(typeof(*frame), info);
3390 regs->gregs[6] = frame_addr + offsetof(typeof(*frame), uc);
pbrook624f7972008-05-31 16:11:38 +00003391 regs->pc = (unsigned long) ka->_sa_handler;
thsc3b5bc82007-12-02 06:31:25 +00003392
3393 unlock_user_struct(frame, frame_addr, 1);
3394 return;
3395
3396give_sigsegv:
3397 unlock_user_struct(frame, frame_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02003398 force_sig(TARGET_SIGSEGV);
thsc3b5bc82007-12-02 06:31:25 +00003399}
3400
Andreas Färber05390242012-02-25 03:37:53 +01003401long do_sigreturn(CPUSH4State *regs)
thsc3b5bc82007-12-02 06:31:25 +00003402{
3403 struct target_sigframe *frame;
3404 abi_ulong frame_addr;
3405 sigset_t blocked;
Anthony Liguoric227f092009-10-01 16:12:16 -05003406 target_sigset_t target_set;
thsc3b5bc82007-12-02 06:31:25 +00003407 int i;
3408 int err = 0;
3409
thsc3b5bc82007-12-02 06:31:25 +00003410 frame_addr = regs->gregs[15];
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01003411 trace_user_do_sigreturn(regs, frame_addr);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003412 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
3413 goto badframe;
3414 }
thsc3b5bc82007-12-02 06:31:25 +00003415
Riku Voipio1d8b5122014-04-23 10:26:05 +03003416 __get_user(target_set.sig[0], &frame->sc.oldmask);
thsc3b5bc82007-12-02 06:31:25 +00003417 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03003418 __get_user(target_set.sig[i], &frame->extramask[i - 1]);
thsc3b5bc82007-12-02 06:31:25 +00003419 }
3420
3421 if (err)
3422 goto badframe;
3423
3424 target_to_host_sigset_internal(&blocked, &target_set);
Peter Maydell9eede5b2016-05-27 15:51:46 +01003425 set_sigmask(&blocked);
thsc3b5bc82007-12-02 06:31:25 +00003426
Timothy E Baldwinba412492016-05-12 18:47:35 +01003427 restore_sigcontext(regs, &frame->sc);
thsc3b5bc82007-12-02 06:31:25 +00003428
3429 unlock_user_struct(frame, frame_addr, 0);
Timothy E Baldwinba412492016-05-12 18:47:35 +01003430 return -TARGET_QEMU_ESIGRETURN;
thsc3b5bc82007-12-02 06:31:25 +00003431
3432badframe:
3433 unlock_user_struct(frame, frame_addr, 0);
3434 force_sig(TARGET_SIGSEGV);
3435 return 0;
3436}
3437
Andreas Färber05390242012-02-25 03:37:53 +01003438long do_rt_sigreturn(CPUSH4State *regs)
thsc3b5bc82007-12-02 06:31:25 +00003439{
3440 struct target_rt_sigframe *frame;
3441 abi_ulong frame_addr;
3442 sigset_t blocked;
3443
thsc3b5bc82007-12-02 06:31:25 +00003444 frame_addr = regs->gregs[15];
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01003445 trace_user_do_rt_sigreturn(regs, frame_addr);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003446 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
3447 goto badframe;
3448 }
thsc3b5bc82007-12-02 06:31:25 +00003449
Aurelien Jarno60e99242010-03-29 02:12:51 +02003450 target_to_host_sigset(&blocked, &frame->uc.tuc_sigmask);
Peter Maydell9eede5b2016-05-27 15:51:46 +01003451 set_sigmask(&blocked);
thsc3b5bc82007-12-02 06:31:25 +00003452
Timothy E Baldwinba412492016-05-12 18:47:35 +01003453 restore_sigcontext(regs, &frame->uc.tuc_mcontext);
thsc3b5bc82007-12-02 06:31:25 +00003454
3455 if (do_sigaltstack(frame_addr +
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003456 offsetof(struct target_rt_sigframe, uc.tuc_stack),
3457 0, get_sp_from_cpustate(regs)) == -EFAULT) {
thsc3b5bc82007-12-02 06:31:25 +00003458 goto badframe;
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003459 }
thsc3b5bc82007-12-02 06:31:25 +00003460
3461 unlock_user_struct(frame, frame_addr, 0);
Timothy E Baldwinba412492016-05-12 18:47:35 +01003462 return -TARGET_QEMU_ESIGRETURN;
thsc3b5bc82007-12-02 06:31:25 +00003463
3464badframe:
3465 unlock_user_struct(frame, frame_addr, 0);
3466 force_sig(TARGET_SIGSEGV);
3467 return 0;
3468}
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003469#elif defined(TARGET_MICROBLAZE)
3470
3471struct target_sigcontext {
3472 struct target_pt_regs regs; /* needs to be first */
3473 uint32_t oldmask;
3474};
3475
Edgar E. Iglesiasb2178702010-07-23 09:30:37 +02003476struct target_stack_t {
3477 abi_ulong ss_sp;
3478 int ss_flags;
3479 unsigned int ss_size;
3480};
3481
3482struct target_ucontext {
Richard Hendersonf711df62010-11-22 14:57:52 -08003483 abi_ulong tuc_flags;
3484 abi_ulong tuc_link;
3485 struct target_stack_t tuc_stack;
3486 struct target_sigcontext tuc_mcontext;
3487 uint32_t tuc_extramask[TARGET_NSIG_WORDS - 1];
Edgar E. Iglesiasb2178702010-07-23 09:30:37 +02003488};
3489
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003490/* Signal frames. */
3491struct target_signal_frame {
Edgar E. Iglesiasb2178702010-07-23 09:30:37 +02003492 struct target_ucontext uc;
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003493 uint32_t extramask[TARGET_NSIG_WORDS - 1];
3494 uint32_t tramp[2];
3495};
3496
3497struct rt_signal_frame {
Richard W.M. Jones02d2bd52012-07-05 03:32:44 +00003498 siginfo_t info;
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003499 struct ucontext uc;
3500 uint32_t tramp[2];
3501};
3502
Andreas Färber05390242012-02-25 03:37:53 +01003503static void setup_sigcontext(struct target_sigcontext *sc, CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003504{
3505 __put_user(env->regs[0], &sc->regs.r0);
3506 __put_user(env->regs[1], &sc->regs.r1);
3507 __put_user(env->regs[2], &sc->regs.r2);
3508 __put_user(env->regs[3], &sc->regs.r3);
3509 __put_user(env->regs[4], &sc->regs.r4);
3510 __put_user(env->regs[5], &sc->regs.r5);
3511 __put_user(env->regs[6], &sc->regs.r6);
3512 __put_user(env->regs[7], &sc->regs.r7);
3513 __put_user(env->regs[8], &sc->regs.r8);
3514 __put_user(env->regs[9], &sc->regs.r9);
3515 __put_user(env->regs[10], &sc->regs.r10);
3516 __put_user(env->regs[11], &sc->regs.r11);
3517 __put_user(env->regs[12], &sc->regs.r12);
3518 __put_user(env->regs[13], &sc->regs.r13);
3519 __put_user(env->regs[14], &sc->regs.r14);
3520 __put_user(env->regs[15], &sc->regs.r15);
3521 __put_user(env->regs[16], &sc->regs.r16);
3522 __put_user(env->regs[17], &sc->regs.r17);
3523 __put_user(env->regs[18], &sc->regs.r18);
3524 __put_user(env->regs[19], &sc->regs.r19);
3525 __put_user(env->regs[20], &sc->regs.r20);
3526 __put_user(env->regs[21], &sc->regs.r21);
3527 __put_user(env->regs[22], &sc->regs.r22);
3528 __put_user(env->regs[23], &sc->regs.r23);
3529 __put_user(env->regs[24], &sc->regs.r24);
3530 __put_user(env->regs[25], &sc->regs.r25);
3531 __put_user(env->regs[26], &sc->regs.r26);
3532 __put_user(env->regs[27], &sc->regs.r27);
3533 __put_user(env->regs[28], &sc->regs.r28);
3534 __put_user(env->regs[29], &sc->regs.r29);
3535 __put_user(env->regs[30], &sc->regs.r30);
3536 __put_user(env->regs[31], &sc->regs.r31);
3537 __put_user(env->sregs[SR_PC], &sc->regs.pc);
3538}
3539
Andreas Färber05390242012-02-25 03:37:53 +01003540static void restore_sigcontext(struct target_sigcontext *sc, CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003541{
3542 __get_user(env->regs[0], &sc->regs.r0);
3543 __get_user(env->regs[1], &sc->regs.r1);
3544 __get_user(env->regs[2], &sc->regs.r2);
3545 __get_user(env->regs[3], &sc->regs.r3);
3546 __get_user(env->regs[4], &sc->regs.r4);
3547 __get_user(env->regs[5], &sc->regs.r5);
3548 __get_user(env->regs[6], &sc->regs.r6);
3549 __get_user(env->regs[7], &sc->regs.r7);
3550 __get_user(env->regs[8], &sc->regs.r8);
3551 __get_user(env->regs[9], &sc->regs.r9);
3552 __get_user(env->regs[10], &sc->regs.r10);
3553 __get_user(env->regs[11], &sc->regs.r11);
3554 __get_user(env->regs[12], &sc->regs.r12);
3555 __get_user(env->regs[13], &sc->regs.r13);
3556 __get_user(env->regs[14], &sc->regs.r14);
3557 __get_user(env->regs[15], &sc->regs.r15);
3558 __get_user(env->regs[16], &sc->regs.r16);
3559 __get_user(env->regs[17], &sc->regs.r17);
3560 __get_user(env->regs[18], &sc->regs.r18);
3561 __get_user(env->regs[19], &sc->regs.r19);
3562 __get_user(env->regs[20], &sc->regs.r20);
3563 __get_user(env->regs[21], &sc->regs.r21);
3564 __get_user(env->regs[22], &sc->regs.r22);
3565 __get_user(env->regs[23], &sc->regs.r23);
3566 __get_user(env->regs[24], &sc->regs.r24);
3567 __get_user(env->regs[25], &sc->regs.r25);
3568 __get_user(env->regs[26], &sc->regs.r26);
3569 __get_user(env->regs[27], &sc->regs.r27);
3570 __get_user(env->regs[28], &sc->regs.r28);
3571 __get_user(env->regs[29], &sc->regs.r29);
3572 __get_user(env->regs[30], &sc->regs.r30);
3573 __get_user(env->regs[31], &sc->regs.r31);
3574 __get_user(env->sregs[SR_PC], &sc->regs.pc);
3575}
3576
3577static abi_ulong get_sigframe(struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01003578 CPUMBState *env, int frame_size)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003579{
3580 abi_ulong sp = env->regs[1];
3581
Riku Voipiob545f632014-07-15 17:01:55 +03003582 if ((ka->sa_flags & TARGET_SA_ONSTACK) != 0 && !on_sig_stack(sp)) {
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003583 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
Riku Voipiob545f632014-07-15 17:01:55 +03003584 }
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003585
3586 return ((sp - frame_size) & -8UL);
3587}
3588
3589static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01003590 target_sigset_t *set, CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003591{
3592 struct target_signal_frame *frame;
3593 abi_ulong frame_addr;
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003594 int i;
3595
3596 frame_addr = get_sigframe(ka, env, sizeof *frame);
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01003597 trace_user_setup_frame(env, frame_addr);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003598 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
3599 goto badframe;
3600
3601 /* Save the mask. */
Riku Voipio1d8b5122014-04-23 10:26:05 +03003602 __put_user(set->sig[0], &frame->uc.tuc_mcontext.oldmask);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003603
3604 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
Riku Voipio0188fad2014-04-23 13:34:15 +03003605 __put_user(set->sig[i], &frame->extramask[i - 1]);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003606 }
3607
Richard Hendersonf711df62010-11-22 14:57:52 -08003608 setup_sigcontext(&frame->uc.tuc_mcontext, env);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003609
3610 /* Set up to return from userspace. If provided, use a stub
3611 already in userspace. */
3612 /* minus 8 is offset to cater for "rtsd r15,8" offset */
3613 if (ka->sa_flags & TARGET_SA_RESTORER) {
3614 env->regs[15] = ((unsigned long)ka->sa_restorer)-8;
3615 } else {
3616 uint32_t t;
3617 /* Note, these encodings are _big endian_! */
3618 /* addi r12, r0, __NR_sigreturn */
3619 t = 0x31800000UL | TARGET_NR_sigreturn;
Riku Voipio1d8b5122014-04-23 10:26:05 +03003620 __put_user(t, frame->tramp + 0);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003621 /* brki r14, 0x8 */
3622 t = 0xb9cc0008UL;
Riku Voipio1d8b5122014-04-23 10:26:05 +03003623 __put_user(t, frame->tramp + 1);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003624
3625 /* Return from sighandler will jump to the tramp.
3626 Negative 8 offset because return is rtsd r15, 8 */
Chen Gang166c97e2016-03-29 22:13:45 +08003627 env->regs[15] = frame_addr + offsetof(struct target_signal_frame, tramp)
3628 - 8;
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003629 }
3630
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003631 /* Set up registers for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003632 env->regs[1] = frame_addr;
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003633 /* Signal handler args: */
3634 env->regs[5] = sig; /* Arg 0: signum */
Edgar E. Iglesias187b4e02010-07-15 15:32:51 +02003635 env->regs[6] = 0;
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003636 /* arg 1: sigcontext */
3637 env->regs[7] = frame_addr += offsetof(typeof(*frame), uc);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003638
3639 /* Offset of 4 to handle microblaze rtid r14, 0 */
3640 env->sregs[SR_PC] = (unsigned long)ka->_sa_handler;
3641
3642 unlock_user_struct(frame, frame_addr, 1);
3643 return;
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003644badframe:
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003645 force_sig(TARGET_SIGSEGV);
3646}
3647
3648static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05003649 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01003650 target_sigset_t *set, CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003651{
3652 fprintf(stderr, "Microblaze setup_rt_frame: not implemented\n");
3653}
3654
Andreas Färber05390242012-02-25 03:37:53 +01003655long do_sigreturn(CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003656{
3657 struct target_signal_frame *frame;
3658 abi_ulong frame_addr;
Anthony Liguoric227f092009-10-01 16:12:16 -05003659 target_sigset_t target_set;
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003660 sigset_t set;
3661 int i;
3662
3663 frame_addr = env->regs[R_SP];
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01003664 trace_user_do_sigreturn(env, frame_addr);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003665 /* Make sure the guest isn't playing games. */
3666 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 1))
3667 goto badframe;
3668
3669 /* Restore blocked signals */
Riku Voipiof5f601a2014-04-23 13:00:17 +03003670 __get_user(target_set.sig[0], &frame->uc.tuc_mcontext.oldmask);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003671 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003672 __get_user(target_set.sig[i], &frame->extramask[i - 1]);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003673 }
3674 target_to_host_sigset_internal(&set, &target_set);
Peter Maydell9eede5b2016-05-27 15:51:46 +01003675 set_sigmask(&set);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003676
Richard Hendersonf711df62010-11-22 14:57:52 -08003677 restore_sigcontext(&frame->uc.tuc_mcontext, env);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003678 /* We got here through a sigreturn syscall, our path back is via an
3679 rtb insn so setup r14 for that. */
3680 env->regs[14] = env->sregs[SR_PC];
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003681
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003682 unlock_user_struct(frame, frame_addr, 0);
Timothy E Baldwin4134ecf2016-05-12 18:47:44 +01003683 return -TARGET_QEMU_ESIGRETURN;
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003684badframe:
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003685 force_sig(TARGET_SIGSEGV);
3686}
3687
Andreas Färber05390242012-02-25 03:37:53 +01003688long do_rt_sigreturn(CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003689{
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01003690 trace_user_do_rt_sigreturn(env, 0);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003691 fprintf(stderr, "Microblaze do_rt_sigreturn: not implemented\n");
3692 return -TARGET_ENOSYS;
3693}
3694
edgar_iglb6d3abd2008-02-28 11:29:27 +00003695#elif defined(TARGET_CRIS)
3696
3697struct target_sigcontext {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003698 struct target_pt_regs regs; /* needs to be first */
3699 uint32_t oldmask;
3700 uint32_t usp; /* usp before stacking this gunk on it */
edgar_iglb6d3abd2008-02-28 11:29:27 +00003701};
3702
3703/* Signal frames. */
3704struct target_signal_frame {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003705 struct target_sigcontext sc;
3706 uint32_t extramask[TARGET_NSIG_WORDS - 1];
3707 uint16_t retcode[4]; /* Trampoline code. */
edgar_iglb6d3abd2008-02-28 11:29:27 +00003708};
3709
3710struct rt_signal_frame {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003711 siginfo_t *pinfo;
3712 void *puc;
3713 siginfo_t info;
3714 struct ucontext uc;
3715 uint16_t retcode[4]; /* Trampoline code. */
edgar_iglb6d3abd2008-02-28 11:29:27 +00003716};
3717
Andreas Färber05390242012-02-25 03:37:53 +01003718static void setup_sigcontext(struct target_sigcontext *sc, CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003719{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003720 __put_user(env->regs[0], &sc->regs.r0);
3721 __put_user(env->regs[1], &sc->regs.r1);
3722 __put_user(env->regs[2], &sc->regs.r2);
3723 __put_user(env->regs[3], &sc->regs.r3);
3724 __put_user(env->regs[4], &sc->regs.r4);
3725 __put_user(env->regs[5], &sc->regs.r5);
3726 __put_user(env->regs[6], &sc->regs.r6);
3727 __put_user(env->regs[7], &sc->regs.r7);
3728 __put_user(env->regs[8], &sc->regs.r8);
3729 __put_user(env->regs[9], &sc->regs.r9);
3730 __put_user(env->regs[10], &sc->regs.r10);
3731 __put_user(env->regs[11], &sc->regs.r11);
3732 __put_user(env->regs[12], &sc->regs.r12);
3733 __put_user(env->regs[13], &sc->regs.r13);
3734 __put_user(env->regs[14], &sc->usp);
3735 __put_user(env->regs[15], &sc->regs.acr);
3736 __put_user(env->pregs[PR_MOF], &sc->regs.mof);
3737 __put_user(env->pregs[PR_SRP], &sc->regs.srp);
3738 __put_user(env->pc, &sc->regs.erp);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003739}
edgar_igl9664d922008-03-03 22:23:53 +00003740
Andreas Färber05390242012-02-25 03:37:53 +01003741static void restore_sigcontext(struct target_sigcontext *sc, CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003742{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003743 __get_user(env->regs[0], &sc->regs.r0);
3744 __get_user(env->regs[1], &sc->regs.r1);
3745 __get_user(env->regs[2], &sc->regs.r2);
3746 __get_user(env->regs[3], &sc->regs.r3);
3747 __get_user(env->regs[4], &sc->regs.r4);
3748 __get_user(env->regs[5], &sc->regs.r5);
3749 __get_user(env->regs[6], &sc->regs.r6);
3750 __get_user(env->regs[7], &sc->regs.r7);
3751 __get_user(env->regs[8], &sc->regs.r8);
3752 __get_user(env->regs[9], &sc->regs.r9);
3753 __get_user(env->regs[10], &sc->regs.r10);
3754 __get_user(env->regs[11], &sc->regs.r11);
3755 __get_user(env->regs[12], &sc->regs.r12);
3756 __get_user(env->regs[13], &sc->regs.r13);
3757 __get_user(env->regs[14], &sc->usp);
3758 __get_user(env->regs[15], &sc->regs.acr);
3759 __get_user(env->pregs[PR_MOF], &sc->regs.mof);
3760 __get_user(env->pregs[PR_SRP], &sc->regs.srp);
3761 __get_user(env->pc, &sc->regs.erp);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003762}
3763
Andreas Färber05390242012-02-25 03:37:53 +01003764static abi_ulong get_sigframe(CPUCRISState *env, int framesize)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003765{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003766 abi_ulong sp;
3767 /* Align the stack downwards to 4. */
3768 sp = (env->regs[R_SP] & ~3);
3769 return sp - framesize;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003770}
3771
pbrook624f7972008-05-31 16:11:38 +00003772static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01003773 target_sigset_t *set, CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003774{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003775 struct target_signal_frame *frame;
3776 abi_ulong frame_addr;
3777 int i;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003778
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003779 frame_addr = get_sigframe(env, sizeof *frame);
3780 trace_user_setup_frame(env, frame_addr);
3781 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
3782 goto badframe;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003783
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003784 /*
3785 * The CRIS signal return trampoline. A real linux/CRIS kernel doesn't
3786 * use this trampoline anymore but it sets it up for GDB.
3787 * In QEMU, using the trampoline simplifies things a bit so we use it.
3788 *
3789 * This is movu.w __NR_sigreturn, r9; break 13;
3790 */
Riku Voipio1d8b5122014-04-23 10:26:05 +03003791 __put_user(0x9c5f, frame->retcode+0);
3792 __put_user(TARGET_NR_sigreturn,
3793 frame->retcode + 1);
3794 __put_user(0xe93d, frame->retcode + 2);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003795
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003796 /* Save the mask. */
Riku Voipio1d8b5122014-04-23 10:26:05 +03003797 __put_user(set->sig[0], &frame->sc.oldmask);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003798
Riku Voipio0188fad2014-04-23 13:34:15 +03003799 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
3800 __put_user(set->sig[i], &frame->extramask[i - 1]);
3801 }
edgar_iglb6d3abd2008-02-28 11:29:27 +00003802
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003803 setup_sigcontext(&frame->sc, env);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003804
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003805 /* Move the stack and setup the arguments for the handler. */
3806 env->regs[R_SP] = frame_addr;
3807 env->regs[10] = sig;
3808 env->pc = (unsigned long) ka->_sa_handler;
3809 /* Link SRP so the guest returns through the trampoline. */
3810 env->pregs[PR_SRP] = frame_addr + offsetof(typeof(*frame), retcode);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003811
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003812 unlock_user_struct(frame, frame_addr, 1);
3813 return;
3814badframe:
3815 force_sig(TARGET_SIGSEGV);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003816}
3817
pbrook624f7972008-05-31 16:11:38 +00003818static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05003819 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01003820 target_sigset_t *set, CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003821{
3822 fprintf(stderr, "CRIS setup_rt_frame: not implemented\n");
3823}
3824
Andreas Färber05390242012-02-25 03:37:53 +01003825long do_sigreturn(CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003826{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003827 struct target_signal_frame *frame;
3828 abi_ulong frame_addr;
3829 target_sigset_t target_set;
3830 sigset_t set;
3831 int i;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003832
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003833 frame_addr = env->regs[R_SP];
3834 trace_user_do_sigreturn(env, frame_addr);
3835 /* Make sure the guest isn't playing games. */
3836 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 1)) {
3837 goto badframe;
3838 }
edgar_iglb6d3abd2008-02-28 11:29:27 +00003839
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003840 /* Restore blocked signals */
Riku Voipiof5f601a2014-04-23 13:00:17 +03003841 __get_user(target_set.sig[0], &frame->sc.oldmask);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003842 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
Riku Voipiof5f601a2014-04-23 13:00:17 +03003843 __get_user(target_set.sig[i], &frame->extramask[i - 1]);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003844 }
3845 target_to_host_sigset_internal(&set, &target_set);
Peter Maydell9eede5b2016-05-27 15:51:46 +01003846 set_sigmask(&set);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003847
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003848 restore_sigcontext(&frame->sc, env);
3849 unlock_user_struct(frame, frame_addr, 0);
Timothy E Baldwin62050862016-05-12 18:47:41 +01003850 return -TARGET_QEMU_ESIGRETURN;
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003851badframe:
3852 force_sig(TARGET_SIGSEGV);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003853}
3854
Andreas Färber05390242012-02-25 03:37:53 +01003855long do_rt_sigreturn(CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003856{
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01003857 trace_user_do_rt_sigreturn(env, 0);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003858 fprintf(stderr, "CRIS do_rt_sigreturn: not implemented\n");
3859 return -TARGET_ENOSYS;
3860}
thsc3b5bc82007-12-02 06:31:25 +00003861
Jia Liud9627832012-07-20 15:50:52 +08003862#elif defined(TARGET_OPENRISC)
3863
3864struct target_sigcontext {
3865 struct target_pt_regs regs;
3866 abi_ulong oldmask;
3867 abi_ulong usp;
3868};
3869
3870struct target_ucontext {
3871 abi_ulong tuc_flags;
3872 abi_ulong tuc_link;
3873 target_stack_t tuc_stack;
3874 struct target_sigcontext tuc_mcontext;
3875 target_sigset_t tuc_sigmask; /* mask last for extensibility */
3876};
3877
3878struct target_rt_sigframe {
3879 abi_ulong pinfo;
3880 uint64_t puc;
3881 struct target_siginfo info;
3882 struct target_sigcontext sc;
3883 struct target_ucontext uc;
3884 unsigned char retcode[16]; /* trampoline code */
3885};
3886
3887/* This is the asm-generic/ucontext.h version */
3888#if 0
3889static int restore_sigcontext(CPUOpenRISCState *regs,
3890 struct target_sigcontext *sc)
3891{
3892 unsigned int err = 0;
3893 unsigned long old_usp;
3894
3895 /* Alwys make any pending restarted system call return -EINTR */
3896 current_thread_info()->restart_block.fn = do_no_restart_syscall;
3897
3898 /* restore the regs from &sc->regs (same as sc, since regs is first)
3899 * (sc is already checked for VERIFY_READ since the sigframe was
3900 * checked in sys_sigreturn previously)
3901 */
3902
3903 if (copy_from_user(regs, &sc, sizeof(struct target_pt_regs))) {
3904 goto badframe;
3905 }
3906
3907 /* make sure the U-flag is set so user-mode cannot fool us */
3908
3909 regs->sr &= ~SR_SM;
3910
3911 /* restore the old USP as it was before we stacked the sc etc.
3912 * (we cannot just pop the sigcontext since we aligned the sp and
3913 * stuff after pushing it)
3914 */
3915
Riku Voipio1d8b5122014-04-23 10:26:05 +03003916 __get_user(old_usp, &sc->usp);
Jia Liud9627832012-07-20 15:50:52 +08003917 phx_signal("old_usp 0x%lx", old_usp);
3918
3919 __PHX__ REALLY /* ??? */
3920 wrusp(old_usp);
3921 regs->gpr[1] = old_usp;
3922
3923 /* TODO: the other ports use regs->orig_XX to disable syscall checks
3924 * after this completes, but we don't use that mechanism. maybe we can
3925 * use it now ?
3926 */
3927
3928 return err;
3929
3930badframe:
3931 return 1;
3932}
3933#endif
3934
3935/* Set up a signal frame. */
3936
Riku Voipio41ecc722014-04-23 11:01:00 +03003937static void setup_sigcontext(struct target_sigcontext *sc,
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003938 CPUOpenRISCState *regs,
3939 unsigned long mask)
Jia Liud9627832012-07-20 15:50:52 +08003940{
Jia Liud9627832012-07-20 15:50:52 +08003941 unsigned long usp = regs->gpr[1];
3942
3943 /* copy the regs. they are first in sc so we can use sc directly */
3944
Riku Voipio1d8b5122014-04-23 10:26:05 +03003945 /*copy_to_user(&sc, regs, sizeof(struct target_pt_regs));*/
Jia Liud9627832012-07-20 15:50:52 +08003946
3947 /* Set the frametype to CRIS_FRAME_NORMAL for the execution of
3948 the signal handler. The frametype will be restored to its previous
3949 value in restore_sigcontext. */
3950 /*regs->frametype = CRIS_FRAME_NORMAL;*/
3951
3952 /* then some other stuff */
Riku Voipio1d8b5122014-04-23 10:26:05 +03003953 __put_user(mask, &sc->oldmask);
Riku Voipio41ecc722014-04-23 11:01:00 +03003954 __put_user(usp, &sc->usp);
Jia Liud9627832012-07-20 15:50:52 +08003955}
3956
3957static inline unsigned long align_sigframe(unsigned long sp)
3958{
3959 unsigned long i;
3960 i = sp & ~3UL;
3961 return i;
3962}
3963
3964static inline abi_ulong get_sigframe(struct target_sigaction *ka,
3965 CPUOpenRISCState *regs,
3966 size_t frame_size)
3967{
3968 unsigned long sp = regs->gpr[1];
3969 int onsigstack = on_sig_stack(sp);
3970
3971 /* redzone */
3972 /* This is the X/Open sanctioned signal stack switching. */
Riku Voipiob545f632014-07-15 17:01:55 +03003973 if ((ka->sa_flags & TARGET_SA_ONSTACK) != 0 && !onsigstack) {
Jia Liud9627832012-07-20 15:50:52 +08003974 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
3975 }
3976
3977 sp = align_sigframe(sp - frame_size);
3978
3979 /*
3980 * If we are on the alternate signal stack and would overflow it, don't.
3981 * Return an always-bogus address instead so we will die with SIGSEGV.
3982 */
3983
3984 if (onsigstack && !likely(on_sig_stack(sp))) {
3985 return -1L;
3986 }
3987
3988 return sp;
3989}
3990
Jia Liud9627832012-07-20 15:50:52 +08003991static void setup_rt_frame(int sig, struct target_sigaction *ka,
3992 target_siginfo_t *info,
3993 target_sigset_t *set, CPUOpenRISCState *env)
3994{
3995 int err = 0;
3996 abi_ulong frame_addr;
3997 unsigned long return_ip;
3998 struct target_rt_sigframe *frame;
3999 abi_ulong info_addr, uc_addr;
4000
Jia Liud9627832012-07-20 15:50:52 +08004001 frame_addr = get_sigframe(ka, env, sizeof(*frame));
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01004002 trace_user_setup_rt_frame(env, frame_addr);
Jia Liud9627832012-07-20 15:50:52 +08004003 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
4004 goto give_sigsegv;
4005 }
4006
4007 info_addr = frame_addr + offsetof(struct target_rt_sigframe, info);
Riku Voipio1d8b5122014-04-23 10:26:05 +03004008 __put_user(info_addr, &frame->pinfo);
Jia Liud9627832012-07-20 15:50:52 +08004009 uc_addr = frame_addr + offsetof(struct target_rt_sigframe, uc);
Riku Voipio1d8b5122014-04-23 10:26:05 +03004010 __put_user(uc_addr, &frame->puc);
Jia Liud9627832012-07-20 15:50:52 +08004011
4012 if (ka->sa_flags & SA_SIGINFO) {
Peter Maydellf6c7a052015-01-08 12:19:48 +00004013 tswap_siginfo(&frame->info, info);
Jia Liud9627832012-07-20 15:50:52 +08004014 }
4015
4016 /*err |= __clear_user(&frame->uc, offsetof(struct ucontext, uc_mcontext));*/
Riku Voipio1d8b5122014-04-23 10:26:05 +03004017 __put_user(0, &frame->uc.tuc_flags);
4018 __put_user(0, &frame->uc.tuc_link);
4019 __put_user(target_sigaltstack_used.ss_sp,
4020 &frame->uc.tuc_stack.ss_sp);
4021 __put_user(sas_ss_flags(env->gpr[1]), &frame->uc.tuc_stack.ss_flags);
4022 __put_user(target_sigaltstack_used.ss_size,
4023 &frame->uc.tuc_stack.ss_size);
Riku Voipio41ecc722014-04-23 11:01:00 +03004024 setup_sigcontext(&frame->sc, env, set->sig[0]);
Jia Liud9627832012-07-20 15:50:52 +08004025
4026 /*err |= copy_to_user(frame->uc.tuc_sigmask, set, sizeof(*set));*/
4027
Jia Liud9627832012-07-20 15:50:52 +08004028 /* trampoline - the desired return ip is the retcode itself */
4029 return_ip = (unsigned long)&frame->retcode;
4030 /* This is l.ori r11,r0,__NR_sigreturn, l.sys 1 */
Riku Voipio1d8b5122014-04-23 10:26:05 +03004031 __put_user(0xa960, (short *)(frame->retcode + 0));
4032 __put_user(TARGET_NR_rt_sigreturn, (short *)(frame->retcode + 2));
4033 __put_user(0x20000001, (unsigned long *)(frame->retcode + 4));
4034 __put_user(0x15000000, (unsigned long *)(frame->retcode + 8));
Jia Liud9627832012-07-20 15:50:52 +08004035
4036 if (err) {
4037 goto give_sigsegv;
4038 }
4039
4040 /* TODO what is the current->exec_domain stuff and invmap ? */
4041
4042 /* Set up registers for signal handler */
4043 env->pc = (unsigned long)ka->_sa_handler; /* what we enter NOW */
4044 env->gpr[9] = (unsigned long)return_ip; /* what we enter LATER */
4045 env->gpr[3] = (unsigned long)sig; /* arg 1: signo */
4046 env->gpr[4] = (unsigned long)&frame->info; /* arg 2: (siginfo_t*) */
4047 env->gpr[5] = (unsigned long)&frame->uc; /* arg 3: ucontext */
4048
4049 /* actually move the usp to reflect the stacked frame */
4050 env->gpr[1] = (unsigned long)frame;
4051
4052 return;
4053
4054give_sigsegv:
4055 unlock_user_struct(frame, frame_addr, 1);
4056 if (sig == TARGET_SIGSEGV) {
4057 ka->_sa_handler = TARGET_SIG_DFL;
4058 }
4059 force_sig(TARGET_SIGSEGV);
4060}
4061
4062long do_sigreturn(CPUOpenRISCState *env)
4063{
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01004064 trace_user_do_sigreturn(env, 0);
4065 fprintf(stderr, "do_sigreturn: not implemented\n");
Jia Liud9627832012-07-20 15:50:52 +08004066 return -TARGET_ENOSYS;
4067}
4068
4069long do_rt_sigreturn(CPUOpenRISCState *env)
4070{
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01004071 trace_user_do_rt_sigreturn(env, 0);
4072 fprintf(stderr, "do_rt_sigreturn: not implemented\n");
Jia Liud9627832012-07-20 15:50:52 +08004073 return -TARGET_ENOSYS;
4074}
4075/* TARGET_OPENRISC */
4076
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004077#elif defined(TARGET_S390X)
4078
4079#define __NUM_GPRS 16
4080#define __NUM_FPRS 16
4081#define __NUM_ACRS 16
4082
4083#define S390_SYSCALL_SIZE 2
4084#define __SIGNAL_FRAMESIZE 160 /* FIXME: 31-bit mode -> 96 */
4085
4086#define _SIGCONTEXT_NSIG 64
4087#define _SIGCONTEXT_NSIG_BPW 64 /* FIXME: 31-bit mode -> 32 */
4088#define _SIGCONTEXT_NSIG_WORDS (_SIGCONTEXT_NSIG / _SIGCONTEXT_NSIG_BPW)
4089#define _SIGMASK_COPY_SIZE (sizeof(unsigned long)*_SIGCONTEXT_NSIG_WORDS)
4090#define PSW_ADDR_AMODE 0x0000000000000000UL /* 0x80000000UL for 31-bit */
4091#define S390_SYSCALL_OPCODE ((uint16_t)0x0a00)
4092
4093typedef struct {
4094 target_psw_t psw;
4095 target_ulong gprs[__NUM_GPRS];
4096 unsigned int acrs[__NUM_ACRS];
4097} target_s390_regs_common;
4098
4099typedef struct {
4100 unsigned int fpc;
4101 double fprs[__NUM_FPRS];
4102} target_s390_fp_regs;
4103
4104typedef struct {
4105 target_s390_regs_common regs;
4106 target_s390_fp_regs fpregs;
4107} target_sigregs;
4108
4109struct target_sigcontext {
4110 target_ulong oldmask[_SIGCONTEXT_NSIG_WORDS];
4111 target_sigregs *sregs;
4112};
4113
4114typedef struct {
4115 uint8_t callee_used_stack[__SIGNAL_FRAMESIZE];
4116 struct target_sigcontext sc;
4117 target_sigregs sregs;
4118 int signo;
4119 uint8_t retcode[S390_SYSCALL_SIZE];
4120} sigframe;
4121
4122struct target_ucontext {
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004123 target_ulong tuc_flags;
4124 struct target_ucontext *tuc_link;
4125 target_stack_t tuc_stack;
4126 target_sigregs tuc_mcontext;
4127 target_sigset_t tuc_sigmask; /* mask last for extensibility */
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004128};
4129
4130typedef struct {
4131 uint8_t callee_used_stack[__SIGNAL_FRAMESIZE];
4132 uint8_t retcode[S390_SYSCALL_SIZE];
4133 struct target_siginfo info;
4134 struct target_ucontext uc;
4135} rt_sigframe;
4136
4137static inline abi_ulong
Andreas Färber05390242012-02-25 03:37:53 +01004138get_sigframe(struct target_sigaction *ka, CPUS390XState *env, size_t frame_size)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004139{
4140 abi_ulong sp;
4141
4142 /* Default to using normal stack */
4143 sp = env->regs[15];
4144
4145 /* This is the X/Open sanctioned signal stack switching. */
4146 if (ka->sa_flags & TARGET_SA_ONSTACK) {
4147 if (!sas_ss_flags(sp)) {
4148 sp = target_sigaltstack_used.ss_sp +
4149 target_sigaltstack_used.ss_size;
4150 }
4151 }
4152
4153 /* This is the legacy signal stack switching. */
4154 else if (/* FIXME !user_mode(regs) */ 0 &&
4155 !(ka->sa_flags & TARGET_SA_RESTORER) &&
4156 ka->sa_restorer) {
4157 sp = (abi_ulong) ka->sa_restorer;
4158 }
4159
4160 return (sp - frame_size) & -8ul;
4161}
4162
Andreas Färber05390242012-02-25 03:37:53 +01004163static void save_sigregs(CPUS390XState *env, target_sigregs *sregs)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004164{
4165 int i;
4166 //save_access_regs(current->thread.acrs); FIXME
4167
4168 /* Copy a 'clean' PSW mask to the user to avoid leaking
4169 information about whether PER is currently on. */
4170 __put_user(env->psw.mask, &sregs->regs.psw.mask);
4171 __put_user(env->psw.addr, &sregs->regs.psw.addr);
4172 for (i = 0; i < 16; i++) {
4173 __put_user(env->regs[i], &sregs->regs.gprs[i]);
4174 }
4175 for (i = 0; i < 16; i++) {
4176 __put_user(env->aregs[i], &sregs->regs.acrs[i]);
4177 }
4178 /*
4179 * We have to store the fp registers to current->thread.fp_regs
4180 * to merge them with the emulated registers.
4181 */
4182 //save_fp_regs(&current->thread.fp_regs); FIXME
4183 for (i = 0; i < 16; i++) {
Eric Farmanc498d8e2015-05-07 14:35:44 -04004184 __put_user(get_freg(env, i)->ll, &sregs->fpregs.fprs[i]);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004185 }
4186}
4187
4188static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01004189 target_sigset_t *set, CPUS390XState *env)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004190{
4191 sigframe *frame;
4192 abi_ulong frame_addr;
4193
4194 frame_addr = get_sigframe(ka, env, sizeof(*frame));
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01004195 trace_user_setup_frame(env, frame_addr);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004196 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01004197 goto give_sigsegv;
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004198 }
4199
Riku Voipio0188fad2014-04-23 13:34:15 +03004200 __put_user(set->sig[0], &frame->sc.oldmask[0]);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004201
4202 save_sigregs(env, &frame->sregs);
4203
4204 __put_user((abi_ulong)(unsigned long)&frame->sregs,
4205 (abi_ulong *)&frame->sc.sregs);
4206
4207 /* Set up to return from userspace. If provided, use a stub
4208 already in userspace. */
4209 if (ka->sa_flags & TARGET_SA_RESTORER) {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01004210 env->regs[14] = (unsigned long)
4211 ka->sa_restorer | PSW_ADDR_AMODE;
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004212 } else {
Chen Gang5b1d59d2016-05-24 14:54:32 +03004213 env->regs[14] = (frame_addr + offsetof(sigframe, retcode))
4214 | PSW_ADDR_AMODE;
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01004215 __put_user(S390_SYSCALL_OPCODE | TARGET_NR_sigreturn,
4216 (uint16_t *)(frame->retcode));
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004217 }
4218
4219 /* Set up backchain. */
Riku Voipio0188fad2014-04-23 13:34:15 +03004220 __put_user(env->regs[15], (abi_ulong *) frame);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004221
4222 /* Set up registers for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02004223 env->regs[15] = frame_addr;
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004224 env->psw.addr = (target_ulong) ka->_sa_handler | PSW_ADDR_AMODE;
4225
4226 env->regs[2] = sig; //map_signal(sig);
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02004227 env->regs[3] = frame_addr += offsetof(typeof(*frame), sc);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004228
4229 /* We forgot to include these in the sigcontext.
4230 To avoid breaking binary compatibility, they are passed as args. */
4231 env->regs[4] = 0; // FIXME: no clue... current->thread.trap_no;
4232 env->regs[5] = 0; // FIXME: no clue... current->thread.prot_addr;
4233
4234 /* Place signal number on stack to allow backtrace from handler. */
Riku Voipio0188fad2014-04-23 13:34:15 +03004235 __put_user(env->regs[2], (int *) &frame->signo);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004236 unlock_user_struct(frame, frame_addr, 1);
4237 return;
4238
4239give_sigsegv:
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004240 force_sig(TARGET_SIGSEGV);
4241}
4242
4243static void setup_rt_frame(int sig, struct target_sigaction *ka,
4244 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01004245 target_sigset_t *set, CPUS390XState *env)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004246{
4247 int i;
4248 rt_sigframe *frame;
4249 abi_ulong frame_addr;
4250
4251 frame_addr = get_sigframe(ka, env, sizeof *frame);
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01004252 trace_user_setup_rt_frame(env, frame_addr);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004253 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
4254 goto give_sigsegv;
4255 }
4256
Peter Maydellf6c7a052015-01-08 12:19:48 +00004257 tswap_siginfo(&frame->info, info);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004258
4259 /* Create the ucontext. */
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004260 __put_user(0, &frame->uc.tuc_flags);
4261 __put_user((abi_ulong)0, (abi_ulong *)&frame->uc.tuc_link);
4262 __put_user(target_sigaltstack_used.ss_sp, &frame->uc.tuc_stack.ss_sp);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004263 __put_user(sas_ss_flags(get_sp_from_cpustate(env)),
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01004264 &frame->uc.tuc_stack.ss_flags);
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004265 __put_user(target_sigaltstack_used.ss_size, &frame->uc.tuc_stack.ss_size);
4266 save_sigregs(env, &frame->uc.tuc_mcontext);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004267 for (i = 0; i < TARGET_NSIG_WORDS; i++) {
4268 __put_user((abi_ulong)set->sig[i],
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01004269 (abi_ulong *)&frame->uc.tuc_sigmask.sig[i]);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004270 }
4271
4272 /* Set up to return from userspace. If provided, use a stub
4273 already in userspace. */
4274 if (ka->sa_flags & TARGET_SA_RESTORER) {
4275 env->regs[14] = (unsigned long) ka->sa_restorer | PSW_ADDR_AMODE;
4276 } else {
4277 env->regs[14] = (unsigned long) frame->retcode | PSW_ADDR_AMODE;
Riku Voipio0188fad2014-04-23 13:34:15 +03004278 __put_user(S390_SYSCALL_OPCODE | TARGET_NR_rt_sigreturn,
4279 (uint16_t *)(frame->retcode));
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004280 }
4281
4282 /* Set up backchain. */
Riku Voipio0188fad2014-04-23 13:34:15 +03004283 __put_user(env->regs[15], (abi_ulong *) frame);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004284
4285 /* Set up registers for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02004286 env->regs[15] = frame_addr;
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004287 env->psw.addr = (target_ulong) ka->_sa_handler | PSW_ADDR_AMODE;
4288
4289 env->regs[2] = sig; //map_signal(sig);
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02004290 env->regs[3] = frame_addr + offsetof(typeof(*frame), info);
4291 env->regs[4] = frame_addr + offsetof(typeof(*frame), uc);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004292 return;
4293
4294give_sigsegv:
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004295 force_sig(TARGET_SIGSEGV);
4296}
4297
4298static int
Andreas Färber05390242012-02-25 03:37:53 +01004299restore_sigregs(CPUS390XState *env, target_sigregs *sc)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004300{
4301 int err = 0;
4302 int i;
4303
4304 for (i = 0; i < 16; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03004305 __get_user(env->regs[i], &sc->regs.gprs[i]);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004306 }
4307
Riku Voipio1d8b5122014-04-23 10:26:05 +03004308 __get_user(env->psw.mask, &sc->regs.psw.mask);
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01004309 trace_user_s390x_restore_sigregs(env, (unsigned long long)sc->regs.psw.addr,
4310 (unsigned long long)env->psw.addr);
Riku Voipio1d8b5122014-04-23 10:26:05 +03004311 __get_user(env->psw.addr, &sc->regs.psw.addr);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004312 /* FIXME: 31-bit -> | PSW_ADDR_AMODE */
4313
4314 for (i = 0; i < 16; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03004315 __get_user(env->aregs[i], &sc->regs.acrs[i]);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004316 }
4317 for (i = 0; i < 16; i++) {
Eric Farmanc498d8e2015-05-07 14:35:44 -04004318 __get_user(get_freg(env, i)->ll, &sc->fpregs.fprs[i]);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004319 }
4320
4321 return err;
4322}
4323
Andreas Färber05390242012-02-25 03:37:53 +01004324long do_sigreturn(CPUS390XState *env)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004325{
4326 sigframe *frame;
4327 abi_ulong frame_addr = env->regs[15];
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004328 target_sigset_t target_set;
4329 sigset_t set;
4330
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01004331 trace_user_do_sigreturn(env, frame_addr);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004332 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
4333 goto badframe;
4334 }
Riku Voipiof5f601a2014-04-23 13:00:17 +03004335 __get_user(target_set.sig[0], &frame->sc.oldmask[0]);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004336
4337 target_to_host_sigset_internal(&set, &target_set);
Peter Maydell9eede5b2016-05-27 15:51:46 +01004338 set_sigmask(&set); /* ~_BLOCKABLE? */
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004339
4340 if (restore_sigregs(env, &frame->sregs)) {
4341 goto badframe;
4342 }
4343
4344 unlock_user_struct(frame, frame_addr, 0);
Timothy E Baldwin47405ab2016-05-12 18:47:40 +01004345 return -TARGET_QEMU_ESIGRETURN;
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004346
4347badframe:
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004348 force_sig(TARGET_SIGSEGV);
4349 return 0;
4350}
4351
Andreas Färber05390242012-02-25 03:37:53 +01004352long do_rt_sigreturn(CPUS390XState *env)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004353{
4354 rt_sigframe *frame;
4355 abi_ulong frame_addr = env->regs[15];
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004356 sigset_t set;
4357
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01004358 trace_user_do_rt_sigreturn(env, frame_addr);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004359 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
4360 goto badframe;
4361 }
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004362 target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004363
Peter Maydell9eede5b2016-05-27 15:51:46 +01004364 set_sigmask(&set); /* ~_BLOCKABLE? */
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004365
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004366 if (restore_sigregs(env, &frame->uc.tuc_mcontext)) {
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004367 goto badframe;
4368 }
4369
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004370 if (do_sigaltstack(frame_addr + offsetof(rt_sigframe, uc.tuc_stack), 0,
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004371 get_sp_from_cpustate(env)) == -EFAULT) {
4372 goto badframe;
4373 }
4374 unlock_user_struct(frame, frame_addr, 0);
Timothy E Baldwin47405ab2016-05-12 18:47:40 +01004375 return -TARGET_QEMU_ESIGRETURN;
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004376
4377badframe:
4378 unlock_user_struct(frame, frame_addr, 0);
4379 force_sig(TARGET_SIGSEGV);
4380 return 0;
4381}
4382
Tom Musta61e75fe2014-06-30 08:13:38 -05004383#elif defined(TARGET_PPC)
Nathan Froydbcd49332009-05-12 19:13:18 -07004384
4385/* Size of dummy stack frame allocated when calling signal handler.
4386 See arch/powerpc/include/asm/ptrace.h. */
4387#if defined(TARGET_PPC64)
4388#define SIGNAL_FRAMESIZE 128
4389#else
4390#define SIGNAL_FRAMESIZE 64
4391#endif
4392
Tom Musta61e75fe2014-06-30 08:13:38 -05004393/* See arch/powerpc/include/asm/ucontext.h. Only used for 32-bit PPC;
4394 on 64-bit PPC, sigcontext and mcontext are one and the same. */
4395struct target_mcontext {
4396 target_ulong mc_gregs[48];
4397 /* Includes fpscr. */
4398 uint64_t mc_fregs[33];
4399 target_ulong mc_pad[2];
4400 /* We need to handle Altivec and SPE at the same time, which no
4401 kernel needs to do. Fortunately, the kernel defines this bit to
4402 be Altivec-register-large all the time, rather than trying to
4403 twiddle it based on the specific platform. */
4404 union {
4405 /* SPE vector registers. One extra for SPEFSCR. */
4406 uint32_t spe[33];
4407 /* Altivec vector registers. The packing of VSCR and VRSAVE
4408 varies depending on whether we're PPC64 or not: PPC64 splits
4409 them apart; PPC32 stuffs them together. */
4410#if defined(TARGET_PPC64)
4411#define QEMU_NVRREG 34
4412#else
4413#define QEMU_NVRREG 33
4414#endif
4415 ppc_avr_t altivec[QEMU_NVRREG];
4416#undef QEMU_NVRREG
4417 } mc_vregs __attribute__((__aligned__(16)));
4418};
4419
Nathan Froydbcd49332009-05-12 19:13:18 -07004420/* See arch/powerpc/include/asm/sigcontext.h. */
4421struct target_sigcontext {
4422 target_ulong _unused[4];
4423 int32_t signal;
4424#if defined(TARGET_PPC64)
4425 int32_t pad0;
4426#endif
4427 target_ulong handler;
4428 target_ulong oldmask;
4429 target_ulong regs; /* struct pt_regs __user * */
Tom Musta61e75fe2014-06-30 08:13:38 -05004430#if defined(TARGET_PPC64)
4431 struct target_mcontext mcontext;
4432#endif
Nathan Froydbcd49332009-05-12 19:13:18 -07004433};
4434
4435/* Indices for target_mcontext.mc_gregs, below.
4436 See arch/powerpc/include/asm/ptrace.h for details. */
4437enum {
4438 TARGET_PT_R0 = 0,
4439 TARGET_PT_R1 = 1,
4440 TARGET_PT_R2 = 2,
4441 TARGET_PT_R3 = 3,
4442 TARGET_PT_R4 = 4,
4443 TARGET_PT_R5 = 5,
4444 TARGET_PT_R6 = 6,
4445 TARGET_PT_R7 = 7,
4446 TARGET_PT_R8 = 8,
4447 TARGET_PT_R9 = 9,
4448 TARGET_PT_R10 = 10,
4449 TARGET_PT_R11 = 11,
4450 TARGET_PT_R12 = 12,
4451 TARGET_PT_R13 = 13,
4452 TARGET_PT_R14 = 14,
4453 TARGET_PT_R15 = 15,
4454 TARGET_PT_R16 = 16,
4455 TARGET_PT_R17 = 17,
4456 TARGET_PT_R18 = 18,
4457 TARGET_PT_R19 = 19,
4458 TARGET_PT_R20 = 20,
4459 TARGET_PT_R21 = 21,
4460 TARGET_PT_R22 = 22,
4461 TARGET_PT_R23 = 23,
4462 TARGET_PT_R24 = 24,
4463 TARGET_PT_R25 = 25,
4464 TARGET_PT_R26 = 26,
4465 TARGET_PT_R27 = 27,
4466 TARGET_PT_R28 = 28,
4467 TARGET_PT_R29 = 29,
4468 TARGET_PT_R30 = 30,
4469 TARGET_PT_R31 = 31,
4470 TARGET_PT_NIP = 32,
4471 TARGET_PT_MSR = 33,
4472 TARGET_PT_ORIG_R3 = 34,
4473 TARGET_PT_CTR = 35,
4474 TARGET_PT_LNK = 36,
4475 TARGET_PT_XER = 37,
4476 TARGET_PT_CCR = 38,
4477 /* Yes, there are two registers with #39. One is 64-bit only. */
4478 TARGET_PT_MQ = 39,
4479 TARGET_PT_SOFTE = 39,
4480 TARGET_PT_TRAP = 40,
4481 TARGET_PT_DAR = 41,
4482 TARGET_PT_DSISR = 42,
4483 TARGET_PT_RESULT = 43,
4484 TARGET_PT_REGS_COUNT = 44
4485};
4486
Nathan Froydbcd49332009-05-12 19:13:18 -07004487
4488struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02004489 target_ulong tuc_flags;
4490 target_ulong tuc_link; /* struct ucontext __user * */
4491 struct target_sigaltstack tuc_stack;
Nathan Froydbcd49332009-05-12 19:13:18 -07004492#if !defined(TARGET_PPC64)
Aurelien Jarno60e99242010-03-29 02:12:51 +02004493 int32_t tuc_pad[7];
4494 target_ulong tuc_regs; /* struct mcontext __user *
Nathan Froydbcd49332009-05-12 19:13:18 -07004495 points to uc_mcontext field */
4496#endif
Aurelien Jarno60e99242010-03-29 02:12:51 +02004497 target_sigset_t tuc_sigmask;
Nathan Froydbcd49332009-05-12 19:13:18 -07004498#if defined(TARGET_PPC64)
Anthony Liguoric227f092009-10-01 16:12:16 -05004499 target_sigset_t unused[15]; /* Allow for uc_sigmask growth */
Tom Musta61e75fe2014-06-30 08:13:38 -05004500 struct target_sigcontext tuc_sigcontext;
Nathan Froydbcd49332009-05-12 19:13:18 -07004501#else
Aurelien Jarno60e99242010-03-29 02:12:51 +02004502 int32_t tuc_maskext[30];
4503 int32_t tuc_pad2[3];
4504 struct target_mcontext tuc_mcontext;
Nathan Froydbcd49332009-05-12 19:13:18 -07004505#endif
4506};
4507
4508/* See arch/powerpc/kernel/signal_32.c. */
4509struct target_sigframe {
4510 struct target_sigcontext sctx;
4511 struct target_mcontext mctx;
4512 int32_t abigap[56];
4513};
4514
Tom Musta61e75fe2014-06-30 08:13:38 -05004515#if defined(TARGET_PPC64)
4516
4517#define TARGET_TRAMP_SIZE 6
4518
4519struct target_rt_sigframe {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01004520 /* sys_rt_sigreturn requires the ucontext be the first field */
4521 struct target_ucontext uc;
4522 target_ulong _unused[2];
4523 uint32_t trampoline[TARGET_TRAMP_SIZE];
4524 target_ulong pinfo; /* struct siginfo __user * */
4525 target_ulong puc; /* void __user * */
4526 struct target_siginfo info;
4527 /* 64 bit ABI allows for 288 bytes below sp before decrementing it. */
4528 char abigap[288];
Tom Musta61e75fe2014-06-30 08:13:38 -05004529} __attribute__((aligned(16)));
4530
4531#else
4532
Nathan Froydbcd49332009-05-12 19:13:18 -07004533struct target_rt_sigframe {
4534 struct target_siginfo info;
4535 struct target_ucontext uc;
4536 int32_t abigap[56];
4537};
4538
Tom Musta61e75fe2014-06-30 08:13:38 -05004539#endif
4540
Tom Musta8d6ab332014-06-30 08:13:39 -05004541#if defined(TARGET_PPC64)
4542
4543struct target_func_ptr {
4544 target_ulong entry;
4545 target_ulong toc;
4546};
4547
4548#endif
4549
Nathan Froydbcd49332009-05-12 19:13:18 -07004550/* We use the mc_pad field for the signal return trampoline. */
4551#define tramp mc_pad
4552
4553/* See arch/powerpc/kernel/signal.c. */
4554static target_ulong get_sigframe(struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01004555 CPUPPCState *env,
Nathan Froydbcd49332009-05-12 19:13:18 -07004556 int frame_size)
4557{
4558 target_ulong oldsp, newsp;
4559
4560 oldsp = env->gpr[1];
4561
4562 if ((ka->sa_flags & TARGET_SA_ONSTACK) &&
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01004563 (sas_ss_flags(oldsp) == 0)) {
Nathan Froydbcd49332009-05-12 19:13:18 -07004564 oldsp = (target_sigaltstack_used.ss_sp
4565 + target_sigaltstack_used.ss_size);
4566 }
4567
4568 newsp = (oldsp - frame_size) & ~0xFUL;
4569
4570 return newsp;
4571}
4572
Tom Musta76781082014-06-30 08:13:37 -05004573static void save_user_regs(CPUPPCState *env, struct target_mcontext *frame)
Nathan Froydbcd49332009-05-12 19:13:18 -07004574{
4575 target_ulong msr = env->msr;
4576 int i;
4577 target_ulong ccr = 0;
4578
4579 /* In general, the kernel attempts to be intelligent about what it
4580 needs to save for Altivec/FP/SPE registers. We don't care that
4581 much, so we just go ahead and save everything. */
4582
4583 /* Save general registers. */
4584 for (i = 0; i < ARRAY_SIZE(env->gpr); i++) {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01004585 __put_user(env->gpr[i], &frame->mc_gregs[i]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004586 }
Riku Voipioc650c002014-04-23 13:53:45 +03004587 __put_user(env->nip, &frame->mc_gregs[TARGET_PT_NIP]);
4588 __put_user(env->ctr, &frame->mc_gregs[TARGET_PT_CTR]);
4589 __put_user(env->lr, &frame->mc_gregs[TARGET_PT_LNK]);
4590 __put_user(env->xer, &frame->mc_gregs[TARGET_PT_XER]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004591
4592 for (i = 0; i < ARRAY_SIZE(env->crf); i++) {
4593 ccr |= env->crf[i] << (32 - ((i + 1) * 4));
4594 }
Riku Voipioc650c002014-04-23 13:53:45 +03004595 __put_user(ccr, &frame->mc_gregs[TARGET_PT_CCR]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004596
4597 /* Save Altivec registers if necessary. */
4598 if (env->insns_flags & PPC_ALTIVEC) {
4599 for (i = 0; i < ARRAY_SIZE(env->avr); i++) {
Anthony Liguoric227f092009-10-01 16:12:16 -05004600 ppc_avr_t *avr = &env->avr[i];
4601 ppc_avr_t *vreg = &frame->mc_vregs.altivec[i];
Nathan Froydbcd49332009-05-12 19:13:18 -07004602
Riku Voipioc650c002014-04-23 13:53:45 +03004603 __put_user(avr->u64[0], &vreg->u64[0]);
4604 __put_user(avr->u64[1], &vreg->u64[1]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004605 }
4606 /* Set MSR_VR in the saved MSR value to indicate that
4607 frame->mc_vregs contains valid data. */
4608 msr |= MSR_VR;
Riku Voipioc650c002014-04-23 13:53:45 +03004609 __put_user((uint32_t)env->spr[SPR_VRSAVE],
4610 &frame->mc_vregs.altivec[32].u32[3]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004611 }
4612
4613 /* Save floating point registers. */
4614 if (env->insns_flags & PPC_FLOAT) {
4615 for (i = 0; i < ARRAY_SIZE(env->fpr); i++) {
Riku Voipioc650c002014-04-23 13:53:45 +03004616 __put_user(env->fpr[i], &frame->mc_fregs[i]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004617 }
Riku Voipioc650c002014-04-23 13:53:45 +03004618 __put_user((uint64_t) env->fpscr, &frame->mc_fregs[32]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004619 }
4620
4621 /* Save SPE registers. The kernel only saves the high half. */
4622 if (env->insns_flags & PPC_SPE) {
4623#if defined(TARGET_PPC64)
4624 for (i = 0; i < ARRAY_SIZE(env->gpr); i++) {
Riku Voipioc650c002014-04-23 13:53:45 +03004625 __put_user(env->gpr[i] >> 32, &frame->mc_vregs.spe[i]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004626 }
4627#else
4628 for (i = 0; i < ARRAY_SIZE(env->gprh); i++) {
Riku Voipioc650c002014-04-23 13:53:45 +03004629 __put_user(env->gprh[i], &frame->mc_vregs.spe[i]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004630 }
4631#endif
4632 /* Set MSR_SPE in the saved MSR value to indicate that
4633 frame->mc_vregs contains valid data. */
4634 msr |= MSR_SPE;
Riku Voipioc650c002014-04-23 13:53:45 +03004635 __put_user(env->spe_fscr, &frame->mc_vregs.spe[32]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004636 }
4637
4638 /* Store MSR. */
Riku Voipioc650c002014-04-23 13:53:45 +03004639 __put_user(msr, &frame->mc_gregs[TARGET_PT_MSR]);
Tom Musta76781082014-06-30 08:13:37 -05004640}
Nathan Froydbcd49332009-05-12 19:13:18 -07004641
Tom Musta76781082014-06-30 08:13:37 -05004642static void encode_trampoline(int sigret, uint32_t *tramp)
4643{
Nathan Froydbcd49332009-05-12 19:13:18 -07004644 /* Set up the sigreturn trampoline: li r0,sigret; sc. */
4645 if (sigret) {
Tom Musta76781082014-06-30 08:13:37 -05004646 __put_user(0x38000000 | sigret, &tramp[0]);
4647 __put_user(0x44000002, &tramp[1]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004648 }
Nathan Froydbcd49332009-05-12 19:13:18 -07004649}
4650
Riku Voipioc650c002014-04-23 13:53:45 +03004651static void restore_user_regs(CPUPPCState *env,
4652 struct target_mcontext *frame, int sig)
Nathan Froydbcd49332009-05-12 19:13:18 -07004653{
4654 target_ulong save_r2 = 0;
4655 target_ulong msr;
4656 target_ulong ccr;
4657
4658 int i;
4659
4660 if (!sig) {
4661 save_r2 = env->gpr[2];
4662 }
4663
4664 /* Restore general registers. */
4665 for (i = 0; i < ARRAY_SIZE(env->gpr); i++) {
Riku Voipioc650c002014-04-23 13:53:45 +03004666 __get_user(env->gpr[i], &frame->mc_gregs[i]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004667 }
Riku Voipioc650c002014-04-23 13:53:45 +03004668 __get_user(env->nip, &frame->mc_gregs[TARGET_PT_NIP]);
4669 __get_user(env->ctr, &frame->mc_gregs[TARGET_PT_CTR]);
4670 __get_user(env->lr, &frame->mc_gregs[TARGET_PT_LNK]);
4671 __get_user(env->xer, &frame->mc_gregs[TARGET_PT_XER]);
4672 __get_user(ccr, &frame->mc_gregs[TARGET_PT_CCR]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004673
4674 for (i = 0; i < ARRAY_SIZE(env->crf); i++) {
4675 env->crf[i] = (ccr >> (32 - ((i + 1) * 4))) & 0xf;
4676 }
4677
4678 if (!sig) {
4679 env->gpr[2] = save_r2;
4680 }
4681 /* Restore MSR. */
Riku Voipioc650c002014-04-23 13:53:45 +03004682 __get_user(msr, &frame->mc_gregs[TARGET_PT_MSR]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004683
4684 /* If doing signal return, restore the previous little-endian mode. */
4685 if (sig)
Laurent Vivier49e55cb2016-03-30 18:36:51 +02004686 env->msr = (env->msr & ~(1ull << MSR_LE)) | (msr & (1ull << MSR_LE));
Nathan Froydbcd49332009-05-12 19:13:18 -07004687
4688 /* Restore Altivec registers if necessary. */
4689 if (env->insns_flags & PPC_ALTIVEC) {
4690 for (i = 0; i < ARRAY_SIZE(env->avr); i++) {
Anthony Liguoric227f092009-10-01 16:12:16 -05004691 ppc_avr_t *avr = &env->avr[i];
4692 ppc_avr_t *vreg = &frame->mc_vregs.altivec[i];
Nathan Froydbcd49332009-05-12 19:13:18 -07004693
Riku Voipioc650c002014-04-23 13:53:45 +03004694 __get_user(avr->u64[0], &vreg->u64[0]);
4695 __get_user(avr->u64[1], &vreg->u64[1]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004696 }
4697 /* Set MSR_VEC in the saved MSR value to indicate that
4698 frame->mc_vregs contains valid data. */
Riku Voipioc650c002014-04-23 13:53:45 +03004699 __get_user(env->spr[SPR_VRSAVE],
4700 (target_ulong *)(&frame->mc_vregs.altivec[32].u32[3]));
Nathan Froydbcd49332009-05-12 19:13:18 -07004701 }
4702
4703 /* Restore floating point registers. */
4704 if (env->insns_flags & PPC_FLOAT) {
4705 uint64_t fpscr;
4706 for (i = 0; i < ARRAY_SIZE(env->fpr); i++) {
Riku Voipioc650c002014-04-23 13:53:45 +03004707 __get_user(env->fpr[i], &frame->mc_fregs[i]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004708 }
Riku Voipioc650c002014-04-23 13:53:45 +03004709 __get_user(fpscr, &frame->mc_fregs[32]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004710 env->fpscr = (uint32_t) fpscr;
4711 }
4712
4713 /* Save SPE registers. The kernel only saves the high half. */
4714 if (env->insns_flags & PPC_SPE) {
4715#if defined(TARGET_PPC64)
4716 for (i = 0; i < ARRAY_SIZE(env->gpr); i++) {
4717 uint32_t hi;
4718
Riku Voipioc650c002014-04-23 13:53:45 +03004719 __get_user(hi, &frame->mc_vregs.spe[i]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004720 env->gpr[i] = ((uint64_t)hi << 32) | ((uint32_t) env->gpr[i]);
4721 }
4722#else
4723 for (i = 0; i < ARRAY_SIZE(env->gprh); i++) {
Riku Voipioc650c002014-04-23 13:53:45 +03004724 __get_user(env->gprh[i], &frame->mc_vregs.spe[i]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004725 }
4726#endif
Riku Voipioc650c002014-04-23 13:53:45 +03004727 __get_user(env->spe_fscr, &frame->mc_vregs.spe[32]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004728 }
Nathan Froydbcd49332009-05-12 19:13:18 -07004729}
4730
4731static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01004732 target_sigset_t *set, CPUPPCState *env)
Nathan Froydbcd49332009-05-12 19:13:18 -07004733{
4734 struct target_sigframe *frame;
4735 struct target_sigcontext *sc;
4736 target_ulong frame_addr, newsp;
4737 int err = 0;
Tom Musta14585582014-06-30 08:13:42 -05004738#if defined(TARGET_PPC64)
4739 struct image_info *image = ((TaskState *)thread_cpu->opaque)->info;
4740#endif
Nathan Froydbcd49332009-05-12 19:13:18 -07004741
4742 frame_addr = get_sigframe(ka, env, sizeof(*frame));
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01004743 trace_user_setup_frame(env, frame_addr);
Nathan Froydbcd49332009-05-12 19:13:18 -07004744 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 1))
4745 goto sigsegv;
4746 sc = &frame->sctx;
4747
Riku Voipio1d8b5122014-04-23 10:26:05 +03004748 __put_user(ka->_sa_handler, &sc->handler);
4749 __put_user(set->sig[0], &sc->oldmask);
Tom Musta61e75fe2014-06-30 08:13:38 -05004750#if TARGET_ABI_BITS == 64
Riku Voipio1d8b5122014-04-23 10:26:05 +03004751 __put_user(set->sig[0] >> 32, &sc->_unused[3]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004752#else
Riku Voipio1d8b5122014-04-23 10:26:05 +03004753 __put_user(set->sig[1], &sc->_unused[3]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004754#endif
Riku Voipio1d8b5122014-04-23 10:26:05 +03004755 __put_user(h2g(&frame->mctx), &sc->regs);
4756 __put_user(sig, &sc->signal);
Nathan Froydbcd49332009-05-12 19:13:18 -07004757
4758 /* Save user regs. */
Tom Musta76781082014-06-30 08:13:37 -05004759 save_user_regs(env, &frame->mctx);
4760
4761 /* Construct the trampoline code on the stack. */
4762 encode_trampoline(TARGET_NR_sigreturn, (uint32_t *)&frame->mctx.tramp);
Nathan Froydbcd49332009-05-12 19:13:18 -07004763
4764 /* The kernel checks for the presence of a VDSO here. We don't
4765 emulate a vdso, so use a sigreturn system call. */
4766 env->lr = (target_ulong) h2g(frame->mctx.tramp);
4767
4768 /* Turn off all fp exceptions. */
4769 env->fpscr = 0;
4770
4771 /* Create a stack frame for the caller of the handler. */
4772 newsp = frame_addr - SIGNAL_FRAMESIZE;
Samuel Seaybeb526b2013-01-02 10:53:46 +00004773 err |= put_user(env->gpr[1], newsp, target_ulong);
Nathan Froydbcd49332009-05-12 19:13:18 -07004774
4775 if (err)
4776 goto sigsegv;
4777
4778 /* Set up registers for signal handler. */
4779 env->gpr[1] = newsp;
Peter Maydellb6e2c932015-01-08 12:19:43 +00004780 env->gpr[3] = sig;
Samuel Seay61993a62013-01-04 14:35:48 +00004781 env->gpr[4] = frame_addr + offsetof(struct target_sigframe, sctx);
Tom Musta8d6ab332014-06-30 08:13:39 -05004782
4783#if defined(TARGET_PPC64)
Tom Musta14585582014-06-30 08:13:42 -05004784 if (get_ppc64_abi(image) < 2) {
4785 /* ELFv1 PPC64 function pointers are pointers to OPD entries. */
4786 struct target_func_ptr *handler =
4787 (struct target_func_ptr *)g2h(ka->_sa_handler);
4788 env->nip = tswapl(handler->entry);
4789 env->gpr[2] = tswapl(handler->toc);
4790 } else {
4791 /* ELFv2 PPC64 function pointers are entry points, but R12
4792 * must also be set */
4793 env->nip = tswapl((target_ulong) ka->_sa_handler);
4794 env->gpr[12] = env->nip;
4795 }
Tom Musta8d6ab332014-06-30 08:13:39 -05004796#else
Nathan Froydbcd49332009-05-12 19:13:18 -07004797 env->nip = (target_ulong) ka->_sa_handler;
Tom Musta8d6ab332014-06-30 08:13:39 -05004798#endif
4799
Nathan Froydbcd49332009-05-12 19:13:18 -07004800 /* Signal handlers are entered in big-endian mode. */
Laurent Vivier49e55cb2016-03-30 18:36:51 +02004801 env->msr &= ~(1ull << MSR_LE);
Nathan Froydbcd49332009-05-12 19:13:18 -07004802
4803 unlock_user_struct(frame, frame_addr, 1);
4804 return;
4805
4806sigsegv:
4807 unlock_user_struct(frame, frame_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02004808 force_sig(TARGET_SIGSEGV);
Nathan Froydbcd49332009-05-12 19:13:18 -07004809}
4810
4811static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05004812 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01004813 target_sigset_t *set, CPUPPCState *env)
Nathan Froydbcd49332009-05-12 19:13:18 -07004814{
4815 struct target_rt_sigframe *rt_sf;
Tom Musta61e75fe2014-06-30 08:13:38 -05004816 uint32_t *trampptr = 0;
4817 struct target_mcontext *mctx = 0;
Nathan Froydbcd49332009-05-12 19:13:18 -07004818 target_ulong rt_sf_addr, newsp = 0;
4819 int i, err = 0;
Tom Musta14585582014-06-30 08:13:42 -05004820#if defined(TARGET_PPC64)
4821 struct image_info *image = ((TaskState *)thread_cpu->opaque)->info;
4822#endif
Nathan Froydbcd49332009-05-12 19:13:18 -07004823
4824 rt_sf_addr = get_sigframe(ka, env, sizeof(*rt_sf));
4825 if (!lock_user_struct(VERIFY_WRITE, rt_sf, rt_sf_addr, 1))
4826 goto sigsegv;
4827
Peter Maydellf6c7a052015-01-08 12:19:48 +00004828 tswap_siginfo(&rt_sf->info, info);
Nathan Froydbcd49332009-05-12 19:13:18 -07004829
Riku Voipio1d8b5122014-04-23 10:26:05 +03004830 __put_user(0, &rt_sf->uc.tuc_flags);
4831 __put_user(0, &rt_sf->uc.tuc_link);
4832 __put_user((target_ulong)target_sigaltstack_used.ss_sp,
4833 &rt_sf->uc.tuc_stack.ss_sp);
4834 __put_user(sas_ss_flags(env->gpr[1]),
4835 &rt_sf->uc.tuc_stack.ss_flags);
4836 __put_user(target_sigaltstack_used.ss_size,
4837 &rt_sf->uc.tuc_stack.ss_size);
Tom Musta61e75fe2014-06-30 08:13:38 -05004838#if !defined(TARGET_PPC64)
Riku Voipio1d8b5122014-04-23 10:26:05 +03004839 __put_user(h2g (&rt_sf->uc.tuc_mcontext),
4840 &rt_sf->uc.tuc_regs);
Tom Musta61e75fe2014-06-30 08:13:38 -05004841#endif
Nathan Froydbcd49332009-05-12 19:13:18 -07004842 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03004843 __put_user(set->sig[i], &rt_sf->uc.tuc_sigmask.sig[i]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004844 }
4845
Tom Musta61e75fe2014-06-30 08:13:38 -05004846#if defined(TARGET_PPC64)
4847 mctx = &rt_sf->uc.tuc_sigcontext.mcontext;
4848 trampptr = &rt_sf->trampoline[0];
4849#else
4850 mctx = &rt_sf->uc.tuc_mcontext;
4851 trampptr = (uint32_t *)&rt_sf->uc.tuc_mcontext.tramp;
4852#endif
4853
4854 save_user_regs(env, mctx);
4855 encode_trampoline(TARGET_NR_rt_sigreturn, trampptr);
Nathan Froydbcd49332009-05-12 19:13:18 -07004856
4857 /* The kernel checks for the presence of a VDSO here. We don't
4858 emulate a vdso, so use a sigreturn system call. */
Tom Musta61e75fe2014-06-30 08:13:38 -05004859 env->lr = (target_ulong) h2g(trampptr);
Nathan Froydbcd49332009-05-12 19:13:18 -07004860
4861 /* Turn off all fp exceptions. */
4862 env->fpscr = 0;
4863
4864 /* Create a stack frame for the caller of the handler. */
4865 newsp = rt_sf_addr - (SIGNAL_FRAMESIZE + 16);
Tom Mustafbdc2002014-06-30 08:13:36 -05004866 err |= put_user(env->gpr[1], newsp, target_ulong);
Nathan Froydbcd49332009-05-12 19:13:18 -07004867
4868 if (err)
4869 goto sigsegv;
4870
4871 /* Set up registers for signal handler. */
4872 env->gpr[1] = newsp;
Peter Maydellb6e2c932015-01-08 12:19:43 +00004873 env->gpr[3] = (target_ulong) sig;
Nathan Froydbcd49332009-05-12 19:13:18 -07004874 env->gpr[4] = (target_ulong) h2g(&rt_sf->info);
4875 env->gpr[5] = (target_ulong) h2g(&rt_sf->uc);
4876 env->gpr[6] = (target_ulong) h2g(rt_sf);
Tom Musta8d6ab332014-06-30 08:13:39 -05004877
4878#if defined(TARGET_PPC64)
Tom Musta14585582014-06-30 08:13:42 -05004879 if (get_ppc64_abi(image) < 2) {
4880 /* ELFv1 PPC64 function pointers are pointers to OPD entries. */
4881 struct target_func_ptr *handler =
4882 (struct target_func_ptr *)g2h(ka->_sa_handler);
4883 env->nip = tswapl(handler->entry);
4884 env->gpr[2] = tswapl(handler->toc);
4885 } else {
4886 /* ELFv2 PPC64 function pointers are entry points, but R12
4887 * must also be set */
4888 env->nip = tswapl((target_ulong) ka->_sa_handler);
4889 env->gpr[12] = env->nip;
4890 }
Tom Musta8d6ab332014-06-30 08:13:39 -05004891#else
Nathan Froydbcd49332009-05-12 19:13:18 -07004892 env->nip = (target_ulong) ka->_sa_handler;
Tom Musta8d6ab332014-06-30 08:13:39 -05004893#endif
4894
Nathan Froydbcd49332009-05-12 19:13:18 -07004895 /* Signal handlers are entered in big-endian mode. */
Laurent Vivier49e55cb2016-03-30 18:36:51 +02004896 env->msr &= ~(1ull << MSR_LE);
Nathan Froydbcd49332009-05-12 19:13:18 -07004897
4898 unlock_user_struct(rt_sf, rt_sf_addr, 1);
4899 return;
4900
4901sigsegv:
4902 unlock_user_struct(rt_sf, rt_sf_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02004903 force_sig(TARGET_SIGSEGV);
Nathan Froydbcd49332009-05-12 19:13:18 -07004904
4905}
4906
Andreas Färber05390242012-02-25 03:37:53 +01004907long do_sigreturn(CPUPPCState *env)
Nathan Froydbcd49332009-05-12 19:13:18 -07004908{
4909 struct target_sigcontext *sc = NULL;
4910 struct target_mcontext *sr = NULL;
Peter Maydellb04636f2013-07-29 12:00:31 +01004911 target_ulong sr_addr = 0, sc_addr;
Nathan Froydbcd49332009-05-12 19:13:18 -07004912 sigset_t blocked;
Anthony Liguoric227f092009-10-01 16:12:16 -05004913 target_sigset_t set;
Nathan Froydbcd49332009-05-12 19:13:18 -07004914
4915 sc_addr = env->gpr[1] + SIGNAL_FRAMESIZE;
4916 if (!lock_user_struct(VERIFY_READ, sc, sc_addr, 1))
4917 goto sigsegv;
4918
4919#if defined(TARGET_PPC64)
Tom Musta61e75fe2014-06-30 08:13:38 -05004920 set.sig[0] = sc->oldmask + ((uint64_t)(sc->_unused[3]) << 32);
Nathan Froydbcd49332009-05-12 19:13:18 -07004921#else
Riku Voipiof5f601a2014-04-23 13:00:17 +03004922 __get_user(set.sig[0], &sc->oldmask);
4923 __get_user(set.sig[1], &sc->_unused[3]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004924#endif
4925 target_to_host_sigset_internal(&blocked, &set);
Peter Maydell9eede5b2016-05-27 15:51:46 +01004926 set_sigmask(&blocked);
Nathan Froydbcd49332009-05-12 19:13:18 -07004927
Riku Voipiof5f601a2014-04-23 13:00:17 +03004928 __get_user(sr_addr, &sc->regs);
Nathan Froydbcd49332009-05-12 19:13:18 -07004929 if (!lock_user_struct(VERIFY_READ, sr, sr_addr, 1))
4930 goto sigsegv;
Riku Voipioc650c002014-04-23 13:53:45 +03004931 restore_user_regs(env, sr, 1);
Nathan Froydbcd49332009-05-12 19:13:18 -07004932
4933 unlock_user_struct(sr, sr_addr, 1);
4934 unlock_user_struct(sc, sc_addr, 1);
4935 return -TARGET_QEMU_ESIGRETURN;
4936
4937sigsegv:
4938 unlock_user_struct(sr, sr_addr, 1);
4939 unlock_user_struct(sc, sc_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02004940 force_sig(TARGET_SIGSEGV);
Nathan Froydbcd49332009-05-12 19:13:18 -07004941 return 0;
4942}
4943
4944/* See arch/powerpc/kernel/signal_32.c. */
Andreas Färber05390242012-02-25 03:37:53 +01004945static int do_setcontext(struct target_ucontext *ucp, CPUPPCState *env, int sig)
Nathan Froydbcd49332009-05-12 19:13:18 -07004946{
4947 struct target_mcontext *mcp;
4948 target_ulong mcp_addr;
4949 sigset_t blocked;
Anthony Liguoric227f092009-10-01 16:12:16 -05004950 target_sigset_t set;
Nathan Froydbcd49332009-05-12 19:13:18 -07004951
Aurelien Jarno60e99242010-03-29 02:12:51 +02004952 if (copy_from_user(&set, h2g(ucp) + offsetof(struct target_ucontext, tuc_sigmask),
Nathan Froydbcd49332009-05-12 19:13:18 -07004953 sizeof (set)))
4954 return 1;
4955
Tom Musta19774ec2014-06-30 08:13:40 -05004956#if defined(TARGET_PPC64)
4957 mcp_addr = h2g(ucp) +
4958 offsetof(struct target_ucontext, tuc_sigcontext.mcontext);
4959#else
Riku Voipio9e918dc2014-04-23 14:05:09 +03004960 __get_user(mcp_addr, &ucp->tuc_regs);
Tom Musta19774ec2014-06-30 08:13:40 -05004961#endif
Nathan Froydbcd49332009-05-12 19:13:18 -07004962
4963 if (!lock_user_struct(VERIFY_READ, mcp, mcp_addr, 1))
4964 return 1;
4965
4966 target_to_host_sigset_internal(&blocked, &set);
Peter Maydell9eede5b2016-05-27 15:51:46 +01004967 set_sigmask(&blocked);
Riku Voipioc650c002014-04-23 13:53:45 +03004968 restore_user_regs(env, mcp, sig);
Nathan Froydbcd49332009-05-12 19:13:18 -07004969
4970 unlock_user_struct(mcp, mcp_addr, 1);
4971 return 0;
Nathan Froydbcd49332009-05-12 19:13:18 -07004972}
4973
Andreas Färber05390242012-02-25 03:37:53 +01004974long do_rt_sigreturn(CPUPPCState *env)
Nathan Froydbcd49332009-05-12 19:13:18 -07004975{
4976 struct target_rt_sigframe *rt_sf = NULL;
4977 target_ulong rt_sf_addr;
4978
4979 rt_sf_addr = env->gpr[1] + SIGNAL_FRAMESIZE + 16;
4980 if (!lock_user_struct(VERIFY_READ, rt_sf, rt_sf_addr, 1))
4981 goto sigsegv;
4982
4983 if (do_setcontext(&rt_sf->uc, env, 1))
4984 goto sigsegv;
4985
4986 do_sigaltstack(rt_sf_addr
Aurelien Jarno60e99242010-03-29 02:12:51 +02004987 + offsetof(struct target_rt_sigframe, uc.tuc_stack),
Nathan Froydbcd49332009-05-12 19:13:18 -07004988 0, env->gpr[1]);
4989
4990 unlock_user_struct(rt_sf, rt_sf_addr, 1);
4991 return -TARGET_QEMU_ESIGRETURN;
4992
4993sigsegv:
4994 unlock_user_struct(rt_sf, rt_sf_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02004995 force_sig(TARGET_SIGSEGV);
Nathan Froydbcd49332009-05-12 19:13:18 -07004996 return 0;
4997}
4998
Laurent Vivier492a8742009-08-03 16:12:17 +02004999#elif defined(TARGET_M68K)
5000
5001struct target_sigcontext {
5002 abi_ulong sc_mask;
5003 abi_ulong sc_usp;
5004 abi_ulong sc_d0;
5005 abi_ulong sc_d1;
5006 abi_ulong sc_a0;
5007 abi_ulong sc_a1;
5008 unsigned short sc_sr;
5009 abi_ulong sc_pc;
5010};
5011
5012struct target_sigframe
5013{
5014 abi_ulong pretcode;
5015 int sig;
5016 int code;
5017 abi_ulong psc;
5018 char retcode[8];
5019 abi_ulong extramask[TARGET_NSIG_WORDS-1];
5020 struct target_sigcontext sc;
5021};
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01005022
Anthony Liguoric227f092009-10-01 16:12:16 -05005023typedef int target_greg_t;
Laurent Vivier71811552009-08-03 16:12:18 +02005024#define TARGET_NGREG 18
Anthony Liguoric227f092009-10-01 16:12:16 -05005025typedef target_greg_t target_gregset_t[TARGET_NGREG];
Laurent Vivier71811552009-08-03 16:12:18 +02005026
5027typedef struct target_fpregset {
5028 int f_fpcntl[3];
5029 int f_fpregs[8*3];
Anthony Liguoric227f092009-10-01 16:12:16 -05005030} target_fpregset_t;
Laurent Vivier71811552009-08-03 16:12:18 +02005031
5032struct target_mcontext {
5033 int version;
Anthony Liguoric227f092009-10-01 16:12:16 -05005034 target_gregset_t gregs;
5035 target_fpregset_t fpregs;
Laurent Vivier71811552009-08-03 16:12:18 +02005036};
5037
5038#define TARGET_MCONTEXT_VERSION 2
5039
5040struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02005041 abi_ulong tuc_flags;
5042 abi_ulong tuc_link;
5043 target_stack_t tuc_stack;
5044 struct target_mcontext tuc_mcontext;
5045 abi_long tuc_filler[80];
5046 target_sigset_t tuc_sigmask;
Laurent Vivier71811552009-08-03 16:12:18 +02005047};
5048
5049struct target_rt_sigframe
5050{
5051 abi_ulong pretcode;
5052 int sig;
5053 abi_ulong pinfo;
5054 abi_ulong puc;
5055 char retcode[8];
5056 struct target_siginfo info;
5057 struct target_ucontext uc;
5058};
Laurent Vivier492a8742009-08-03 16:12:17 +02005059
Riku Voipio41ecc722014-04-23 11:01:00 +03005060static void setup_sigcontext(struct target_sigcontext *sc, CPUM68KState *env,
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01005061 abi_ulong mask)
Laurent Vivier492a8742009-08-03 16:12:17 +02005062{
Riku Voipio1d8b5122014-04-23 10:26:05 +03005063 __put_user(mask, &sc->sc_mask);
5064 __put_user(env->aregs[7], &sc->sc_usp);
5065 __put_user(env->dregs[0], &sc->sc_d0);
5066 __put_user(env->dregs[1], &sc->sc_d1);
5067 __put_user(env->aregs[0], &sc->sc_a0);
5068 __put_user(env->aregs[1], &sc->sc_a1);
5069 __put_user(env->sr, &sc->sc_sr);
5070 __put_user(env->pc, &sc->sc_pc);
Laurent Vivier492a8742009-08-03 16:12:17 +02005071}
5072
Riku Voipio016d2e12014-04-23 11:19:48 +03005073static void
Timothy E Baldwin7ccb84a2016-05-12 18:47:39 +01005074restore_sigcontext(CPUM68KState *env, struct target_sigcontext *sc)
Laurent Vivier492a8742009-08-03 16:12:17 +02005075{
Laurent Vivier492a8742009-08-03 16:12:17 +02005076 int temp;
5077
Riku Voipio1d8b5122014-04-23 10:26:05 +03005078 __get_user(env->aregs[7], &sc->sc_usp);
Timothy E Baldwin7ccb84a2016-05-12 18:47:39 +01005079 __get_user(env->dregs[0], &sc->sc_d0);
Riku Voipio1d8b5122014-04-23 10:26:05 +03005080 __get_user(env->dregs[1], &sc->sc_d1);
5081 __get_user(env->aregs[0], &sc->sc_a0);
5082 __get_user(env->aregs[1], &sc->sc_a1);
5083 __get_user(env->pc, &sc->sc_pc);
5084 __get_user(temp, &sc->sc_sr);
Laurent Vivier492a8742009-08-03 16:12:17 +02005085 env->sr = (env->sr & 0xff00) | (temp & 0xff);
Laurent Vivier492a8742009-08-03 16:12:17 +02005086}
5087
5088/*
5089 * Determine which stack to use..
5090 */
5091static inline abi_ulong
Andreas Färber05390242012-02-25 03:37:53 +01005092get_sigframe(struct target_sigaction *ka, CPUM68KState *regs,
5093 size_t frame_size)
Laurent Vivier492a8742009-08-03 16:12:17 +02005094{
5095 unsigned long sp;
5096
5097 sp = regs->aregs[7];
5098
5099 /* This is the X/Open sanctioned signal stack switching. */
5100 if ((ka->sa_flags & TARGET_SA_ONSTACK) && (sas_ss_flags (sp) == 0)) {
5101 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
5102 }
5103
5104 return ((sp - frame_size) & -8UL);
5105}
5106
5107static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01005108 target_sigset_t *set, CPUM68KState *env)
Laurent Vivier492a8742009-08-03 16:12:17 +02005109{
5110 struct target_sigframe *frame;
5111 abi_ulong frame_addr;
5112 abi_ulong retcode_addr;
5113 abi_ulong sc_addr;
Laurent Vivier492a8742009-08-03 16:12:17 +02005114 int i;
5115
5116 frame_addr = get_sigframe(ka, env, sizeof *frame);
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01005117 trace_user_setup_frame(env, frame_addr);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01005118 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
5119 goto give_sigsegv;
5120 }
Laurent Vivier492a8742009-08-03 16:12:17 +02005121
Riku Voipio1d8b5122014-04-23 10:26:05 +03005122 __put_user(sig, &frame->sig);
Laurent Vivier492a8742009-08-03 16:12:17 +02005123
5124 sc_addr = frame_addr + offsetof(struct target_sigframe, sc);
Riku Voipio1d8b5122014-04-23 10:26:05 +03005125 __put_user(sc_addr, &frame->psc);
Laurent Vivier492a8742009-08-03 16:12:17 +02005126
Riku Voipio41ecc722014-04-23 11:01:00 +03005127 setup_sigcontext(&frame->sc, env, set->sig[0]);
Laurent Vivier492a8742009-08-03 16:12:17 +02005128
5129 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
Riku Voipio0188fad2014-04-23 13:34:15 +03005130 __put_user(set->sig[i], &frame->extramask[i - 1]);
Laurent Vivier492a8742009-08-03 16:12:17 +02005131 }
5132
5133 /* Set up to return from userspace. */
5134
5135 retcode_addr = frame_addr + offsetof(struct target_sigframe, retcode);
Riku Voipio1d8b5122014-04-23 10:26:05 +03005136 __put_user(retcode_addr, &frame->pretcode);
Laurent Vivier492a8742009-08-03 16:12:17 +02005137
5138 /* moveq #,d0; trap #0 */
5139
Riku Voipio1d8b5122014-04-23 10:26:05 +03005140 __put_user(0x70004e40 + (TARGET_NR_sigreturn << 16),
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01005141 (uint32_t *)(frame->retcode));
Laurent Vivier492a8742009-08-03 16:12:17 +02005142
Laurent Vivier492a8742009-08-03 16:12:17 +02005143 /* Set up to return from userspace */
5144
5145 env->aregs[7] = frame_addr;
5146 env->pc = ka->_sa_handler;
5147
5148 unlock_user_struct(frame, frame_addr, 1);
5149 return;
5150
5151give_sigsegv:
Riku Voipio66393fb2009-12-04 15:16:32 +02005152 force_sig(TARGET_SIGSEGV);
Laurent Vivier492a8742009-08-03 16:12:17 +02005153}
5154
Laurent Vivier71811552009-08-03 16:12:18 +02005155static inline int target_rt_setup_ucontext(struct target_ucontext *uc,
Andreas Färber05390242012-02-25 03:37:53 +01005156 CPUM68KState *env)
Laurent Vivier71811552009-08-03 16:12:18 +02005157{
Aurelien Jarno60e99242010-03-29 02:12:51 +02005158 target_greg_t *gregs = uc->tuc_mcontext.gregs;
Laurent Vivier71811552009-08-03 16:12:18 +02005159
Riku Voipio1d8b5122014-04-23 10:26:05 +03005160 __put_user(TARGET_MCONTEXT_VERSION, &uc->tuc_mcontext.version);
5161 __put_user(env->dregs[0], &gregs[0]);
5162 __put_user(env->dregs[1], &gregs[1]);
5163 __put_user(env->dregs[2], &gregs[2]);
5164 __put_user(env->dregs[3], &gregs[3]);
5165 __put_user(env->dregs[4], &gregs[4]);
5166 __put_user(env->dregs[5], &gregs[5]);
5167 __put_user(env->dregs[6], &gregs[6]);
5168 __put_user(env->dregs[7], &gregs[7]);
5169 __put_user(env->aregs[0], &gregs[8]);
5170 __put_user(env->aregs[1], &gregs[9]);
5171 __put_user(env->aregs[2], &gregs[10]);
5172 __put_user(env->aregs[3], &gregs[11]);
5173 __put_user(env->aregs[4], &gregs[12]);
5174 __put_user(env->aregs[5], &gregs[13]);
5175 __put_user(env->aregs[6], &gregs[14]);
5176 __put_user(env->aregs[7], &gregs[15]);
5177 __put_user(env->pc, &gregs[16]);
5178 __put_user(env->sr, &gregs[17]);
Laurent Vivier71811552009-08-03 16:12:18 +02005179
Riku Voipio1d8b5122014-04-23 10:26:05 +03005180 return 0;
Laurent Vivier71811552009-08-03 16:12:18 +02005181}
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01005182
Andreas Färber05390242012-02-25 03:37:53 +01005183static inline int target_rt_restore_ucontext(CPUM68KState *env,
Timothy E Baldwin7ccb84a2016-05-12 18:47:39 +01005184 struct target_ucontext *uc)
Laurent Vivier71811552009-08-03 16:12:18 +02005185{
5186 int temp;
Aurelien Jarno60e99242010-03-29 02:12:51 +02005187 target_greg_t *gregs = uc->tuc_mcontext.gregs;
Laurent Vivier71811552009-08-03 16:12:18 +02005188
Riku Voipio1d8b5122014-04-23 10:26:05 +03005189 __get_user(temp, &uc->tuc_mcontext.version);
Laurent Vivier71811552009-08-03 16:12:18 +02005190 if (temp != TARGET_MCONTEXT_VERSION)
5191 goto badframe;
5192
5193 /* restore passed registers */
Riku Voipio1d8b5122014-04-23 10:26:05 +03005194 __get_user(env->dregs[0], &gregs[0]);
5195 __get_user(env->dregs[1], &gregs[1]);
5196 __get_user(env->dregs[2], &gregs[2]);
5197 __get_user(env->dregs[3], &gregs[3]);
5198 __get_user(env->dregs[4], &gregs[4]);
5199 __get_user(env->dregs[5], &gregs[5]);
5200 __get_user(env->dregs[6], &gregs[6]);
5201 __get_user(env->dregs[7], &gregs[7]);
5202 __get_user(env->aregs[0], &gregs[8]);
5203 __get_user(env->aregs[1], &gregs[9]);
5204 __get_user(env->aregs[2], &gregs[10]);
5205 __get_user(env->aregs[3], &gregs[11]);
5206 __get_user(env->aregs[4], &gregs[12]);
5207 __get_user(env->aregs[5], &gregs[13]);
5208 __get_user(env->aregs[6], &gregs[14]);
5209 __get_user(env->aregs[7], &gregs[15]);
5210 __get_user(env->pc, &gregs[16]);
5211 __get_user(temp, &gregs[17]);
Laurent Vivier71811552009-08-03 16:12:18 +02005212 env->sr = (env->sr & 0xff00) | (temp & 0xff);
5213
Riku Voipio1d8b5122014-04-23 10:26:05 +03005214 return 0;
Laurent Vivier71811552009-08-03 16:12:18 +02005215
5216badframe:
5217 return 1;
5218}
5219
Laurent Vivier492a8742009-08-03 16:12:17 +02005220static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05005221 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01005222 target_sigset_t *set, CPUM68KState *env)
Laurent Vivier492a8742009-08-03 16:12:17 +02005223{
Laurent Vivier71811552009-08-03 16:12:18 +02005224 struct target_rt_sigframe *frame;
5225 abi_ulong frame_addr;
5226 abi_ulong retcode_addr;
5227 abi_ulong info_addr;
5228 abi_ulong uc_addr;
5229 int err = 0;
5230 int i;
5231
5232 frame_addr = get_sigframe(ka, env, sizeof *frame);
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01005233 trace_user_setup_rt_frame(env, frame_addr);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01005234 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
5235 goto give_sigsegv;
5236 }
Laurent Vivier71811552009-08-03 16:12:18 +02005237
Riku Voipio1d8b5122014-04-23 10:26:05 +03005238 __put_user(sig, &frame->sig);
Laurent Vivier71811552009-08-03 16:12:18 +02005239
5240 info_addr = frame_addr + offsetof(struct target_rt_sigframe, info);
Riku Voipio1d8b5122014-04-23 10:26:05 +03005241 __put_user(info_addr, &frame->pinfo);
Laurent Vivier71811552009-08-03 16:12:18 +02005242
5243 uc_addr = frame_addr + offsetof(struct target_rt_sigframe, uc);
Riku Voipio1d8b5122014-04-23 10:26:05 +03005244 __put_user(uc_addr, &frame->puc);
Laurent Vivier71811552009-08-03 16:12:18 +02005245
Peter Maydellf6c7a052015-01-08 12:19:48 +00005246 tswap_siginfo(&frame->info, info);
Laurent Vivier71811552009-08-03 16:12:18 +02005247
5248 /* Create the ucontext */
5249
Riku Voipio1d8b5122014-04-23 10:26:05 +03005250 __put_user(0, &frame->uc.tuc_flags);
5251 __put_user(0, &frame->uc.tuc_link);
5252 __put_user(target_sigaltstack_used.ss_sp,
5253 &frame->uc.tuc_stack.ss_sp);
5254 __put_user(sas_ss_flags(env->aregs[7]),
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01005255 &frame->uc.tuc_stack.ss_flags);
Riku Voipio1d8b5122014-04-23 10:26:05 +03005256 __put_user(target_sigaltstack_used.ss_size,
5257 &frame->uc.tuc_stack.ss_size);
Laurent Vivier71811552009-08-03 16:12:18 +02005258 err |= target_rt_setup_ucontext(&frame->uc, env);
5259
5260 if (err)
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01005261 goto give_sigsegv;
Laurent Vivier71811552009-08-03 16:12:18 +02005262
5263 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
Riku Voipio0188fad2014-04-23 13:34:15 +03005264 __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
Laurent Vivier71811552009-08-03 16:12:18 +02005265 }
5266
5267 /* Set up to return from userspace. */
5268
5269 retcode_addr = frame_addr + offsetof(struct target_sigframe, retcode);
Riku Voipio1d8b5122014-04-23 10:26:05 +03005270 __put_user(retcode_addr, &frame->pretcode);
Laurent Vivier71811552009-08-03 16:12:18 +02005271
5272 /* moveq #,d0; notb d0; trap #0 */
5273
Riku Voipio1d8b5122014-04-23 10:26:05 +03005274 __put_user(0x70004600 + ((TARGET_NR_rt_sigreturn ^ 0xff) << 16),
Peter Maydell1669add2014-12-22 17:47:00 +00005275 (uint32_t *)(frame->retcode + 0));
5276 __put_user(0x4e40, (uint16_t *)(frame->retcode + 4));
Laurent Vivier71811552009-08-03 16:12:18 +02005277
5278 if (err)
5279 goto give_sigsegv;
5280
5281 /* Set up to return from userspace */
5282
5283 env->aregs[7] = frame_addr;
5284 env->pc = ka->_sa_handler;
5285
5286 unlock_user_struct(frame, frame_addr, 1);
5287 return;
5288
5289give_sigsegv:
5290 unlock_user_struct(frame, frame_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02005291 force_sig(TARGET_SIGSEGV);
Laurent Vivier492a8742009-08-03 16:12:17 +02005292}
5293
Andreas Färber05390242012-02-25 03:37:53 +01005294long do_sigreturn(CPUM68KState *env)
Laurent Vivier492a8742009-08-03 16:12:17 +02005295{
5296 struct target_sigframe *frame;
5297 abi_ulong frame_addr = env->aregs[7] - 4;
Anthony Liguoric227f092009-10-01 16:12:16 -05005298 target_sigset_t target_set;
Laurent Vivier492a8742009-08-03 16:12:17 +02005299 sigset_t set;
Timothy E Baldwin7ccb84a2016-05-12 18:47:39 +01005300 int i;
Laurent Vivier492a8742009-08-03 16:12:17 +02005301
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01005302 trace_user_do_sigreturn(env, frame_addr);
Laurent Vivier492a8742009-08-03 16:12:17 +02005303 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
5304 goto badframe;
5305
5306 /* set blocked signals */
5307
Riku Voipiof5f601a2014-04-23 13:00:17 +03005308 __get_user(target_set.sig[0], &frame->sc.sc_mask);
Laurent Vivier492a8742009-08-03 16:12:17 +02005309
5310 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
Riku Voipiof5f601a2014-04-23 13:00:17 +03005311 __get_user(target_set.sig[i], &frame->extramask[i - 1]);
Laurent Vivier492a8742009-08-03 16:12:17 +02005312 }
5313
5314 target_to_host_sigset_internal(&set, &target_set);
Peter Maydell9eede5b2016-05-27 15:51:46 +01005315 set_sigmask(&set);
Laurent Vivier492a8742009-08-03 16:12:17 +02005316
5317 /* restore registers */
5318
Timothy E Baldwin7ccb84a2016-05-12 18:47:39 +01005319 restore_sigcontext(env, &frame->sc);
Laurent Vivier492a8742009-08-03 16:12:17 +02005320
5321 unlock_user_struct(frame, frame_addr, 0);
Timothy E Baldwin7ccb84a2016-05-12 18:47:39 +01005322 return -TARGET_QEMU_ESIGRETURN;
Laurent Vivier492a8742009-08-03 16:12:17 +02005323
5324badframe:
Laurent Vivier492a8742009-08-03 16:12:17 +02005325 force_sig(TARGET_SIGSEGV);
5326 return 0;
5327}
5328
Andreas Färber05390242012-02-25 03:37:53 +01005329long do_rt_sigreturn(CPUM68KState *env)
Laurent Vivier492a8742009-08-03 16:12:17 +02005330{
Laurent Vivier71811552009-08-03 16:12:18 +02005331 struct target_rt_sigframe *frame;
5332 abi_ulong frame_addr = env->aregs[7] - 4;
Anthony Liguoric227f092009-10-01 16:12:16 -05005333 target_sigset_t target_set;
Laurent Vivier71811552009-08-03 16:12:18 +02005334 sigset_t set;
Laurent Vivier71811552009-08-03 16:12:18 +02005335
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01005336 trace_user_do_rt_sigreturn(env, frame_addr);
Laurent Vivier71811552009-08-03 16:12:18 +02005337 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
5338 goto badframe;
5339
5340 target_to_host_sigset_internal(&set, &target_set);
Peter Maydell9eede5b2016-05-27 15:51:46 +01005341 set_sigmask(&set);
Laurent Vivier71811552009-08-03 16:12:18 +02005342
5343 /* restore registers */
5344
Timothy E Baldwin7ccb84a2016-05-12 18:47:39 +01005345 if (target_rt_restore_ucontext(env, &frame->uc))
Laurent Vivier71811552009-08-03 16:12:18 +02005346 goto badframe;
5347
5348 if (do_sigaltstack(frame_addr +
Aurelien Jarno60e99242010-03-29 02:12:51 +02005349 offsetof(struct target_rt_sigframe, uc.tuc_stack),
Laurent Vivier71811552009-08-03 16:12:18 +02005350 0, get_sp_from_cpustate(env)) == -EFAULT)
5351 goto badframe;
5352
5353 unlock_user_struct(frame, frame_addr, 0);
Timothy E Baldwin7ccb84a2016-05-12 18:47:39 +01005354 return -TARGET_QEMU_ESIGRETURN;
Laurent Vivier71811552009-08-03 16:12:18 +02005355
5356badframe:
5357 unlock_user_struct(frame, frame_addr, 0);
5358 force_sig(TARGET_SIGSEGV);
5359 return 0;
Laurent Vivier492a8742009-08-03 16:12:17 +02005360}
5361
Richard Henderson6049f4f2009-12-27 18:30:03 -08005362#elif defined(TARGET_ALPHA)
5363
5364struct target_sigcontext {
5365 abi_long sc_onstack;
5366 abi_long sc_mask;
5367 abi_long sc_pc;
5368 abi_long sc_ps;
5369 abi_long sc_regs[32];
5370 abi_long sc_ownedfp;
5371 abi_long sc_fpregs[32];
5372 abi_ulong sc_fpcr;
5373 abi_ulong sc_fp_control;
5374 abi_ulong sc_reserved1;
5375 abi_ulong sc_reserved2;
5376 abi_ulong sc_ssize;
5377 abi_ulong sc_sbase;
5378 abi_ulong sc_traparg_a0;
5379 abi_ulong sc_traparg_a1;
5380 abi_ulong sc_traparg_a2;
5381 abi_ulong sc_fp_trap_pc;
5382 abi_ulong sc_fp_trigger_sum;
5383 abi_ulong sc_fp_trigger_inst;
5384};
5385
5386struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02005387 abi_ulong tuc_flags;
5388 abi_ulong tuc_link;
5389 abi_ulong tuc_osf_sigmask;
5390 target_stack_t tuc_stack;
5391 struct target_sigcontext tuc_mcontext;
5392 target_sigset_t tuc_sigmask;
Richard Henderson6049f4f2009-12-27 18:30:03 -08005393};
5394
5395struct target_sigframe {
5396 struct target_sigcontext sc;
5397 unsigned int retcode[3];
5398};
5399
5400struct target_rt_sigframe {
5401 target_siginfo_t info;
5402 struct target_ucontext uc;
5403 unsigned int retcode[3];
5404};
5405
5406#define INSN_MOV_R30_R16 0x47fe0410
5407#define INSN_LDI_R0 0x201f0000
5408#define INSN_CALLSYS 0x00000083
5409
Riku Voipio41ecc722014-04-23 11:01:00 +03005410static void setup_sigcontext(struct target_sigcontext *sc, CPUAlphaState *env,
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01005411 abi_ulong frame_addr, target_sigset_t *set)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005412{
Riku Voipio41ecc722014-04-23 11:01:00 +03005413 int i;
Richard Henderson6049f4f2009-12-27 18:30:03 -08005414
Riku Voipio1d8b5122014-04-23 10:26:05 +03005415 __put_user(on_sig_stack(frame_addr), &sc->sc_onstack);
5416 __put_user(set->sig[0], &sc->sc_mask);
5417 __put_user(env->pc, &sc->sc_pc);
5418 __put_user(8, &sc->sc_ps);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005419
5420 for (i = 0; i < 31; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03005421 __put_user(env->ir[i], &sc->sc_regs[i]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005422 }
Riku Voipio1d8b5122014-04-23 10:26:05 +03005423 __put_user(0, &sc->sc_regs[31]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005424
5425 for (i = 0; i < 31; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03005426 __put_user(env->fir[i], &sc->sc_fpregs[i]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005427 }
Riku Voipio1d8b5122014-04-23 10:26:05 +03005428 __put_user(0, &sc->sc_fpregs[31]);
5429 __put_user(cpu_alpha_load_fpcr(env), &sc->sc_fpcr);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005430
Riku Voipio1d8b5122014-04-23 10:26:05 +03005431 __put_user(0, &sc->sc_traparg_a0); /* FIXME */
5432 __put_user(0, &sc->sc_traparg_a1); /* FIXME */
5433 __put_user(0, &sc->sc_traparg_a2); /* FIXME */
Richard Henderson6049f4f2009-12-27 18:30:03 -08005434}
5435
Riku Voipio016d2e12014-04-23 11:19:48 +03005436static void restore_sigcontext(CPUAlphaState *env,
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01005437 struct target_sigcontext *sc)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005438{
5439 uint64_t fpcr;
Riku Voipio016d2e12014-04-23 11:19:48 +03005440 int i;
Richard Henderson6049f4f2009-12-27 18:30:03 -08005441
Riku Voipio1d8b5122014-04-23 10:26:05 +03005442 __get_user(env->pc, &sc->sc_pc);
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->ir[i], &sc->sc_regs[i]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005446 }
5447 for (i = 0; i < 31; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03005448 __get_user(env->fir[i], &sc->sc_fpregs[i]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005449 }
5450
Riku Voipio1d8b5122014-04-23 10:26:05 +03005451 __get_user(fpcr, &sc->sc_fpcr);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005452 cpu_alpha_store_fpcr(env, fpcr);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005453}
5454
5455static inline abi_ulong get_sigframe(struct target_sigaction *sa,
Andreas Färber05390242012-02-25 03:37:53 +01005456 CPUAlphaState *env,
5457 unsigned long framesize)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005458{
5459 abi_ulong sp = env->ir[IR_SP];
5460
5461 /* This is the X/Open sanctioned signal stack switching. */
5462 if ((sa->sa_flags & TARGET_SA_ONSTACK) != 0 && !sas_ss_flags(sp)) {
5463 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
5464 }
5465 return (sp - framesize) & -32;
5466}
5467
5468static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01005469 target_sigset_t *set, CPUAlphaState *env)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005470{
5471 abi_ulong frame_addr, r26;
5472 struct target_sigframe *frame;
5473 int err = 0;
5474
5475 frame_addr = get_sigframe(ka, env, sizeof(*frame));
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01005476 trace_user_setup_frame(env, frame_addr);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005477 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
5478 goto give_sigsegv;
5479 }
5480
Riku Voipio41ecc722014-04-23 11:01:00 +03005481 setup_sigcontext(&frame->sc, env, frame_addr, set);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005482
5483 if (ka->sa_restorer) {
5484 r26 = ka->sa_restorer;
5485 } else {
Riku Voipio1d8b5122014-04-23 10:26:05 +03005486 __put_user(INSN_MOV_R30_R16, &frame->retcode[0]);
5487 __put_user(INSN_LDI_R0 + TARGET_NR_sigreturn,
5488 &frame->retcode[1]);
5489 __put_user(INSN_CALLSYS, &frame->retcode[2]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005490 /* imb() */
5491 r26 = frame_addr;
5492 }
5493
5494 unlock_user_struct(frame, frame_addr, 1);
5495
5496 if (err) {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01005497give_sigsegv:
Richard Henderson6049f4f2009-12-27 18:30:03 -08005498 if (sig == TARGET_SIGSEGV) {
5499 ka->_sa_handler = TARGET_SIG_DFL;
5500 }
5501 force_sig(TARGET_SIGSEGV);
5502 }
5503
5504 env->ir[IR_RA] = r26;
5505 env->ir[IR_PV] = env->pc = ka->_sa_handler;
5506 env->ir[IR_A0] = sig;
5507 env->ir[IR_A1] = 0;
5508 env->ir[IR_A2] = frame_addr + offsetof(struct target_sigframe, sc);
5509 env->ir[IR_SP] = frame_addr;
5510}
5511
5512static void setup_rt_frame(int sig, struct target_sigaction *ka,
5513 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01005514 target_sigset_t *set, CPUAlphaState *env)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005515{
5516 abi_ulong frame_addr, r26;
5517 struct target_rt_sigframe *frame;
5518 int i, err = 0;
5519
5520 frame_addr = get_sigframe(ka, env, sizeof(*frame));
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01005521 trace_user_setup_rt_frame(env, frame_addr);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005522 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
5523 goto give_sigsegv;
5524 }
5525
Peter Maydellf6c7a052015-01-08 12:19:48 +00005526 tswap_siginfo(&frame->info, info);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005527
Riku Voipio1d8b5122014-04-23 10:26:05 +03005528 __put_user(0, &frame->uc.tuc_flags);
5529 __put_user(0, &frame->uc.tuc_link);
5530 __put_user(set->sig[0], &frame->uc.tuc_osf_sigmask);
5531 __put_user(target_sigaltstack_used.ss_sp,
5532 &frame->uc.tuc_stack.ss_sp);
5533 __put_user(sas_ss_flags(env->ir[IR_SP]),
5534 &frame->uc.tuc_stack.ss_flags);
5535 __put_user(target_sigaltstack_used.ss_size,
5536 &frame->uc.tuc_stack.ss_size);
Riku Voipio41ecc722014-04-23 11:01:00 +03005537 setup_sigcontext(&frame->uc.tuc_mcontext, env, frame_addr, set);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005538 for (i = 0; i < TARGET_NSIG_WORDS; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03005539 __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005540 }
5541
5542 if (ka->sa_restorer) {
5543 r26 = ka->sa_restorer;
5544 } else {
Riku Voipio1d8b5122014-04-23 10:26:05 +03005545 __put_user(INSN_MOV_R30_R16, &frame->retcode[0]);
5546 __put_user(INSN_LDI_R0 + TARGET_NR_rt_sigreturn,
5547 &frame->retcode[1]);
5548 __put_user(INSN_CALLSYS, &frame->retcode[2]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005549 /* imb(); */
5550 r26 = frame_addr;
5551 }
5552
5553 if (err) {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01005554give_sigsegv:
5555 if (sig == TARGET_SIGSEGV) {
Richard Henderson6049f4f2009-12-27 18:30:03 -08005556 ka->_sa_handler = TARGET_SIG_DFL;
5557 }
5558 force_sig(TARGET_SIGSEGV);
5559 }
5560
5561 env->ir[IR_RA] = r26;
5562 env->ir[IR_PV] = env->pc = ka->_sa_handler;
5563 env->ir[IR_A0] = sig;
5564 env->ir[IR_A1] = frame_addr + offsetof(struct target_rt_sigframe, info);
5565 env->ir[IR_A2] = frame_addr + offsetof(struct target_rt_sigframe, uc);
5566 env->ir[IR_SP] = frame_addr;
5567}
5568
Andreas Färber05390242012-02-25 03:37:53 +01005569long do_sigreturn(CPUAlphaState *env)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005570{
5571 struct target_sigcontext *sc;
5572 abi_ulong sc_addr = env->ir[IR_A0];
5573 target_sigset_t target_set;
5574 sigset_t set;
5575
5576 if (!lock_user_struct(VERIFY_READ, sc, sc_addr, 1)) {
5577 goto badframe;
5578 }
5579
5580 target_sigemptyset(&target_set);
Riku Voipiof5f601a2014-04-23 13:00:17 +03005581 __get_user(target_set.sig[0], &sc->sc_mask);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005582
5583 target_to_host_sigset_internal(&set, &target_set);
Peter Maydell9eede5b2016-05-27 15:51:46 +01005584 set_sigmask(&set);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005585
Riku Voipio016d2e12014-04-23 11:19:48 +03005586 restore_sigcontext(env, sc);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005587 unlock_user_struct(sc, sc_addr, 0);
Timothy E Baldwin338c8582016-05-12 18:47:36 +01005588 return -TARGET_QEMU_ESIGRETURN;
Richard Henderson6049f4f2009-12-27 18:30:03 -08005589
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01005590badframe:
Richard Henderson6049f4f2009-12-27 18:30:03 -08005591 force_sig(TARGET_SIGSEGV);
5592}
5593
Andreas Färber05390242012-02-25 03:37:53 +01005594long do_rt_sigreturn(CPUAlphaState *env)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005595{
5596 abi_ulong frame_addr = env->ir[IR_A0];
5597 struct target_rt_sigframe *frame;
5598 sigset_t set;
5599
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01005600 trace_user_do_rt_sigreturn(env, frame_addr);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005601 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
5602 goto badframe;
5603 }
Aurelien Jarno60e99242010-03-29 02:12:51 +02005604 target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
Peter Maydell9eede5b2016-05-27 15:51:46 +01005605 set_sigmask(&set);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005606
Riku Voipio016d2e12014-04-23 11:19:48 +03005607 restore_sigcontext(env, &frame->uc.tuc_mcontext);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005608 if (do_sigaltstack(frame_addr + offsetof(struct target_rt_sigframe,
Aurelien Jarno60e99242010-03-29 02:12:51 +02005609 uc.tuc_stack),
Richard Henderson6049f4f2009-12-27 18:30:03 -08005610 0, env->ir[IR_SP]) == -EFAULT) {
5611 goto badframe;
5612 }
5613
5614 unlock_user_struct(frame, frame_addr, 0);
Timothy E Baldwin338c8582016-05-12 18:47:36 +01005615 return -TARGET_QEMU_ESIGRETURN;
Richard Henderson6049f4f2009-12-27 18:30:03 -08005616
5617
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01005618badframe:
Richard Henderson6049f4f2009-12-27 18:30:03 -08005619 unlock_user_struct(frame, frame_addr, 0);
5620 force_sig(TARGET_SIGSEGV);
5621}
5622
Chen Gangbf0f60a2015-09-27 08:10:18 +08005623#elif defined(TARGET_TILEGX)
5624
5625struct target_sigcontext {
5626 union {
5627 /* General-purpose registers. */
5628 abi_ulong gregs[56];
5629 struct {
5630 abi_ulong __gregs[53];
5631 abi_ulong tp; /* Aliases gregs[TREG_TP]. */
5632 abi_ulong sp; /* Aliases gregs[TREG_SP]. */
5633 abi_ulong lr; /* Aliases gregs[TREG_LR]. */
5634 };
5635 };
5636 abi_ulong pc; /* Program counter. */
5637 abi_ulong ics; /* In Interrupt Critical Section? */
5638 abi_ulong faultnum; /* Fault number. */
5639 abi_ulong pad[5];
5640};
5641
5642struct target_ucontext {
5643 abi_ulong tuc_flags;
5644 abi_ulong tuc_link;
5645 target_stack_t tuc_stack;
5646 struct target_sigcontext tuc_mcontext;
5647 target_sigset_t tuc_sigmask; /* mask last for extensibility */
5648};
5649
5650struct target_rt_sigframe {
5651 unsigned char save_area[16]; /* caller save area */
5652 struct target_siginfo info;
5653 struct target_ucontext uc;
Chen Gangf1d9d102016-03-29 21:53:49 +08005654 abi_ulong retcode[2];
Chen Gangbf0f60a2015-09-27 08:10:18 +08005655};
5656
Chen Gangf1d9d102016-03-29 21:53:49 +08005657#define INSN_MOVELI_R10_139 0x00045fe551483000ULL /* { moveli r10, 139 } */
5658#define INSN_SWINT1 0x286b180051485000ULL /* { swint1 } */
5659
5660
Chen Gangbf0f60a2015-09-27 08:10:18 +08005661static void setup_sigcontext(struct target_sigcontext *sc,
5662 CPUArchState *env, int signo)
5663{
5664 int i;
5665
5666 for (i = 0; i < TILEGX_R_COUNT; ++i) {
5667 __put_user(env->regs[i], &sc->gregs[i]);
5668 }
5669
5670 __put_user(env->pc, &sc->pc);
5671 __put_user(0, &sc->ics);
5672 __put_user(signo, &sc->faultnum);
5673}
5674
5675static void restore_sigcontext(CPUTLGState *env, struct target_sigcontext *sc)
5676{
5677 int i;
5678
5679 for (i = 0; i < TILEGX_R_COUNT; ++i) {
5680 __get_user(env->regs[i], &sc->gregs[i]);
5681 }
5682
5683 __get_user(env->pc, &sc->pc);
5684}
5685
5686static abi_ulong get_sigframe(struct target_sigaction *ka, CPUArchState *env,
5687 size_t frame_size)
5688{
5689 unsigned long sp = env->regs[TILEGX_R_SP];
5690
5691 if (on_sig_stack(sp) && !likely(on_sig_stack(sp - frame_size))) {
5692 return -1UL;
5693 }
5694
5695 if ((ka->sa_flags & SA_ONSTACK) && !sas_ss_flags(sp)) {
5696 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
5697 }
5698
5699 sp -= frame_size;
5700 sp &= -16UL;
5701 return sp;
5702}
5703
5704static void setup_rt_frame(int sig, struct target_sigaction *ka,
5705 target_siginfo_t *info,
5706 target_sigset_t *set, CPUArchState *env)
5707{
5708 abi_ulong frame_addr;
5709 struct target_rt_sigframe *frame;
5710 unsigned long restorer;
5711
5712 frame_addr = get_sigframe(ka, env, sizeof(*frame));
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01005713 trace_user_setup_rt_frame(env, frame_addr);
Chen Gangbf0f60a2015-09-27 08:10:18 +08005714 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
5715 goto give_sigsegv;
5716 }
5717
5718 /* Always write at least the signal number for the stack backtracer. */
5719 if (ka->sa_flags & TARGET_SA_SIGINFO) {
5720 /* At sigreturn time, restore the callee-save registers too. */
5721 tswap_siginfo(&frame->info, info);
5722 /* regs->flags |= PT_FLAGS_RESTORE_REGS; FIXME: we can skip it? */
5723 } else {
5724 __put_user(info->si_signo, &frame->info.si_signo);
5725 }
5726
5727 /* Create the ucontext. */
5728 __put_user(0, &frame->uc.tuc_flags);
5729 __put_user(0, &frame->uc.tuc_link);
5730 __put_user(target_sigaltstack_used.ss_sp, &frame->uc.tuc_stack.ss_sp);
5731 __put_user(sas_ss_flags(env->regs[TILEGX_R_SP]),
5732 &frame->uc.tuc_stack.ss_flags);
5733 __put_user(target_sigaltstack_used.ss_size, &frame->uc.tuc_stack.ss_size);
5734 setup_sigcontext(&frame->uc.tuc_mcontext, env, info->si_signo);
5735
Chen Gangbf0f60a2015-09-27 08:10:18 +08005736 if (ka->sa_flags & TARGET_SA_RESTORER) {
Chen Gangf1d9d102016-03-29 21:53:49 +08005737 restorer = (unsigned long) ka->sa_restorer;
5738 } else {
5739 __put_user(INSN_MOVELI_R10_139, &frame->retcode[0]);
5740 __put_user(INSN_SWINT1, &frame->retcode[1]);
5741 restorer = frame_addr + offsetof(struct target_rt_sigframe, retcode);
Chen Gangbf0f60a2015-09-27 08:10:18 +08005742 }
5743 env->pc = (unsigned long) ka->_sa_handler;
5744 env->regs[TILEGX_R_SP] = (unsigned long) frame;
5745 env->regs[TILEGX_R_LR] = restorer;
5746 env->regs[0] = (unsigned long) sig;
5747 env->regs[1] = (unsigned long) &frame->info;
5748 env->regs[2] = (unsigned long) &frame->uc;
5749 /* regs->flags |= PT_FLAGS_CALLER_SAVES; FIXME: we can skip it? */
5750
5751 unlock_user_struct(frame, frame_addr, 1);
5752 return;
5753
5754give_sigsegv:
5755 if (sig == TARGET_SIGSEGV) {
5756 ka->_sa_handler = TARGET_SIG_DFL;
5757 }
5758 force_sig(TARGET_SIGSEGV /* , current */);
5759}
5760
5761long do_rt_sigreturn(CPUTLGState *env)
5762{
5763 abi_ulong frame_addr = env->regs[TILEGX_R_SP];
5764 struct target_rt_sigframe *frame;
5765 sigset_t set;
5766
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01005767 trace_user_do_rt_sigreturn(env, frame_addr);
Chen Gangbf0f60a2015-09-27 08:10:18 +08005768 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
5769 goto badframe;
5770 }
5771 target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
Peter Maydell9eede5b2016-05-27 15:51:46 +01005772 set_sigmask(&set);
Chen Gangbf0f60a2015-09-27 08:10:18 +08005773
5774 restore_sigcontext(env, &frame->uc.tuc_mcontext);
5775 if (do_sigaltstack(frame_addr + offsetof(struct target_rt_sigframe,
5776 uc.tuc_stack),
5777 0, env->regs[TILEGX_R_SP]) == -EFAULT) {
5778 goto badframe;
5779 }
5780
5781 unlock_user_struct(frame, frame_addr, 0);
Peter Maydella9175162016-05-12 18:47:42 +01005782 return -TARGET_QEMU_ESIGRETURN;
Chen Gangbf0f60a2015-09-27 08:10:18 +08005783
5784
5785 badframe:
5786 unlock_user_struct(frame, frame_addr, 0);
5787 force_sig(TARGET_SIGSEGV);
5788}
5789
bellardb346ff42003-06-15 20:05:50 +00005790#else
5791
pbrook624f7972008-05-31 16:11:38 +00005792static void setup_frame(int sig, struct target_sigaction *ka,
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01005793 target_sigset_t *set, CPUArchState *env)
bellardb346ff42003-06-15 20:05:50 +00005794{
5795 fprintf(stderr, "setup_frame: not implemented\n");
5796}
5797
pbrook624f7972008-05-31 16:11:38 +00005798static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05005799 target_siginfo_t *info,
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01005800 target_sigset_t *set, CPUArchState *env)
bellardb346ff42003-06-15 20:05:50 +00005801{
5802 fprintf(stderr, "setup_rt_frame: not implemented\n");
5803}
5804
Andreas Färber9349b4f2012-03-14 01:38:32 +01005805long do_sigreturn(CPUArchState *env)
bellardb346ff42003-06-15 20:05:50 +00005806{
5807 fprintf(stderr, "do_sigreturn: not implemented\n");
bellardf8b0aa22007-11-11 23:03:42 +00005808 return -TARGET_ENOSYS;
bellardb346ff42003-06-15 20:05:50 +00005809}
5810
Andreas Färber9349b4f2012-03-14 01:38:32 +01005811long do_rt_sigreturn(CPUArchState *env)
bellardb346ff42003-06-15 20:05:50 +00005812{
5813 fprintf(stderr, "do_rt_sigreturn: not implemented\n");
bellardf8b0aa22007-11-11 23:03:42 +00005814 return -TARGET_ENOSYS;
bellardb346ff42003-06-15 20:05:50 +00005815}
5816
bellard66fb9762003-03-23 01:06:05 +00005817#endif
5818
Peter Maydelleb552502016-05-27 15:51:43 +01005819static void handle_pending_signal(CPUArchState *cpu_env, int sig)
5820{
5821 CPUState *cpu = ENV_GET_CPU(cpu_env);
5822 abi_ulong handler;
Peter Maydell3d3efba2016-05-27 15:51:49 +01005823 sigset_t set;
Peter Maydelleb552502016-05-27 15:51:43 +01005824 target_sigset_t target_old_set;
5825 struct target_sigaction *sa;
Peter Maydelleb552502016-05-27 15:51:43 +01005826 TaskState *ts = cpu->opaque;
5827 struct emulated_sigtable *k = &ts->sigtab[sig - 1];
5828
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01005829 trace_user_handle_signal(cpu_env, sig);
bellard66fb9762003-03-23 01:06:05 +00005830 /* dequeue signal */
Timothy E Baldwin907f5fd2016-05-27 15:51:52 +01005831 k->pending = 0;
ths3b46e622007-09-17 08:09:54 +00005832
Andreas Färberdb6b81d2013-06-27 19:49:31 +02005833 sig = gdb_handlesig(cpu, sig);
bellard1fddef42005-04-17 19:16:13 +00005834 if (!sig) {
aurel32ca587a82008-12-18 22:44:13 +00005835 sa = NULL;
5836 handler = TARGET_SIG_IGN;
5837 } else {
5838 sa = &sigact_table[sig - 1];
5839 handler = sa->_sa_handler;
bellard1fddef42005-04-17 19:16:13 +00005840 }
bellard66fb9762003-03-23 01:06:05 +00005841
bellard66fb9762003-03-23 01:06:05 +00005842 if (handler == TARGET_SIG_DFL) {
aurel32ca587a82008-12-18 22:44:13 +00005843 /* default handler : ignore some signal. The other are job control or fatal */
5844 if (sig == TARGET_SIGTSTP || sig == TARGET_SIGTTIN || sig == TARGET_SIGTTOU) {
5845 kill(getpid(),SIGSTOP);
5846 } else if (sig != TARGET_SIGCHLD &&
5847 sig != TARGET_SIGURG &&
5848 sig != TARGET_SIGWINCH &&
5849 sig != TARGET_SIGCONT) {
bellard66fb9762003-03-23 01:06:05 +00005850 force_sig(sig);
5851 }
5852 } else if (handler == TARGET_SIG_IGN) {
5853 /* ignore sig */
5854 } else if (handler == TARGET_SIG_ERR) {
5855 force_sig(sig);
5856 } else {
bellard9de5e442003-03-23 16:49:39 +00005857 /* compute the blocked signals during the handler execution */
Peter Maydell3d3efba2016-05-27 15:51:49 +01005858 sigset_t *blocked_set;
5859
pbrook624f7972008-05-31 16:11:38 +00005860 target_to_host_sigset(&set, &sa->sa_mask);
bellard9de5e442003-03-23 16:49:39 +00005861 /* SA_NODEFER indicates that the current signal should not be
5862 blocked during the handler */
pbrook624f7972008-05-31 16:11:38 +00005863 if (!(sa->sa_flags & TARGET_SA_NODEFER))
bellard9de5e442003-03-23 16:49:39 +00005864 sigaddset(&set, target_to_host_signal(sig));
ths3b46e622007-09-17 08:09:54 +00005865
bellard9de5e442003-03-23 16:49:39 +00005866 /* save the previous blocked signal state to restore it at the
5867 end of the signal execution (see do_sigreturn) */
Peter Maydell3d3efba2016-05-27 15:51:49 +01005868 host_to_target_sigset_internal(&target_old_set, &ts->signal_mask);
5869
5870 /* block signals in the handler */
5871 blocked_set = ts->in_sigsuspend ?
5872 &ts->sigsuspend_mask : &ts->signal_mask;
5873 sigorset(&ts->signal_mask, blocked_set, &set);
5874 ts->in_sigsuspend = 0;
bellard9de5e442003-03-23 16:49:39 +00005875
bellardbc8a22c2003-03-30 21:02:40 +00005876 /* if the CPU is in VM86 mode, we restore the 32 bit values */
j_mayer84409dd2007-04-06 08:56:50 +00005877#if defined(TARGET_I386) && !defined(TARGET_X86_64)
bellardbc8a22c2003-03-30 21:02:40 +00005878 {
5879 CPUX86State *env = cpu_env;
5880 if (env->eflags & VM_MASK)
5881 save_v86_state(env);
5882 }
5883#endif
bellard9de5e442003-03-23 16:49:39 +00005884 /* prepare the stack frame of the virtual CPU */
Chen Gangd0924a22015-09-12 23:32:30 +08005885#if defined(TARGET_ABI_MIPSN32) || defined(TARGET_ABI_MIPSN64) \
Chen Gangbf0f60a2015-09-27 08:10:18 +08005886 || defined(TARGET_OPENRISC) || defined(TARGET_TILEGX)
Richard Hendersonff970902013-02-10 10:30:42 -08005887 /* These targets do not have traditional signals. */
Timothy E Baldwin907f5fd2016-05-27 15:51:52 +01005888 setup_rt_frame(sig, sa, &k->info, &target_old_set, cpu_env);
Richard Hendersonff970902013-02-10 10:30:42 -08005889#else
pbrook624f7972008-05-31 16:11:38 +00005890 if (sa->sa_flags & TARGET_SA_SIGINFO)
Timothy E Baldwin907f5fd2016-05-27 15:51:52 +01005891 setup_rt_frame(sig, sa, &k->info, &target_old_set, cpu_env);
bellard66fb9762003-03-23 01:06:05 +00005892 else
pbrook624f7972008-05-31 16:11:38 +00005893 setup_frame(sig, sa, &target_old_set, cpu_env);
Richard Hendersonff970902013-02-10 10:30:42 -08005894#endif
Peter Maydell7ec87e02016-05-27 15:51:45 +01005895 if (sa->sa_flags & TARGET_SA_RESETHAND) {
pbrook624f7972008-05-31 16:11:38 +00005896 sa->_sa_handler = TARGET_SIG_DFL;
Peter Maydell7ec87e02016-05-27 15:51:45 +01005897 }
bellard31e31b82003-02-18 22:55:36 +00005898 }
bellard31e31b82003-02-18 22:55:36 +00005899}
Peter Maydelle902d582016-05-27 15:51:44 +01005900
5901void process_pending_signals(CPUArchState *cpu_env)
5902{
5903 CPUState *cpu = ENV_GET_CPU(cpu_env);
5904 int sig;
5905 TaskState *ts = cpu->opaque;
Peter Maydell3d3efba2016-05-27 15:51:49 +01005906 sigset_t set;
5907 sigset_t *blocked_set;
Peter Maydelle902d582016-05-27 15:51:44 +01005908
Peter Maydell3d3efba2016-05-27 15:51:49 +01005909 while (atomic_read(&ts->signal_pending)) {
5910 /* FIXME: This is not threadsafe. */
5911 sigfillset(&set);
5912 sigprocmask(SIG_SETMASK, &set, 0);
Peter Maydelle902d582016-05-27 15:51:44 +01005913
Timothy E Baldwin655ed672016-05-27 15:51:53 +01005914 sig = ts->sync_signal.pending;
5915 if (sig) {
5916 /* Synchronous signals are forced,
5917 * see force_sig_info() and callers in Linux
5918 * Note that not all of our queue_signal() calls in QEMU correspond
5919 * to force_sig_info() calls in Linux (some are send_sig_info()).
5920 * However it seems like a kernel bug to me to allow the process
5921 * to block a synchronous signal since it could then just end up
5922 * looping round and round indefinitely.
5923 */
5924 if (sigismember(&ts->signal_mask, target_to_host_signal_table[sig])
5925 || sigact_table[sig - 1]._sa_handler == TARGET_SIG_IGN) {
5926 sigdelset(&ts->signal_mask, target_to_host_signal_table[sig]);
5927 sigact_table[sig - 1]._sa_handler = TARGET_SIG_DFL;
5928 }
5929
5930 handle_pending_signal(cpu_env, sig);
5931 }
5932
Peter Maydell3d3efba2016-05-27 15:51:49 +01005933 for (sig = 1; sig <= TARGET_NSIG; sig++) {
5934 blocked_set = ts->in_sigsuspend ?
5935 &ts->sigsuspend_mask : &ts->signal_mask;
5936
5937 if (ts->sigtab[sig - 1].pending &&
5938 (!sigismember(blocked_set,
Timothy E Baldwin655ed672016-05-27 15:51:53 +01005939 target_to_host_signal_table[sig]))) {
Peter Maydell3d3efba2016-05-27 15:51:49 +01005940 handle_pending_signal(cpu_env, sig);
5941 /* Restart scan from the beginning */
5942 sig = 1;
5943 }
Peter Maydelle902d582016-05-27 15:51:44 +01005944 }
Peter Maydell3d3efba2016-05-27 15:51:49 +01005945
5946 /* if no signal is pending, unblock signals and recheck (the act
5947 * of unblocking might cause us to take another host signal which
5948 * will set signal_pending again).
5949 */
5950 atomic_set(&ts->signal_pending, 0);
5951 ts->in_sigsuspend = 0;
5952 set = ts->signal_mask;
5953 sigdelset(&set, SIGSEGV);
5954 sigdelset(&set, SIGBUS);
5955 sigprocmask(SIG_SETMASK, &set, 0);
Peter Maydelle902d582016-05-27 15:51:44 +01005956 }
Peter Maydell3d3efba2016-05-27 15:51:49 +01005957 ts->in_sigsuspend = 0;
Peter Maydelle902d582016-05-27 15:51:44 +01005958}