blob: 9d980456ec46eed0854a2360f59e2fca5e1afaa1 [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;
Peter Maydell3d3efba2016-05-27 15:51:49 +0100198
199 /* It's OK to block everything including SIGSEGV, because we won't
200 * run any further guest code before unblocking signals in
201 * process_pending_signals().
202 */
203 sigfillset(&set);
204 sigprocmask(SIG_SETMASK, &set, 0);
205
Eduardo Habkost9be38592016-06-13 18:57:58 -0300206 return atomic_xchg(&ts->signal_pending, 1);
Peter Maydell3d3efba2016-05-27 15:51:49 +0100207}
208
Alex Barcelo1c275922014-03-14 14:36:55 +0000209/* Wrapper for sigprocmask function
210 * Emulates a sigprocmask in a safe way for the guest. Note that set and oldset
Peter Maydell3d3efba2016-05-27 15:51:49 +0100211 * are host signal set, not guest ones. Returns -TARGET_ERESTARTSYS if
212 * a signal was already pending and the syscall must be restarted, or
213 * 0 on success.
214 * If set is NULL, this is guaranteed not to fail.
Alex Barcelo1c275922014-03-14 14:36:55 +0000215 */
216int do_sigprocmask(int how, const sigset_t *set, sigset_t *oldset)
217{
Peter Maydell3d3efba2016-05-27 15:51:49 +0100218 TaskState *ts = (TaskState *)thread_cpu->opaque;
219
220 if (oldset) {
221 *oldset = ts->signal_mask;
222 }
Peter Maydella7ec0f92014-03-14 14:36:56 +0000223
224 if (set) {
Peter Maydell3d3efba2016-05-27 15:51:49 +0100225 int i;
Peter Maydella7ec0f92014-03-14 14:36:56 +0000226
Peter Maydell3d3efba2016-05-27 15:51:49 +0100227 if (block_signals()) {
228 return -TARGET_ERESTARTSYS;
229 }
Peter Maydella7ec0f92014-03-14 14:36:56 +0000230
231 switch (how) {
232 case SIG_BLOCK:
Peter Maydell3d3efba2016-05-27 15:51:49 +0100233 sigorset(&ts->signal_mask, &ts->signal_mask, set);
Peter Maydella7ec0f92014-03-14 14:36:56 +0000234 break;
235 case SIG_UNBLOCK:
Peter Maydell3d3efba2016-05-27 15:51:49 +0100236 for (i = 1; i <= NSIG; ++i) {
237 if (sigismember(set, i)) {
238 sigdelset(&ts->signal_mask, i);
239 }
Peter Maydella7ec0f92014-03-14 14:36:56 +0000240 }
241 break;
242 case SIG_SETMASK:
Peter Maydell3d3efba2016-05-27 15:51:49 +0100243 ts->signal_mask = *set;
Peter Maydella7ec0f92014-03-14 14:36:56 +0000244 break;
245 default:
246 g_assert_not_reached();
247 }
Peter Maydell3d3efba2016-05-27 15:51:49 +0100248
249 /* Silently ignore attempts to change blocking status of KILL or STOP */
250 sigdelset(&ts->signal_mask, SIGKILL);
251 sigdelset(&ts->signal_mask, SIGSTOP);
Peter Maydella7ec0f92014-03-14 14:36:56 +0000252 }
Peter Maydell3d3efba2016-05-27 15:51:49 +0100253 return 0;
Alex Barcelo1c275922014-03-14 14:36:55 +0000254}
255
Peter Maydell9eede5b2016-05-27 15:51:46 +0100256#if !defined(TARGET_OPENRISC) && !defined(TARGET_UNICORE32) && \
257 !defined(TARGET_X86_64)
Peter Maydell3d3efba2016-05-27 15:51:49 +0100258/* Just set the guest's signal mask to the specified value; the
259 * caller is assumed to have called block_signals() already.
260 */
Peter Maydell9eede5b2016-05-27 15:51:46 +0100261static void set_sigmask(const sigset_t *set)
262{
Peter Maydell3d3efba2016-05-27 15:51:49 +0100263 TaskState *ts = (TaskState *)thread_cpu->opaque;
264
265 ts->signal_mask = *set;
Peter Maydell9eede5b2016-05-27 15:51:46 +0100266}
267#endif
268
bellard9de5e442003-03-23 16:49:39 +0000269/* siginfo conversion */
270
Anthony Liguoric227f092009-10-01 16:12:16 -0500271static inline void host_to_target_siginfo_noswap(target_siginfo_t *tinfo,
bellard9de5e442003-03-23 16:49:39 +0000272 const siginfo_t *info)
bellard66fb9762003-03-23 01:06:05 +0000273{
Richard Hendersona05c6402012-09-15 11:34:20 -0700274 int sig = host_to_target_signal(info->si_signo);
Peter Maydella70dadc2016-05-27 15:51:59 +0100275 int si_code = info->si_code;
276 int si_type;
bellard9de5e442003-03-23 16:49:39 +0000277 tinfo->si_signo = sig;
278 tinfo->si_errno = 0;
pbrookafd7cd92008-05-31 12:14:21 +0000279 tinfo->si_code = info->si_code;
Richard Hendersona05c6402012-09-15 11:34:20 -0700280
Peter Maydell55d72a72016-06-13 11:22:05 +0100281 /* This memset serves two purposes:
282 * (1) ensure we don't leak random junk to the guest later
283 * (2) placate false positives from gcc about fields
284 * being used uninitialized if it chooses to inline both this
285 * function and tswap_siginfo() into host_to_target_siginfo().
286 */
287 memset(tinfo->_sifields._pad, 0, sizeof(tinfo->_sifields._pad));
288
Peter Maydella70dadc2016-05-27 15:51:59 +0100289 /* This is awkward, because we have to use a combination of
290 * the si_code and si_signo to figure out which of the union's
291 * members are valid. (Within the host kernel it is always possible
292 * to tell, but the kernel carefully avoids giving userspace the
293 * high 16 bits of si_code, so we don't have the information to
294 * do this the easy way...) We therefore make our best guess,
295 * bearing in mind that a guest can spoof most of the si_codes
296 * via rt_sigqueueinfo() if it likes.
297 *
298 * Once we have made our guess, we record it in the top 16 bits of
299 * the si_code, so that tswap_siginfo() later can use it.
300 * tswap_siginfo() will strip these top bits out before writing
301 * si_code to the guest (sign-extending the lower bits).
302 */
303
304 switch (si_code) {
305 case SI_USER:
306 case SI_TKILL:
307 case SI_KERNEL:
308 /* Sent via kill(), tkill() or tgkill(), or direct from the kernel.
309 * These are the only unspoofable si_code values.
310 */
311 tinfo->_sifields._kill._pid = info->si_pid;
312 tinfo->_sifields._kill._uid = info->si_uid;
313 si_type = QEMU_SI_KILL;
314 break;
315 default:
316 /* Everything else is spoofable. Make best guess based on signal */
317 switch (sig) {
318 case TARGET_SIGCHLD:
319 tinfo->_sifields._sigchld._pid = info->si_pid;
320 tinfo->_sifields._sigchld._uid = info->si_uid;
321 tinfo->_sifields._sigchld._status
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100322 = host_to_target_waitstatus(info->si_status);
Peter Maydella70dadc2016-05-27 15:51:59 +0100323 tinfo->_sifields._sigchld._utime = info->si_utime;
324 tinfo->_sifields._sigchld._stime = info->si_stime;
325 si_type = QEMU_SI_CHLD;
326 break;
327 case TARGET_SIGIO:
328 tinfo->_sifields._sigpoll._band = info->si_band;
329 tinfo->_sifields._sigpoll._fd = info->si_fd;
330 si_type = QEMU_SI_POLL;
331 break;
332 default:
333 /* Assume a sigqueue()/mq_notify()/rt_sigqueueinfo() source. */
334 tinfo->_sifields._rt._pid = info->si_pid;
335 tinfo->_sifields._rt._uid = info->si_uid;
336 /* XXX: potential problem if 64 bit */
337 tinfo->_sifields._rt._sigval.sival_ptr
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100338 = (abi_ulong)(unsigned long)info->si_value.sival_ptr;
Peter Maydella70dadc2016-05-27 15:51:59 +0100339 si_type = QEMU_SI_RT;
340 break;
341 }
342 break;
bellard9de5e442003-03-23 16:49:39 +0000343 }
Peter Maydella70dadc2016-05-27 15:51:59 +0100344
345 tinfo->si_code = deposit32(si_code, 16, 16, si_type);
bellard66fb9762003-03-23 01:06:05 +0000346}
347
Anthony Liguoric227f092009-10-01 16:12:16 -0500348static void tswap_siginfo(target_siginfo_t *tinfo,
349 const target_siginfo_t *info)
bellard9de5e442003-03-23 16:49:39 +0000350{
Peter Maydella70dadc2016-05-27 15:51:59 +0100351 int si_type = extract32(info->si_code, 16, 16);
352 int si_code = sextract32(info->si_code, 0, 16);
Richard Hendersona05c6402012-09-15 11:34:20 -0700353
Peter Maydella70dadc2016-05-27 15:51:59 +0100354 __put_user(info->si_signo, &tinfo->si_signo);
355 __put_user(info->si_errno, &tinfo->si_errno);
356 __put_user(si_code, &tinfo->si_code);
357
358 /* We can use our internal marker of which fields in the structure
359 * are valid, rather than duplicating the guesswork of
360 * host_to_target_siginfo_noswap() here.
361 */
362 switch (si_type) {
363 case QEMU_SI_KILL:
364 __put_user(info->_sifields._kill._pid, &tinfo->_sifields._kill._pid);
365 __put_user(info->_sifields._kill._uid, &tinfo->_sifields._kill._uid);
366 break;
367 case QEMU_SI_TIMER:
368 __put_user(info->_sifields._timer._timer1,
369 &tinfo->_sifields._timer._timer1);
370 __put_user(info->_sifields._timer._timer2,
371 &tinfo->_sifields._timer._timer2);
372 break;
373 case QEMU_SI_POLL:
374 __put_user(info->_sifields._sigpoll._band,
375 &tinfo->_sifields._sigpoll._band);
376 __put_user(info->_sifields._sigpoll._fd,
377 &tinfo->_sifields._sigpoll._fd);
378 break;
379 case QEMU_SI_FAULT:
380 __put_user(info->_sifields._sigfault._addr,
381 &tinfo->_sifields._sigfault._addr);
382 break;
383 case QEMU_SI_CHLD:
384 __put_user(info->_sifields._sigchld._pid,
385 &tinfo->_sifields._sigchld._pid);
386 __put_user(info->_sifields._sigchld._uid,
387 &tinfo->_sifields._sigchld._uid);
388 __put_user(info->_sifields._sigchld._status,
389 &tinfo->_sifields._sigchld._status);
390 __put_user(info->_sifields._sigchld._utime,
391 &tinfo->_sifields._sigchld._utime);
392 __put_user(info->_sifields._sigchld._stime,
393 &tinfo->_sifields._sigchld._stime);
394 break;
395 case QEMU_SI_RT:
396 __put_user(info->_sifields._rt._pid, &tinfo->_sifields._rt._pid);
397 __put_user(info->_sifields._rt._uid, &tinfo->_sifields._rt._uid);
398 __put_user(info->_sifields._rt._sigval.sival_ptr,
399 &tinfo->_sifields._rt._sigval.sival_ptr);
400 break;
401 default:
402 g_assert_not_reached();
bellard9de5e442003-03-23 16:49:39 +0000403 }
404}
405
Anthony Liguoric227f092009-10-01 16:12:16 -0500406void host_to_target_siginfo(target_siginfo_t *tinfo, const siginfo_t *info)
bellard9de5e442003-03-23 16:49:39 +0000407{
Peter Maydell55d72a72016-06-13 11:22:05 +0100408 target_siginfo_t tgt_tmp;
409 host_to_target_siginfo_noswap(&tgt_tmp, info);
410 tswap_siginfo(tinfo, &tgt_tmp);
bellard9de5e442003-03-23 16:49:39 +0000411}
412
413/* XXX: we support only POSIX RT signals are used. */
thsaa1f17c2007-07-11 22:48:58 +0000414/* XXX: find a solution for 64 bit (additional malloced data is needed) */
Anthony Liguoric227f092009-10-01 16:12:16 -0500415void target_to_host_siginfo(siginfo_t *info, const target_siginfo_t *tinfo)
bellard66fb9762003-03-23 01:06:05 +0000416{
Peter Maydell90c0f082016-05-27 15:52:01 +0100417 /* This conversion is used only for the rt_sigqueueinfo syscall,
418 * and so we know that the _rt fields are the valid ones.
419 */
420 abi_ulong sival_ptr;
421
422 __get_user(info->si_signo, &tinfo->si_signo);
423 __get_user(info->si_errno, &tinfo->si_errno);
424 __get_user(info->si_code, &tinfo->si_code);
425 __get_user(info->si_pid, &tinfo->_sifields._rt._pid);
426 __get_user(info->si_uid, &tinfo->_sifields._rt._uid);
427 __get_user(sival_ptr, &tinfo->_sifields._rt._sigval.sival_ptr);
428 info->si_value.sival_ptr = (void *)(long)sival_ptr;
bellard66fb9762003-03-23 01:06:05 +0000429}
430
aurel32ca587a82008-12-18 22:44:13 +0000431static int fatal_signal (int sig)
432{
433 switch (sig) {
434 case TARGET_SIGCHLD:
435 case TARGET_SIGURG:
436 case TARGET_SIGWINCH:
437 /* Ignored by default. */
438 return 0;
439 case TARGET_SIGCONT:
440 case TARGET_SIGSTOP:
441 case TARGET_SIGTSTP:
442 case TARGET_SIGTTIN:
443 case TARGET_SIGTTOU:
444 /* Job control signals. */
445 return 0;
446 default:
447 return 1;
448 }
449}
450
Mika Westerbergedf8e2a2009-04-07 09:57:11 +0300451/* returns 1 if given signal should dump core if not handled */
452static int core_dump_signal(int sig)
453{
454 switch (sig) {
455 case TARGET_SIGABRT:
456 case TARGET_SIGFPE:
457 case TARGET_SIGILL:
458 case TARGET_SIGQUIT:
459 case TARGET_SIGSEGV:
460 case TARGET_SIGTRAP:
461 case TARGET_SIGBUS:
462 return (1);
463 default:
464 return (0);
465 }
466}
467
bellard31e31b82003-02-18 22:55:36 +0000468void signal_init(void)
469{
Peter Maydell3d3efba2016-05-27 15:51:49 +0100470 TaskState *ts = (TaskState *)thread_cpu->opaque;
bellard31e31b82003-02-18 22:55:36 +0000471 struct sigaction act;
pbrook624f7972008-05-31 16:11:38 +0000472 struct sigaction oact;
bellard9e5f5282003-07-13 17:33:54 +0000473 int i, j;
pbrook624f7972008-05-31 16:11:38 +0000474 int host_sig;
bellard31e31b82003-02-18 22:55:36 +0000475
bellard9e5f5282003-07-13 17:33:54 +0000476 /* generate signal conversion tables */
Arnaud Patard3ca05582009-03-30 01:18:20 +0200477 for(i = 1; i < _NSIG; i++) {
bellard9e5f5282003-07-13 17:33:54 +0000478 if (host_to_target_signal_table[i] == 0)
479 host_to_target_signal_table[i] = i;
480 }
Arnaud Patard3ca05582009-03-30 01:18:20 +0200481 for(i = 1; i < _NSIG; i++) {
bellard9e5f5282003-07-13 17:33:54 +0000482 j = host_to_target_signal_table[i];
483 target_to_host_signal_table[j] = i;
484 }
ths3b46e622007-09-17 08:09:54 +0000485
Peter Maydell3d3efba2016-05-27 15:51:49 +0100486 /* Set the signal mask from the host mask. */
487 sigprocmask(0, 0, &ts->signal_mask);
488
bellard9de5e442003-03-23 16:49:39 +0000489 /* set all host signal handlers. ALL signals are blocked during
490 the handlers to serialize them. */
pbrook624f7972008-05-31 16:11:38 +0000491 memset(sigact_table, 0, sizeof(sigact_table));
492
bellard9de5e442003-03-23 16:49:39 +0000493 sigfillset(&act.sa_mask);
bellard31e31b82003-02-18 22:55:36 +0000494 act.sa_flags = SA_SIGINFO;
495 act.sa_sigaction = host_signal_handler;
pbrook624f7972008-05-31 16:11:38 +0000496 for(i = 1; i <= TARGET_NSIG; i++) {
497 host_sig = target_to_host_signal(i);
498 sigaction(host_sig, NULL, &oact);
499 if (oact.sa_sigaction == (void *)SIG_IGN) {
500 sigact_table[i - 1]._sa_handler = TARGET_SIG_IGN;
501 } else if (oact.sa_sigaction == (void *)SIG_DFL) {
502 sigact_table[i - 1]._sa_handler = TARGET_SIG_DFL;
503 }
504 /* If there's already a handler installed then something has
505 gone horribly wrong, so don't even try to handle that case. */
aurel32ca587a82008-12-18 22:44:13 +0000506 /* Install some handlers for our own use. We need at least
507 SIGSEGV and SIGBUS, to detect exceptions. We can not just
508 trap all signals because it affects syscall interrupt
509 behavior. But do trap all default-fatal signals. */
510 if (fatal_signal (i))
pbrook624f7972008-05-31 16:11:38 +0000511 sigaction(host_sig, &act, NULL);
bellard31e31b82003-02-18 22:55:36 +0000512 }
bellard31e31b82003-02-18 22:55:36 +0000513}
514
bellard66fb9762003-03-23 01:06:05 +0000515
bellard9de5e442003-03-23 16:49:39 +0000516/* abort execution with signal */
Riku Voipio66393fb2009-12-04 15:16:32 +0200517static void QEMU_NORETURN force_sig(int target_sig)
bellard66fb9762003-03-23 01:06:05 +0000518{
Andreas Färber0429a972013-08-26 18:14:44 +0200519 CPUState *cpu = thread_cpu;
520 CPUArchState *env = cpu->env_ptr;
521 TaskState *ts = (TaskState *)cpu->opaque;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +0300522 int host_sig, core_dumped = 0;
aurel32603e4fd2009-04-15 16:18:38 +0000523 struct sigaction act;
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +0100524
Riku Voipio66393fb2009-12-04 15:16:32 +0200525 host_sig = target_to_host_signal(target_sig);
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +0100526 trace_user_force_sig(env, target_sig, host_sig);
Andreas Färbera2247f82013-06-09 19:47:04 +0200527 gdb_signalled(env, target_sig);
aurel32603e4fd2009-04-15 16:18:38 +0000528
Mika Westerbergedf8e2a2009-04-07 09:57:11 +0300529 /* dump core if supported by target binary format */
Riku Voipio66393fb2009-12-04 15:16:32 +0200530 if (core_dump_signal(target_sig) && (ts->bprm->core_dump != NULL)) {
Mika Westerbergedf8e2a2009-04-07 09:57:11 +0300531 stop_all_tasks();
532 core_dumped =
Andreas Färbera2247f82013-06-09 19:47:04 +0200533 ((*ts->bprm->core_dump)(target_sig, env) == 0);
Mika Westerbergedf8e2a2009-04-07 09:57:11 +0300534 }
535 if (core_dumped) {
536 /* we already dumped the core of target process, we don't want
537 * a coredump of qemu itself */
538 struct rlimit nodump;
539 getrlimit(RLIMIT_CORE, &nodump);
540 nodump.rlim_cur=0;
541 setrlimit(RLIMIT_CORE, &nodump);
542 (void) fprintf(stderr, "qemu: uncaught target signal %d (%s) - %s\n",
Riku Voipio66393fb2009-12-04 15:16:32 +0200543 target_sig, strsignal(host_sig), "core dumped" );
Mika Westerbergedf8e2a2009-04-07 09:57:11 +0300544 }
545
Stefan Weil0c587512011-04-28 17:20:32 +0200546 /* The proper exit code for dying from an uncaught signal is
aurel32603e4fd2009-04-15 16:18:38 +0000547 * -<signal>. The kernel doesn't allow exit() or _exit() to pass
548 * a negative value. To get the proper exit code we need to
549 * actually die from an uncaught signal. Here the default signal
550 * handler is installed, we send ourself a signal and we wait for
551 * it to arrive. */
552 sigfillset(&act.sa_mask);
553 act.sa_handler = SIG_DFL;
Peter Maydell3a5d30b2014-02-17 18:55:32 +0000554 act.sa_flags = 0;
aurel32603e4fd2009-04-15 16:18:38 +0000555 sigaction(host_sig, &act, NULL);
556
557 /* For some reason raise(host_sig) doesn't send the signal when
558 * statically linked on x86-64. */
559 kill(getpid(), host_sig);
560
561 /* Make sure the signal isn't masked (just reuse the mask inside
562 of act) */
563 sigdelset(&act.sa_mask, host_sig);
564 sigsuspend(&act.sa_mask);
565
566 /* unreachable */
Blue Swirla6c6f762010-03-13 14:18:50 +0000567 abort();
bellard66fb9762003-03-23 01:06:05 +0000568}
569
bellard9de5e442003-03-23 16:49:39 +0000570/* queue a signal so that it will be send to the virtual CPU as soon
571 as possible */
Andreas Färber9349b4f2012-03-14 01:38:32 +0100572int queue_signal(CPUArchState *env, int sig, target_siginfo_t *info)
bellard31e31b82003-02-18 22:55:36 +0000573{
Andreas Färber0429a972013-08-26 18:14:44 +0200574 CPUState *cpu = ENV_GET_CPU(env);
575 TaskState *ts = cpu->opaque;
bellard66fb9762003-03-23 01:06:05 +0000576
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +0100577 trace_user_queue_signal(env, sig);
Peter Maydella7ec0f92014-03-14 14:36:56 +0000578
Peter Maydella70dadc2016-05-27 15:51:59 +0100579 /* Currently all callers define siginfo structures which
580 * use the _sifields._sigfault union member, so we can
581 * set the type here. If that changes we should push this
582 * out so the si_type is passed in by callers.
583 */
584 info->si_code = deposit32(info->si_code, 16, 16, QEMU_SI_FAULT);
585
Timothy E Baldwin655ed672016-05-27 15:51:53 +0100586 ts->sync_signal.info = *info;
587 ts->sync_signal.pending = sig;
Timothy E Baldwin907f5fd2016-05-27 15:51:52 +0100588 /* signal that a new signal is pending */
589 atomic_set(&ts->signal_pending, 1);
590 return 1; /* indicates that the signal was queued */
bellard9de5e442003-03-23 16:49:39 +0000591}
592
Timothy E Baldwin4d330ce2016-05-12 18:47:46 +0100593#ifndef HAVE_SAFE_SYSCALL
594static inline void rewind_if_in_safe_syscall(void *puc)
595{
596 /* Default version: never rewind */
597}
598#endif
599
ths5fafdf22007-09-16 21:08:06 +0000600static void host_signal_handler(int host_signum, siginfo_t *info,
bellard9de5e442003-03-23 16:49:39 +0000601 void *puc)
602{
Andreas Färbera2247f82013-06-09 19:47:04 +0200603 CPUArchState *env = thread_cpu->env_ptr;
Timothy E Baldwin655ed672016-05-27 15:51:53 +0100604 CPUState *cpu = ENV_GET_CPU(env);
605 TaskState *ts = cpu->opaque;
606
bellard9de5e442003-03-23 16:49:39 +0000607 int sig;
Anthony Liguoric227f092009-10-01 16:12:16 -0500608 target_siginfo_t tinfo;
Peter Maydell3d3efba2016-05-27 15:51:49 +0100609 ucontext_t *uc = puc;
Timothy E Baldwin655ed672016-05-27 15:51:53 +0100610 struct emulated_sigtable *k;
bellard9de5e442003-03-23 16:49:39 +0000611
612 /* the CPU emulator uses some host signals to detect exceptions,
aurel32eaa449b2009-01-03 13:14:52 +0000613 we forward to it some signals */
aurel32ca587a82008-12-18 22:44:13 +0000614 if ((host_signum == SIGSEGV || host_signum == SIGBUS)
aurel32eaa449b2009-01-03 13:14:52 +0000615 && info->si_code > 0) {
bellardb346ff42003-06-15 20:05:50 +0000616 if (cpu_signal_handler(host_signum, info, puc))
bellard9de5e442003-03-23 16:49:39 +0000617 return;
618 }
619
620 /* get target signal number */
621 sig = host_to_target_signal(host_signum);
622 if (sig < 1 || sig > TARGET_NSIG)
623 return;
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +0100624 trace_user_host_signal(env, host_signum, sig);
Timothy E Baldwin4d330ce2016-05-12 18:47:46 +0100625
626 rewind_if_in_safe_syscall(puc);
627
bellard9de5e442003-03-23 16:49:39 +0000628 host_to_target_siginfo_noswap(&tinfo, info);
Timothy E Baldwin655ed672016-05-27 15:51:53 +0100629 k = &ts->sigtab[sig - 1];
630 k->info = tinfo;
631 k->pending = sig;
632 ts->signal_pending = 1;
Peter Maydell3d3efba2016-05-27 15:51:49 +0100633
Timothy E Baldwin655ed672016-05-27 15:51:53 +0100634 /* Block host signals until target signal handler entered. We
635 * can't block SIGSEGV or SIGBUS while we're executing guest
636 * code in case the guest code provokes one in the window between
637 * now and it getting out to the main loop. Signals will be
638 * unblocked again in process_pending_signals().
Peter Maydell1d48fdd2016-06-14 12:49:18 +0100639 *
640 * WARNING: we cannot use sigfillset() here because the uc_sigmask
641 * field is a kernel sigset_t, which is much smaller than the
642 * libc sigset_t which sigfillset() operates on. Using sigfillset()
643 * would write 0xff bytes off the end of the structure and trash
644 * data on the struct.
645 * We can't use sizeof(uc->uc_sigmask) either, because the libc
646 * headers define the struct field with the wrong (too large) type.
Timothy E Baldwin655ed672016-05-27 15:51:53 +0100647 */
Peter Maydell1d48fdd2016-06-14 12:49:18 +0100648 memset(&uc->uc_sigmask, 0xff, SIGSET_T_SIZE);
Timothy E Baldwin655ed672016-05-27 15:51:53 +0100649 sigdelset(&uc->uc_sigmask, SIGSEGV);
650 sigdelset(&uc->uc_sigmask, SIGBUS);
651
652 /* interrupt the virtual CPU as soon as possible */
653 cpu_exit(thread_cpu);
bellard31e31b82003-02-18 22:55:36 +0000654}
655
ths0da46a62007-10-20 20:23:07 +0000656/* do_sigaltstack() returns target values and errnos. */
bellard579a97f2007-11-11 14:26:47 +0000657/* compare linux/kernel/signal.c:do_sigaltstack() */
658abi_long do_sigaltstack(abi_ulong uss_addr, abi_ulong uoss_addr, abi_ulong sp)
thsa04e1342007-09-27 13:57:58 +0000659{
660 int ret;
661 struct target_sigaltstack oss;
662
663 /* XXX: test errors */
bellard579a97f2007-11-11 14:26:47 +0000664 if(uoss_addr)
thsa04e1342007-09-27 13:57:58 +0000665 {
666 __put_user(target_sigaltstack_used.ss_sp, &oss.ss_sp);
667 __put_user(target_sigaltstack_used.ss_size, &oss.ss_size);
668 __put_user(sas_ss_flags(sp), &oss.ss_flags);
669 }
670
bellard579a97f2007-11-11 14:26:47 +0000671 if(uss_addr)
thsa04e1342007-09-27 13:57:58 +0000672 {
bellard579a97f2007-11-11 14:26:47 +0000673 struct target_sigaltstack *uss;
674 struct target_sigaltstack ss;
Tom Musta0903c8b2014-08-12 13:53:40 -0500675 size_t minstacksize = TARGET_MINSIGSTKSZ;
676
677#if defined(TARGET_PPC64)
678 /* ELF V2 for PPC64 has a 4K minimum stack size for signal handlers */
679 struct image_info *image = ((TaskState *)thread_cpu->opaque)->info;
680 if (get_ppc64_abi(image) > 1) {
681 minstacksize = 4096;
682 }
683#endif
thsa04e1342007-09-27 13:57:58 +0000684
ths0da46a62007-10-20 20:23:07 +0000685 ret = -TARGET_EFAULT;
Riku Voipio9eeb8302014-04-23 11:26:34 +0300686 if (!lock_user_struct(VERIFY_READ, uss, uss_addr, 1)) {
thsa04e1342007-09-27 13:57:58 +0000687 goto out;
Riku Voipio9eeb8302014-04-23 11:26:34 +0300688 }
689 __get_user(ss.ss_sp, &uss->ss_sp);
690 __get_user(ss.ss_size, &uss->ss_size);
691 __get_user(ss.ss_flags, &uss->ss_flags);
bellard579a97f2007-11-11 14:26:47 +0000692 unlock_user_struct(uss, uss_addr, 0);
thsa04e1342007-09-27 13:57:58 +0000693
ths0da46a62007-10-20 20:23:07 +0000694 ret = -TARGET_EPERM;
thsa04e1342007-09-27 13:57:58 +0000695 if (on_sig_stack(sp))
696 goto out;
697
ths0da46a62007-10-20 20:23:07 +0000698 ret = -TARGET_EINVAL;
thsa04e1342007-09-27 13:57:58 +0000699 if (ss.ss_flags != TARGET_SS_DISABLE
700 && ss.ss_flags != TARGET_SS_ONSTACK
701 && ss.ss_flags != 0)
702 goto out;
703
704 if (ss.ss_flags == TARGET_SS_DISABLE) {
705 ss.ss_size = 0;
706 ss.ss_sp = 0;
707 } else {
ths0da46a62007-10-20 20:23:07 +0000708 ret = -TARGET_ENOMEM;
Tom Musta0903c8b2014-08-12 13:53:40 -0500709 if (ss.ss_size < minstacksize) {
thsa04e1342007-09-27 13:57:58 +0000710 goto out;
Tom Musta0903c8b2014-08-12 13:53:40 -0500711 }
thsa04e1342007-09-27 13:57:58 +0000712 }
713
714 target_sigaltstack_used.ss_sp = ss.ss_sp;
715 target_sigaltstack_used.ss_size = ss.ss_size;
716 }
717
bellard579a97f2007-11-11 14:26:47 +0000718 if (uoss_addr) {
ths0da46a62007-10-20 20:23:07 +0000719 ret = -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +0000720 if (copy_to_user(uoss_addr, &oss, sizeof(oss)))
thsa04e1342007-09-27 13:57:58 +0000721 goto out;
thsa04e1342007-09-27 13:57:58 +0000722 }
723
724 ret = 0;
725out:
726 return ret;
727}
728
Timothy E Baldwinef6a7782016-05-27 15:51:54 +0100729/* do_sigaction() return target values and host errnos */
bellard66fb9762003-03-23 01:06:05 +0000730int do_sigaction(int sig, const struct target_sigaction *act,
731 struct target_sigaction *oact)
bellard31e31b82003-02-18 22:55:36 +0000732{
pbrook624f7972008-05-31 16:11:38 +0000733 struct target_sigaction *k;
bellard773b93e2004-01-04 17:15:59 +0000734 struct sigaction act1;
735 int host_sig;
ths0da46a62007-10-20 20:23:07 +0000736 int ret = 0;
bellard31e31b82003-02-18 22:55:36 +0000737
Timothy E Baldwinef6a7782016-05-27 15:51:54 +0100738 if (sig < 1 || sig > TARGET_NSIG || sig == TARGET_SIGKILL || sig == TARGET_SIGSTOP) {
739 return -TARGET_EINVAL;
740 }
741
742 if (block_signals()) {
743 return -TARGET_ERESTARTSYS;
744 }
745
bellard66fb9762003-03-23 01:06:05 +0000746 k = &sigact_table[sig - 1];
bellard66fb9762003-03-23 01:06:05 +0000747 if (oact) {
Richard Hendersond2565872013-01-04 16:39:32 -0800748 __put_user(k->_sa_handler, &oact->_sa_handler);
749 __put_user(k->sa_flags, &oact->sa_flags);
ths388bb212007-05-13 13:58:00 +0000750#if !defined(TARGET_MIPS)
Richard Hendersond2565872013-01-04 16:39:32 -0800751 __put_user(k->sa_restorer, &oact->sa_restorer);
ths388bb212007-05-13 13:58:00 +0000752#endif
Richard Hendersond2565872013-01-04 16:39:32 -0800753 /* Not swapped. */
pbrook624f7972008-05-31 16:11:38 +0000754 oact->sa_mask = k->sa_mask;
bellard66fb9762003-03-23 01:06:05 +0000755 }
756 if (act) {
pbrook624f7972008-05-31 16:11:38 +0000757 /* FIXME: This is not threadsafe. */
Richard Hendersond2565872013-01-04 16:39:32 -0800758 __get_user(k->_sa_handler, &act->_sa_handler);
759 __get_user(k->sa_flags, &act->sa_flags);
ths388bb212007-05-13 13:58:00 +0000760#if !defined(TARGET_MIPS)
Richard Hendersond2565872013-01-04 16:39:32 -0800761 __get_user(k->sa_restorer, &act->sa_restorer);
ths388bb212007-05-13 13:58:00 +0000762#endif
Richard Hendersond2565872013-01-04 16:39:32 -0800763 /* To be swapped in target_to_host_sigset. */
pbrook624f7972008-05-31 16:11:38 +0000764 k->sa_mask = act->sa_mask;
bellard773b93e2004-01-04 17:15:59 +0000765
766 /* we update the host linux signal state */
767 host_sig = target_to_host_signal(sig);
768 if (host_sig != SIGSEGV && host_sig != SIGBUS) {
769 sigfillset(&act1.sa_mask);
770 act1.sa_flags = SA_SIGINFO;
pbrook624f7972008-05-31 16:11:38 +0000771 if (k->sa_flags & TARGET_SA_RESTART)
bellard773b93e2004-01-04 17:15:59 +0000772 act1.sa_flags |= SA_RESTART;
773 /* NOTE: it is important to update the host kernel signal
774 ignore state to avoid getting unexpected interrupted
775 syscalls */
pbrook624f7972008-05-31 16:11:38 +0000776 if (k->_sa_handler == TARGET_SIG_IGN) {
bellard773b93e2004-01-04 17:15:59 +0000777 act1.sa_sigaction = (void *)SIG_IGN;
pbrook624f7972008-05-31 16:11:38 +0000778 } else if (k->_sa_handler == TARGET_SIG_DFL) {
aurel32ca587a82008-12-18 22:44:13 +0000779 if (fatal_signal (sig))
780 act1.sa_sigaction = host_signal_handler;
781 else
782 act1.sa_sigaction = (void *)SIG_DFL;
bellard773b93e2004-01-04 17:15:59 +0000783 } else {
784 act1.sa_sigaction = host_signal_handler;
785 }
ths0da46a62007-10-20 20:23:07 +0000786 ret = sigaction(host_sig, &act1, NULL);
bellard773b93e2004-01-04 17:15:59 +0000787 }
bellard66fb9762003-03-23 01:06:05 +0000788 }
ths0da46a62007-10-20 20:23:07 +0000789 return ret;
bellard66fb9762003-03-23 01:06:05 +0000790}
bellard31e31b82003-02-18 22:55:36 +0000791
bellard459a4012007-11-11 19:45:10 +0000792#if defined(TARGET_I386) && TARGET_ABI_BITS == 32
bellard66fb9762003-03-23 01:06:05 +0000793
794/* from the Linux kernel */
795
796struct target_fpreg {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100797 uint16_t significand[4];
798 uint16_t exponent;
bellard66fb9762003-03-23 01:06:05 +0000799};
800
801struct target_fpxreg {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100802 uint16_t significand[4];
803 uint16_t exponent;
804 uint16_t padding[3];
bellard66fb9762003-03-23 01:06:05 +0000805};
806
807struct target_xmmreg {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100808 abi_ulong element[4];
bellard66fb9762003-03-23 01:06:05 +0000809};
810
811struct target_fpstate {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100812 /* Regular FPU environment */
813 abi_ulong cw;
814 abi_ulong sw;
815 abi_ulong tag;
816 abi_ulong ipoff;
817 abi_ulong cssel;
818 abi_ulong dataoff;
819 abi_ulong datasel;
820 struct target_fpreg _st[8];
821 uint16_t status;
822 uint16_t magic; /* 0xffff = regular FPU data only */
bellard66fb9762003-03-23 01:06:05 +0000823
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100824 /* FXSR FPU environment */
825 abi_ulong _fxsr_env[6]; /* FXSR FPU env is ignored */
826 abi_ulong mxcsr;
827 abi_ulong reserved;
828 struct target_fpxreg _fxsr_st[8]; /* FXSR FPU reg data is ignored */
829 struct target_xmmreg _xmm[8];
830 abi_ulong padding[56];
bellard66fb9762003-03-23 01:06:05 +0000831};
832
833#define X86_FXSR_MAGIC 0x0000
834
835struct target_sigcontext {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100836 uint16_t gs, __gsh;
837 uint16_t fs, __fsh;
838 uint16_t es, __esh;
839 uint16_t ds, __dsh;
840 abi_ulong edi;
841 abi_ulong esi;
842 abi_ulong ebp;
843 abi_ulong esp;
844 abi_ulong ebx;
845 abi_ulong edx;
846 abi_ulong ecx;
847 abi_ulong eax;
848 abi_ulong trapno;
849 abi_ulong err;
850 abi_ulong eip;
851 uint16_t cs, __csh;
852 abi_ulong eflags;
853 abi_ulong esp_at_signal;
854 uint16_t ss, __ssh;
855 abi_ulong fpstate; /* pointer */
856 abi_ulong oldmask;
857 abi_ulong cr2;
bellard66fb9762003-03-23 01:06:05 +0000858};
859
bellard66fb9762003-03-23 01:06:05 +0000860struct target_ucontext {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100861 abi_ulong tuc_flags;
862 abi_ulong tuc_link;
863 target_stack_t tuc_stack;
864 struct target_sigcontext tuc_mcontext;
865 target_sigset_t tuc_sigmask; /* mask last for extensibility */
bellard66fb9762003-03-23 01:06:05 +0000866};
867
868struct sigframe
869{
blueswir1992f48a2007-10-14 16:27:31 +0000870 abi_ulong pretcode;
bellard66fb9762003-03-23 01:06:05 +0000871 int sig;
872 struct target_sigcontext sc;
873 struct target_fpstate fpstate;
blueswir1992f48a2007-10-14 16:27:31 +0000874 abi_ulong extramask[TARGET_NSIG_WORDS-1];
bellard66fb9762003-03-23 01:06:05 +0000875 char retcode[8];
876};
877
878struct rt_sigframe
879{
blueswir1992f48a2007-10-14 16:27:31 +0000880 abi_ulong pretcode;
bellard66fb9762003-03-23 01:06:05 +0000881 int sig;
blueswir1992f48a2007-10-14 16:27:31 +0000882 abi_ulong pinfo;
883 abi_ulong puc;
bellard66fb9762003-03-23 01:06:05 +0000884 struct target_siginfo info;
885 struct target_ucontext uc;
886 struct target_fpstate fpstate;
887 char retcode[8];
888};
889
890/*
891 * Set up a signal frame.
892 */
893
bellard66fb9762003-03-23 01:06:05 +0000894/* XXX: save x87 state */
Riku Voipio41ecc722014-04-23 11:01:00 +0300895static void setup_sigcontext(struct target_sigcontext *sc,
896 struct target_fpstate *fpstate, CPUX86State *env, abi_ulong mask,
897 abi_ulong fpstate_addr)
bellard66fb9762003-03-23 01:06:05 +0000898{
Andreas Färber27103422013-08-26 08:31:06 +0200899 CPUState *cs = CPU(x86_env_get_cpu(env));
Andreas Färber27103422013-08-26 08:31:06 +0200900 uint16_t magic;
bellard66fb9762003-03-23 01:06:05 +0000901
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100902 /* already locked in setup_frame() */
Riku Voipio1d8b5122014-04-23 10:26:05 +0300903 __put_user(env->segs[R_GS].selector, (unsigned int *)&sc->gs);
904 __put_user(env->segs[R_FS].selector, (unsigned int *)&sc->fs);
905 __put_user(env->segs[R_ES].selector, (unsigned int *)&sc->es);
906 __put_user(env->segs[R_DS].selector, (unsigned int *)&sc->ds);
907 __put_user(env->regs[R_EDI], &sc->edi);
908 __put_user(env->regs[R_ESI], &sc->esi);
909 __put_user(env->regs[R_EBP], &sc->ebp);
910 __put_user(env->regs[R_ESP], &sc->esp);
911 __put_user(env->regs[R_EBX], &sc->ebx);
912 __put_user(env->regs[R_EDX], &sc->edx);
913 __put_user(env->regs[R_ECX], &sc->ecx);
914 __put_user(env->regs[R_EAX], &sc->eax);
915 __put_user(cs->exception_index, &sc->trapno);
916 __put_user(env->error_code, &sc->err);
917 __put_user(env->eip, &sc->eip);
918 __put_user(env->segs[R_CS].selector, (unsigned int *)&sc->cs);
919 __put_user(env->eflags, &sc->eflags);
920 __put_user(env->regs[R_ESP], &sc->esp_at_signal);
921 __put_user(env->segs[R_SS].selector, (unsigned int *)&sc->ss);
bellarded2dcdf2003-05-29 20:06:27 +0000922
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100923 cpu_x86_fsave(env, fpstate_addr, 1);
924 fpstate->status = fpstate->sw;
925 magic = 0xffff;
Riku Voipio1d8b5122014-04-23 10:26:05 +0300926 __put_user(magic, &fpstate->magic);
927 __put_user(fpstate_addr, &sc->fpstate);
bellarded2dcdf2003-05-29 20:06:27 +0000928
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100929 /* non-iBCS2 extensions.. */
Riku Voipio1d8b5122014-04-23 10:26:05 +0300930 __put_user(mask, &sc->oldmask);
931 __put_user(env->cr[2], &sc->cr2);
bellard66fb9762003-03-23 01:06:05 +0000932}
933
934/*
935 * Determine which stack to use..
936 */
937
bellard579a97f2007-11-11 14:26:47 +0000938static inline abi_ulong
pbrook624f7972008-05-31 16:11:38 +0000939get_sigframe(struct target_sigaction *ka, CPUX86State *env, size_t frame_size)
bellard66fb9762003-03-23 01:06:05 +0000940{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100941 unsigned long esp;
bellard66fb9762003-03-23 01:06:05 +0000942
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100943 /* Default to using normal stack */
944 esp = env->regs[R_ESP];
945 /* This is the X/Open sanctioned signal stack switching. */
946 if (ka->sa_flags & TARGET_SA_ONSTACK) {
947 if (sas_ss_flags(esp) == 0) {
948 esp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
thsa04e1342007-09-27 13:57:58 +0000949 }
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100950 } else {
bellard66fb9762003-03-23 01:06:05 +0000951
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100952 /* This is the legacy signal stack switching. */
bellarda52c7572003-06-21 13:14:12 +0000953 if ((env->segs[R_SS].selector & 0xffff) != __USER_DS &&
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100954 !(ka->sa_flags & TARGET_SA_RESTORER) &&
955 ka->sa_restorer) {
pbrook624f7972008-05-31 16:11:38 +0000956 esp = (unsigned long) ka->sa_restorer;
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100957 }
958 }
959 return (esp - frame_size) & -8ul;
bellard66fb9762003-03-23 01:06:05 +0000960}
961
bellard579a97f2007-11-11 14:26:47 +0000962/* compare linux/arch/i386/kernel/signal.c:setup_frame() */
pbrook624f7972008-05-31 16:11:38 +0000963static void setup_frame(int sig, struct target_sigaction *ka,
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100964 target_sigset_t *set, CPUX86State *env)
bellard66fb9762003-03-23 01:06:05 +0000965{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100966 abi_ulong frame_addr;
967 struct sigframe *frame;
968 int i;
bellard66fb9762003-03-23 01:06:05 +0000969
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100970 frame_addr = get_sigframe(ka, env, sizeof(*frame));
971 trace_user_setup_frame(env, frame_addr);
bellard66fb9762003-03-23 01:06:05 +0000972
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100973 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
974 goto give_sigsegv;
bellard579a97f2007-11-11 14:26:47 +0000975
Peter Maydellb6e2c932015-01-08 12:19:43 +0000976 __put_user(sig, &frame->sig);
bellard66fb9762003-03-23 01:06:05 +0000977
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100978 setup_sigcontext(&frame->sc, &frame->fpstate, env, set->sig[0],
979 frame_addr + offsetof(struct sigframe, fpstate));
bellard66fb9762003-03-23 01:06:05 +0000980
Riku Voipio7df2fa32014-04-23 10:34:53 +0300981 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
982 __put_user(set->sig[i], &frame->extramask[i - 1]);
983 }
bellard66fb9762003-03-23 01:06:05 +0000984
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100985 /* Set up to return from userspace. If provided, use a stub
986 already in userspace. */
987 if (ka->sa_flags & TARGET_SA_RESTORER) {
Riku Voipio1d8b5122014-04-23 10:26:05 +0300988 __put_user(ka->sa_restorer, &frame->pretcode);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100989 } else {
990 uint16_t val16;
991 abi_ulong retcode_addr;
992 retcode_addr = frame_addr + offsetof(struct sigframe, retcode);
Riku Voipio1d8b5122014-04-23 10:26:05 +0300993 __put_user(retcode_addr, &frame->pretcode);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100994 /* This is popl %eax ; movl $,%eax ; int $0x80 */
995 val16 = 0xb858;
Riku Voipio1d8b5122014-04-23 10:26:05 +0300996 __put_user(val16, (uint16_t *)(frame->retcode+0));
997 __put_user(TARGET_NR_sigreturn, (int *)(frame->retcode+2));
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100998 val16 = 0x80cd;
Riku Voipio1d8b5122014-04-23 10:26:05 +0300999 __put_user(val16, (uint16_t *)(frame->retcode+6));
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001000 }
bellard66fb9762003-03-23 01:06:05 +00001001
bellard66fb9762003-03-23 01:06:05 +00001002
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001003 /* Set up registers for signal handler */
1004 env->regs[R_ESP] = frame_addr;
1005 env->eip = ka->_sa_handler;
bellard66fb9762003-03-23 01:06:05 +00001006
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001007 cpu_x86_load_seg(env, R_DS, __USER_DS);
1008 cpu_x86_load_seg(env, R_ES, __USER_DS);
1009 cpu_x86_load_seg(env, R_SS, __USER_DS);
1010 cpu_x86_load_seg(env, R_CS, __USER_CS);
1011 env->eflags &= ~TF_MASK;
bellard66fb9762003-03-23 01:06:05 +00001012
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001013 unlock_user_struct(frame, frame_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00001014
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001015 return;
bellard66fb9762003-03-23 01:06:05 +00001016
1017give_sigsegv:
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001018 if (sig == TARGET_SIGSEGV) {
1019 ka->_sa_handler = TARGET_SIG_DFL;
1020 }
1021 force_sig(TARGET_SIGSEGV /* , current */);
bellard66fb9762003-03-23 01:06:05 +00001022}
1023
bellard579a97f2007-11-11 14:26:47 +00001024/* compare linux/arch/i386/kernel/signal.c:setup_rt_frame() */
pbrook624f7972008-05-31 16:11:38 +00001025static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05001026 target_siginfo_t *info,
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001027 target_sigset_t *set, CPUX86State *env)
bellard66fb9762003-03-23 01:06:05 +00001028{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001029 abi_ulong frame_addr, addr;
1030 struct rt_sigframe *frame;
1031 int i;
bellard66fb9762003-03-23 01:06:05 +00001032
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001033 frame_addr = get_sigframe(ka, env, sizeof(*frame));
1034 trace_user_setup_rt_frame(env, frame_addr);
bellard66fb9762003-03-23 01:06:05 +00001035
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001036 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
1037 goto give_sigsegv;
bellard66fb9762003-03-23 01:06:05 +00001038
Peter Maydellb6e2c932015-01-08 12:19:43 +00001039 __put_user(sig, &frame->sig);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001040 addr = frame_addr + offsetof(struct rt_sigframe, info);
Riku Voipio1d8b5122014-04-23 10:26:05 +03001041 __put_user(addr, &frame->pinfo);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001042 addr = frame_addr + offsetof(struct rt_sigframe, uc);
Riku Voipio1d8b5122014-04-23 10:26:05 +03001043 __put_user(addr, &frame->puc);
Peter Maydellf6c7a052015-01-08 12:19:48 +00001044 tswap_siginfo(&frame->info, info);
bellard66fb9762003-03-23 01:06:05 +00001045
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001046 /* Create the ucontext. */
Riku Voipio1d8b5122014-04-23 10:26:05 +03001047 __put_user(0, &frame->uc.tuc_flags);
1048 __put_user(0, &frame->uc.tuc_link);
1049 __put_user(target_sigaltstack_used.ss_sp, &frame->uc.tuc_stack.ss_sp);
1050 __put_user(sas_ss_flags(get_sp_from_cpustate(env)),
1051 &frame->uc.tuc_stack.ss_flags);
1052 __put_user(target_sigaltstack_used.ss_size,
1053 &frame->uc.tuc_stack.ss_size);
Riku Voipio41ecc722014-04-23 11:01:00 +03001054 setup_sigcontext(&frame->uc.tuc_mcontext, &frame->fpstate, env,
1055 set->sig[0], frame_addr + offsetof(struct rt_sigframe, fpstate));
1056
Riku Voipio0188fad2014-04-23 13:34:15 +03001057 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
1058 __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
1059 }
bellard66fb9762003-03-23 01:06:05 +00001060
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001061 /* Set up to return from userspace. If provided, use a stub
1062 already in userspace. */
1063 if (ka->sa_flags & TARGET_SA_RESTORER) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03001064 __put_user(ka->sa_restorer, &frame->pretcode);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001065 } else {
1066 uint16_t val16;
1067 addr = frame_addr + offsetof(struct rt_sigframe, retcode);
Riku Voipio1d8b5122014-04-23 10:26:05 +03001068 __put_user(addr, &frame->pretcode);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001069 /* This is movl $,%eax ; int $0x80 */
Riku Voipio1d8b5122014-04-23 10:26:05 +03001070 __put_user(0xb8, (char *)(frame->retcode+0));
1071 __put_user(TARGET_NR_rt_sigreturn, (int *)(frame->retcode+1));
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001072 val16 = 0x80cd;
Riku Voipio1d8b5122014-04-23 10:26:05 +03001073 __put_user(val16, (uint16_t *)(frame->retcode+5));
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001074 }
bellard66fb9762003-03-23 01:06:05 +00001075
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001076 /* Set up registers for signal handler */
1077 env->regs[R_ESP] = frame_addr;
1078 env->eip = ka->_sa_handler;
bellard66fb9762003-03-23 01:06:05 +00001079
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001080 cpu_x86_load_seg(env, R_DS, __USER_DS);
1081 cpu_x86_load_seg(env, R_ES, __USER_DS);
1082 cpu_x86_load_seg(env, R_SS, __USER_DS);
1083 cpu_x86_load_seg(env, R_CS, __USER_CS);
1084 env->eflags &= ~TF_MASK;
bellard66fb9762003-03-23 01:06:05 +00001085
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001086 unlock_user_struct(frame, frame_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00001087
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001088 return;
bellard66fb9762003-03-23 01:06:05 +00001089
1090give_sigsegv:
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001091 if (sig == TARGET_SIGSEGV) {
1092 ka->_sa_handler = TARGET_SIG_DFL;
1093 }
1094 force_sig(TARGET_SIGSEGV /* , current */);
bellard66fb9762003-03-23 01:06:05 +00001095}
1096
1097static int
Timothy E Baldwin0284b032016-05-12 18:47:30 +01001098restore_sigcontext(CPUX86State *env, struct target_sigcontext *sc)
bellard66fb9762003-03-23 01:06:05 +00001099{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001100 unsigned int err = 0;
1101 abi_ulong fpstate_addr;
1102 unsigned int tmpflags;
bellard66fb9762003-03-23 01:06:05 +00001103
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001104 cpu_x86_load_seg(env, R_GS, tswap16(sc->gs));
1105 cpu_x86_load_seg(env, R_FS, tswap16(sc->fs));
1106 cpu_x86_load_seg(env, R_ES, tswap16(sc->es));
1107 cpu_x86_load_seg(env, R_DS, tswap16(sc->ds));
bellard66fb9762003-03-23 01:06:05 +00001108
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001109 env->regs[R_EDI] = tswapl(sc->edi);
1110 env->regs[R_ESI] = tswapl(sc->esi);
1111 env->regs[R_EBP] = tswapl(sc->ebp);
1112 env->regs[R_ESP] = tswapl(sc->esp);
1113 env->regs[R_EBX] = tswapl(sc->ebx);
1114 env->regs[R_EDX] = tswapl(sc->edx);
1115 env->regs[R_ECX] = tswapl(sc->ecx);
Timothy E Baldwin0284b032016-05-12 18:47:30 +01001116 env->regs[R_EAX] = tswapl(sc->eax);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001117 env->eip = tswapl(sc->eip);
bellard66fb9762003-03-23 01:06:05 +00001118
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001119 cpu_x86_load_seg(env, R_CS, lduw_p(&sc->cs) | 3);
1120 cpu_x86_load_seg(env, R_SS, lduw_p(&sc->ss) | 3);
ths5fafdf22007-09-16 21:08:06 +00001121
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001122 tmpflags = tswapl(sc->eflags);
1123 env->eflags = (env->eflags & ~0x40DD5) | (tmpflags & 0x40DD5);
1124 // regs->orig_eax = -1; /* disable syscall checks */
bellard28be6232007-11-11 22:23:38 +00001125
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001126 fpstate_addr = tswapl(sc->fpstate);
1127 if (fpstate_addr != 0) {
1128 if (!access_ok(VERIFY_READ, fpstate_addr,
1129 sizeof(struct target_fpstate)))
1130 goto badframe;
1131 cpu_x86_frstor(env, fpstate_addr, 1);
1132 }
bellard66fb9762003-03-23 01:06:05 +00001133
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001134 return err;
bellard66fb9762003-03-23 01:06:05 +00001135badframe:
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001136 return 1;
bellard66fb9762003-03-23 01:06:05 +00001137}
1138
1139long do_sigreturn(CPUX86State *env)
1140{
bellard579a97f2007-11-11 14:26:47 +00001141 struct sigframe *frame;
1142 abi_ulong frame_addr = env->regs[R_ESP] - 8;
Anthony Liguoric227f092009-10-01 16:12:16 -05001143 target_sigset_t target_set;
bellard66fb9762003-03-23 01:06:05 +00001144 sigset_t set;
Timothy E Baldwin0284b032016-05-12 18:47:30 +01001145 int i;
bellard66fb9762003-03-23 01:06:05 +00001146
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01001147 trace_user_do_sigreturn(env, frame_addr);
bellard579a97f2007-11-11 14:26:47 +00001148 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
1149 goto badframe;
bellard66fb9762003-03-23 01:06:05 +00001150 /* set blocked signals */
Riku Voipiof5f601a2014-04-23 13:00:17 +03001151 __get_user(target_set.sig[0], &frame->sc.oldmask);
bellard92319442004-06-19 16:58:13 +00001152 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
Riku Voipiof5f601a2014-04-23 13:00:17 +03001153 __get_user(target_set.sig[i], &frame->extramask[i - 1]);
bellard92319442004-06-19 16:58:13 +00001154 }
bellard66fb9762003-03-23 01:06:05 +00001155
bellard92319442004-06-19 16:58:13 +00001156 target_to_host_sigset_internal(&set, &target_set);
Peter Maydell9eede5b2016-05-27 15:51:46 +01001157 set_sigmask(&set);
ths3b46e622007-09-17 08:09:54 +00001158
bellard66fb9762003-03-23 01:06:05 +00001159 /* restore registers */
Timothy E Baldwin0284b032016-05-12 18:47:30 +01001160 if (restore_sigcontext(env, &frame->sc))
bellard66fb9762003-03-23 01:06:05 +00001161 goto badframe;
bellard579a97f2007-11-11 14:26:47 +00001162 unlock_user_struct(frame, frame_addr, 0);
Timothy E Baldwin0284b032016-05-12 18:47:30 +01001163 return -TARGET_QEMU_ESIGRETURN;
bellard66fb9762003-03-23 01:06:05 +00001164
1165badframe:
bellard579a97f2007-11-11 14:26:47 +00001166 unlock_user_struct(frame, frame_addr, 0);
bellard66fb9762003-03-23 01:06:05 +00001167 force_sig(TARGET_SIGSEGV);
1168 return 0;
1169}
1170
1171long do_rt_sigreturn(CPUX86State *env)
1172{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001173 abi_ulong frame_addr;
1174 struct rt_sigframe *frame;
1175 sigset_t set;
bellard66fb9762003-03-23 01:06:05 +00001176
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001177 frame_addr = env->regs[R_ESP] - 4;
1178 trace_user_do_rt_sigreturn(env, frame_addr);
1179 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
1180 goto badframe;
1181 target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
Peter Maydell9eede5b2016-05-27 15:51:46 +01001182 set_sigmask(&set);
ths5fafdf22007-09-16 21:08:06 +00001183
Timothy E Baldwin0284b032016-05-12 18:47:30 +01001184 if (restore_sigcontext(env, &frame->uc.tuc_mcontext)) {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001185 goto badframe;
1186 }
bellard66fb9762003-03-23 01:06:05 +00001187
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001188 if (do_sigaltstack(frame_addr + offsetof(struct rt_sigframe, uc.tuc_stack), 0,
1189 get_sp_from_cpustate(env)) == -EFAULT) {
1190 goto badframe;
1191 }
thsa04e1342007-09-27 13:57:58 +00001192
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001193 unlock_user_struct(frame, frame_addr, 0);
Timothy E Baldwin0284b032016-05-12 18:47:30 +01001194 return -TARGET_QEMU_ESIGRETURN;
bellard66fb9762003-03-23 01:06:05 +00001195
1196badframe:
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001197 unlock_user_struct(frame, frame_addr, 0);
1198 force_sig(TARGET_SIGSEGV);
1199 return 0;
bellard66fb9762003-03-23 01:06:05 +00001200}
1201
Andreas Schwab1744aea2013-09-03 20:12:16 +01001202#elif defined(TARGET_AARCH64)
1203
1204struct target_sigcontext {
1205 uint64_t fault_address;
1206 /* AArch64 registers */
1207 uint64_t regs[31];
1208 uint64_t sp;
1209 uint64_t pc;
1210 uint64_t pstate;
1211 /* 4K reserved for FP/SIMD state and future expansion */
1212 char __reserved[4096] __attribute__((__aligned__(16)));
1213};
1214
1215struct target_ucontext {
1216 abi_ulong tuc_flags;
1217 abi_ulong tuc_link;
1218 target_stack_t tuc_stack;
1219 target_sigset_t tuc_sigmask;
1220 /* glibc uses a 1024-bit sigset_t */
1221 char __unused[1024 / 8 - sizeof(target_sigset_t)];
1222 /* last for future expansion */
1223 struct target_sigcontext tuc_mcontext;
1224};
1225
1226/*
1227 * Header to be used at the beginning of structures extending the user
1228 * context. Such structures must be placed after the rt_sigframe on the stack
1229 * and be 16-byte aligned. The last structure must be a dummy one with the
1230 * magic and size set to 0.
1231 */
1232struct target_aarch64_ctx {
1233 uint32_t magic;
1234 uint32_t size;
1235};
1236
1237#define TARGET_FPSIMD_MAGIC 0x46508001
1238
1239struct target_fpsimd_context {
1240 struct target_aarch64_ctx head;
1241 uint32_t fpsr;
1242 uint32_t fpcr;
1243 uint64_t vregs[32 * 2]; /* really uint128_t vregs[32] */
1244};
1245
1246/*
1247 * Auxiliary context saved in the sigcontext.__reserved array. Not exported to
1248 * user space as it will change with the addition of new context. User space
1249 * should check the magic/size information.
1250 */
1251struct target_aux_context {
1252 struct target_fpsimd_context fpsimd;
1253 /* additional context to be added before "end" */
1254 struct target_aarch64_ctx end;
1255};
1256
1257struct target_rt_sigframe {
1258 struct target_siginfo info;
1259 struct target_ucontext uc;
1260 uint64_t fp;
1261 uint64_t lr;
1262 uint32_t tramp[2];
1263};
1264
1265static int target_setup_sigframe(struct target_rt_sigframe *sf,
1266 CPUARMState *env, target_sigset_t *set)
1267{
1268 int i;
1269 struct target_aux_context *aux =
1270 (struct target_aux_context *)sf->uc.tuc_mcontext.__reserved;
1271
1272 /* set up the stack frame for unwinding */
1273 __put_user(env->xregs[29], &sf->fp);
1274 __put_user(env->xregs[30], &sf->lr);
1275
1276 for (i = 0; i < 31; i++) {
1277 __put_user(env->xregs[i], &sf->uc.tuc_mcontext.regs[i]);
1278 }
1279 __put_user(env->xregs[31], &sf->uc.tuc_mcontext.sp);
1280 __put_user(env->pc, &sf->uc.tuc_mcontext.pc);
Peter Maydelld3563122013-12-17 19:42:30 +00001281 __put_user(pstate_read(env), &sf->uc.tuc_mcontext.pstate);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001282
Peter Maydell7af03922014-05-01 18:36:17 +01001283 __put_user(env->exception.vaddress, &sf->uc.tuc_mcontext.fault_address);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001284
1285 for (i = 0; i < TARGET_NSIG_WORDS; i++) {
1286 __put_user(set->sig[i], &sf->uc.tuc_sigmask.sig[i]);
1287 }
1288
1289 for (i = 0; i < 32; i++) {
1290#ifdef TARGET_WORDS_BIGENDIAN
1291 __put_user(env->vfp.regs[i * 2], &aux->fpsimd.vregs[i * 2 + 1]);
1292 __put_user(env->vfp.regs[i * 2 + 1], &aux->fpsimd.vregs[i * 2]);
1293#else
1294 __put_user(env->vfp.regs[i * 2], &aux->fpsimd.vregs[i * 2]);
1295 __put_user(env->vfp.regs[i * 2 + 1], &aux->fpsimd.vregs[i * 2 + 1]);
1296#endif
1297 }
Will Newtone0ee1382014-01-04 22:15:48 +00001298 __put_user(vfp_get_fpsr(env), &aux->fpsimd.fpsr);
1299 __put_user(vfp_get_fpcr(env), &aux->fpsimd.fpcr);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001300 __put_user(TARGET_FPSIMD_MAGIC, &aux->fpsimd.head.magic);
1301 __put_user(sizeof(struct target_fpsimd_context),
1302 &aux->fpsimd.head.size);
1303
1304 /* set the "end" magic */
1305 __put_user(0, &aux->end.magic);
1306 __put_user(0, &aux->end.size);
1307
1308 return 0;
1309}
1310
1311static int target_restore_sigframe(CPUARMState *env,
1312 struct target_rt_sigframe *sf)
1313{
1314 sigset_t set;
1315 int i;
1316 struct target_aux_context *aux =
1317 (struct target_aux_context *)sf->uc.tuc_mcontext.__reserved;
Will Newtone0ee1382014-01-04 22:15:48 +00001318 uint32_t magic, size, fpsr, fpcr;
Peter Maydelld3563122013-12-17 19:42:30 +00001319 uint64_t pstate;
Andreas Schwab1744aea2013-09-03 20:12:16 +01001320
1321 target_to_host_sigset(&set, &sf->uc.tuc_sigmask);
Peter Maydell9eede5b2016-05-27 15:51:46 +01001322 set_sigmask(&set);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001323
1324 for (i = 0; i < 31; i++) {
1325 __get_user(env->xregs[i], &sf->uc.tuc_mcontext.regs[i]);
1326 }
1327
1328 __get_user(env->xregs[31], &sf->uc.tuc_mcontext.sp);
1329 __get_user(env->pc, &sf->uc.tuc_mcontext.pc);
Peter Maydelld3563122013-12-17 19:42:30 +00001330 __get_user(pstate, &sf->uc.tuc_mcontext.pstate);
1331 pstate_write(env, pstate);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001332
1333 __get_user(magic, &aux->fpsimd.head.magic);
1334 __get_user(size, &aux->fpsimd.head.size);
1335
1336 if (magic != TARGET_FPSIMD_MAGIC
1337 || size != sizeof(struct target_fpsimd_context)) {
1338 return 1;
1339 }
1340
Peter Maydell4cf23482014-03-02 19:36:38 +00001341 for (i = 0; i < 32; i++) {
1342#ifdef TARGET_WORDS_BIGENDIAN
1343 __get_user(env->vfp.regs[i * 2], &aux->fpsimd.vregs[i * 2 + 1]);
1344 __get_user(env->vfp.regs[i * 2 + 1], &aux->fpsimd.vregs[i * 2]);
1345#else
1346 __get_user(env->vfp.regs[i * 2], &aux->fpsimd.vregs[i * 2]);
1347 __get_user(env->vfp.regs[i * 2 + 1], &aux->fpsimd.vregs[i * 2 + 1]);
1348#endif
Andreas Schwab1744aea2013-09-03 20:12:16 +01001349 }
Will Newtone0ee1382014-01-04 22:15:48 +00001350 __get_user(fpsr, &aux->fpsimd.fpsr);
1351 vfp_set_fpsr(env, fpsr);
1352 __get_user(fpcr, &aux->fpsimd.fpcr);
1353 vfp_set_fpcr(env, fpcr);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001354
1355 return 0;
1356}
1357
1358static abi_ulong get_sigframe(struct target_sigaction *ka, CPUARMState *env)
1359{
1360 abi_ulong sp;
1361
1362 sp = env->xregs[31];
1363
1364 /*
1365 * This is the X/Open sanctioned signal stack switching.
1366 */
Riku Voipiob545f632014-07-15 17:01:55 +03001367 if ((ka->sa_flags & TARGET_SA_ONSTACK) && !sas_ss_flags(sp)) {
Andreas Schwab1744aea2013-09-03 20:12:16 +01001368 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
1369 }
1370
1371 sp = (sp - sizeof(struct target_rt_sigframe)) & ~15;
1372
1373 return sp;
1374}
1375
1376static void target_setup_frame(int usig, struct target_sigaction *ka,
1377 target_siginfo_t *info, target_sigset_t *set,
1378 CPUARMState *env)
1379{
1380 struct target_rt_sigframe *frame;
Michael Matz8a3ae912014-03-02 19:36:39 +00001381 abi_ulong frame_addr, return_addr;
Andreas Schwab1744aea2013-09-03 20:12:16 +01001382
1383 frame_addr = get_sigframe(ka, env);
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01001384 trace_user_setup_frame(env, frame_addr);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001385 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
1386 goto give_sigsegv;
1387 }
1388
1389 __put_user(0, &frame->uc.tuc_flags);
1390 __put_user(0, &frame->uc.tuc_link);
1391
1392 __put_user(target_sigaltstack_used.ss_sp,
1393 &frame->uc.tuc_stack.ss_sp);
1394 __put_user(sas_ss_flags(env->xregs[31]),
1395 &frame->uc.tuc_stack.ss_flags);
1396 __put_user(target_sigaltstack_used.ss_size,
1397 &frame->uc.tuc_stack.ss_size);
1398 target_setup_sigframe(frame, env, set);
Michael Matz8a3ae912014-03-02 19:36:39 +00001399 if (ka->sa_flags & TARGET_SA_RESTORER) {
1400 return_addr = ka->sa_restorer;
1401 } else {
1402 /* mov x8,#__NR_rt_sigreturn; svc #0 */
1403 __put_user(0xd2801168, &frame->tramp[0]);
1404 __put_user(0xd4000001, &frame->tramp[1]);
1405 return_addr = frame_addr + offsetof(struct target_rt_sigframe, tramp);
1406 }
Andreas Schwab1744aea2013-09-03 20:12:16 +01001407 env->xregs[0] = usig;
1408 env->xregs[31] = frame_addr;
1409 env->xregs[29] = env->xregs[31] + offsetof(struct target_rt_sigframe, fp);
1410 env->pc = ka->_sa_handler;
Michael Matz8a3ae912014-03-02 19:36:39 +00001411 env->xregs[30] = return_addr;
Andreas Schwab1744aea2013-09-03 20:12:16 +01001412 if (info) {
Peter Maydellf6c7a052015-01-08 12:19:48 +00001413 tswap_siginfo(&frame->info, info);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001414 env->xregs[1] = frame_addr + offsetof(struct target_rt_sigframe, info);
1415 env->xregs[2] = frame_addr + offsetof(struct target_rt_sigframe, uc);
1416 }
1417
1418 unlock_user_struct(frame, frame_addr, 1);
1419 return;
1420
1421 give_sigsegv:
1422 unlock_user_struct(frame, frame_addr, 1);
1423 force_sig(TARGET_SIGSEGV);
1424}
1425
1426static void setup_rt_frame(int sig, struct target_sigaction *ka,
1427 target_siginfo_t *info, target_sigset_t *set,
1428 CPUARMState *env)
1429{
1430 target_setup_frame(sig, ka, info, set, env);
1431}
1432
1433static void setup_frame(int sig, struct target_sigaction *ka,
1434 target_sigset_t *set, CPUARMState *env)
1435{
1436 target_setup_frame(sig, ka, 0, set, env);
1437}
1438
1439long do_rt_sigreturn(CPUARMState *env)
1440{
Peter Maydell7f72cd22014-03-12 13:06:00 +00001441 struct target_rt_sigframe *frame = NULL;
Andreas Schwab1744aea2013-09-03 20:12:16 +01001442 abi_ulong frame_addr = env->xregs[31];
1443
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01001444 trace_user_do_rt_sigreturn(env, frame_addr);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001445 if (frame_addr & 15) {
1446 goto badframe;
1447 }
1448
1449 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
1450 goto badframe;
1451 }
1452
1453 if (target_restore_sigframe(env, frame)) {
1454 goto badframe;
1455 }
1456
1457 if (do_sigaltstack(frame_addr +
1458 offsetof(struct target_rt_sigframe, uc.tuc_stack),
1459 0, get_sp_from_cpustate(env)) == -EFAULT) {
1460 goto badframe;
1461 }
1462
1463 unlock_user_struct(frame, frame_addr, 0);
Timothy E Baldwinf0267ef2016-05-12 18:47:31 +01001464 return -TARGET_QEMU_ESIGRETURN;
Andreas Schwab1744aea2013-09-03 20:12:16 +01001465
1466 badframe:
1467 unlock_user_struct(frame, frame_addr, 0);
1468 force_sig(TARGET_SIGSEGV);
1469 return 0;
1470}
1471
1472long do_sigreturn(CPUARMState *env)
1473{
1474 return do_rt_sigreturn(env);
1475}
1476
bellard43fff232003-07-09 19:31:39 +00001477#elif defined(TARGET_ARM)
1478
1479struct target_sigcontext {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001480 abi_ulong trap_no;
1481 abi_ulong error_code;
1482 abi_ulong oldmask;
1483 abi_ulong arm_r0;
1484 abi_ulong arm_r1;
1485 abi_ulong arm_r2;
1486 abi_ulong arm_r3;
1487 abi_ulong arm_r4;
1488 abi_ulong arm_r5;
1489 abi_ulong arm_r6;
1490 abi_ulong arm_r7;
1491 abi_ulong arm_r8;
1492 abi_ulong arm_r9;
1493 abi_ulong arm_r10;
1494 abi_ulong arm_fp;
1495 abi_ulong arm_ip;
1496 abi_ulong arm_sp;
1497 abi_ulong arm_lr;
1498 abi_ulong arm_pc;
1499 abi_ulong arm_cpsr;
1500 abi_ulong fault_address;
bellard43fff232003-07-09 19:31:39 +00001501};
1502
pbrooka745ec62008-05-06 15:36:17 +00001503struct target_ucontext_v1 {
blueswir1992f48a2007-10-14 16:27:31 +00001504 abi_ulong tuc_flags;
1505 abi_ulong tuc_link;
Anthony Liguoric227f092009-10-01 16:12:16 -05001506 target_stack_t tuc_stack;
bellardb8076a72005-04-07 22:20:31 +00001507 struct target_sigcontext tuc_mcontext;
Anthony Liguoric227f092009-10-01 16:12:16 -05001508 target_sigset_t tuc_sigmask; /* mask last for extensibility */
bellard43fff232003-07-09 19:31:39 +00001509};
1510
pbrooka745ec62008-05-06 15:36:17 +00001511struct target_ucontext_v2 {
1512 abi_ulong tuc_flags;
1513 abi_ulong tuc_link;
Anthony Liguoric227f092009-10-01 16:12:16 -05001514 target_stack_t tuc_stack;
pbrooka745ec62008-05-06 15:36:17 +00001515 struct target_sigcontext tuc_mcontext;
Anthony Liguoric227f092009-10-01 16:12:16 -05001516 target_sigset_t tuc_sigmask; /* mask last for extensibility */
Peter Maydell5f0b7c82010-11-24 15:20:03 +00001517 char __unused[128 - sizeof(target_sigset_t)];
pbrooka745ec62008-05-06 15:36:17 +00001518 abi_ulong tuc_regspace[128] __attribute__((__aligned__(8)));
1519};
1520
Peter Maydell0d871bd2010-11-24 15:20:05 +00001521struct target_user_vfp {
1522 uint64_t fpregs[32];
1523 abi_ulong fpscr;
1524};
1525
1526struct target_user_vfp_exc {
1527 abi_ulong fpexc;
1528 abi_ulong fpinst;
1529 abi_ulong fpinst2;
1530};
1531
1532struct target_vfp_sigframe {
1533 abi_ulong magic;
1534 abi_ulong size;
1535 struct target_user_vfp ufp;
1536 struct target_user_vfp_exc ufp_exc;
1537} __attribute__((__aligned__(8)));
1538
Peter Maydell08e11252010-11-24 15:20:07 +00001539struct target_iwmmxt_sigframe {
1540 abi_ulong magic;
1541 abi_ulong size;
1542 uint64_t regs[16];
1543 /* Note that not all the coprocessor control registers are stored here */
1544 uint32_t wcssf;
1545 uint32_t wcasf;
1546 uint32_t wcgr0;
1547 uint32_t wcgr1;
1548 uint32_t wcgr2;
1549 uint32_t wcgr3;
1550} __attribute__((__aligned__(8)));
1551
Peter Maydell0d871bd2010-11-24 15:20:05 +00001552#define TARGET_VFP_MAGIC 0x56465001
Peter Maydell08e11252010-11-24 15:20:07 +00001553#define TARGET_IWMMXT_MAGIC 0x12ef842a
Peter Maydell0d871bd2010-11-24 15:20:05 +00001554
pbrooka8c33202008-05-07 23:22:46 +00001555struct sigframe_v1
bellard43fff232003-07-09 19:31:39 +00001556{
1557 struct target_sigcontext sc;
blueswir1992f48a2007-10-14 16:27:31 +00001558 abi_ulong extramask[TARGET_NSIG_WORDS-1];
1559 abi_ulong retcode;
bellard43fff232003-07-09 19:31:39 +00001560};
1561
pbrooka8c33202008-05-07 23:22:46 +00001562struct sigframe_v2
1563{
1564 struct target_ucontext_v2 uc;
1565 abi_ulong retcode;
1566};
1567
pbrooka745ec62008-05-06 15:36:17 +00001568struct rt_sigframe_v1
bellard43fff232003-07-09 19:31:39 +00001569{
bellardf8b0aa22007-11-11 23:03:42 +00001570 abi_ulong pinfo;
1571 abi_ulong puc;
bellard43fff232003-07-09 19:31:39 +00001572 struct target_siginfo info;
pbrooka745ec62008-05-06 15:36:17 +00001573 struct target_ucontext_v1 uc;
1574 abi_ulong retcode;
1575};
1576
1577struct rt_sigframe_v2
1578{
1579 struct target_siginfo info;
1580 struct target_ucontext_v2 uc;
blueswir1992f48a2007-10-14 16:27:31 +00001581 abi_ulong retcode;
bellard43fff232003-07-09 19:31:39 +00001582};
1583
1584#define TARGET_CONFIG_CPU_32 1
1585
1586/*
1587 * For ARM syscalls, we encode the syscall number into the instruction.
1588 */
1589#define SWI_SYS_SIGRETURN (0xef000000|(TARGET_NR_sigreturn + ARM_SYSCALL_BASE))
1590#define SWI_SYS_RT_SIGRETURN (0xef000000|(TARGET_NR_rt_sigreturn + ARM_SYSCALL_BASE))
1591
1592/*
1593 * For Thumb syscalls, we pass the syscall number via r7. We therefore
1594 * need two 16-bit instructions.
1595 */
1596#define SWI_THUMB_SIGRETURN (0xdf00 << 16 | 0x2700 | (TARGET_NR_sigreturn))
1597#define SWI_THUMB_RT_SIGRETURN (0xdf00 << 16 | 0x2700 | (TARGET_NR_rt_sigreturn))
1598
blueswir1992f48a2007-10-14 16:27:31 +00001599static const abi_ulong retcodes[4] = {
bellard43fff232003-07-09 19:31:39 +00001600 SWI_SYS_SIGRETURN, SWI_THUMB_SIGRETURN,
1601 SWI_SYS_RT_SIGRETURN, SWI_THUMB_RT_SIGRETURN
1602};
1603
1604
Andreas Färber05390242012-02-25 03:37:53 +01001605static inline int valid_user_regs(CPUARMState *regs)
bellard43fff232003-07-09 19:31:39 +00001606{
1607 return 1;
1608}
1609
pbrooka8c33202008-05-07 23:22:46 +00001610static void
bellard43fff232003-07-09 19:31:39 +00001611setup_sigcontext(struct target_sigcontext *sc, /*struct _fpstate *fpstate,*/
Andreas Färber05390242012-02-25 03:37:53 +01001612 CPUARMState *env, abi_ulong mask)
bellard43fff232003-07-09 19:31:39 +00001613{
Paolo Bonzinia0e1e6d2016-03-04 11:30:18 +00001614 __put_user(env->regs[0], &sc->arm_r0);
1615 __put_user(env->regs[1], &sc->arm_r1);
1616 __put_user(env->regs[2], &sc->arm_r2);
1617 __put_user(env->regs[3], &sc->arm_r3);
1618 __put_user(env->regs[4], &sc->arm_r4);
1619 __put_user(env->regs[5], &sc->arm_r5);
1620 __put_user(env->regs[6], &sc->arm_r6);
1621 __put_user(env->regs[7], &sc->arm_r7);
1622 __put_user(env->regs[8], &sc->arm_r8);
1623 __put_user(env->regs[9], &sc->arm_r9);
1624 __put_user(env->regs[10], &sc->arm_r10);
1625 __put_user(env->regs[11], &sc->arm_fp);
1626 __put_user(env->regs[12], &sc->arm_ip);
1627 __put_user(env->regs[13], &sc->arm_sp);
1628 __put_user(env->regs[14], &sc->arm_lr);
1629 __put_user(env->regs[15], &sc->arm_pc);
bellard43fff232003-07-09 19:31:39 +00001630#ifdef TARGET_CONFIG_CPU_32
Paolo Bonzinia0e1e6d2016-03-04 11:30:18 +00001631 __put_user(cpsr_read(env), &sc->arm_cpsr);
bellard43fff232003-07-09 19:31:39 +00001632#endif
1633
Paolo Bonzinia0e1e6d2016-03-04 11:30:18 +00001634 __put_user(/* current->thread.trap_no */ 0, &sc->trap_no);
1635 __put_user(/* current->thread.error_code */ 0, &sc->error_code);
1636 __put_user(/* current->thread.address */ 0, &sc->fault_address);
1637 __put_user(mask, &sc->oldmask);
bellard43fff232003-07-09 19:31:39 +00001638}
1639
bellard579a97f2007-11-11 14:26:47 +00001640static inline abi_ulong
Andreas Färber05390242012-02-25 03:37:53 +01001641get_sigframe(struct target_sigaction *ka, CPUARMState *regs, int framesize)
bellard43fff232003-07-09 19:31:39 +00001642{
Paolo Bonzinia0e1e6d2016-03-04 11:30:18 +00001643 unsigned long sp = regs->regs[13];
bellard43fff232003-07-09 19:31:39 +00001644
Paolo Bonzinia0e1e6d2016-03-04 11:30:18 +00001645 /*
1646 * This is the X/Open sanctioned signal stack switching.
1647 */
1648 if ((ka->sa_flags & TARGET_SA_ONSTACK) && !sas_ss_flags(sp)) {
1649 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
1650 }
1651 /*
1652 * ATPCS B01 mandates 8-byte alignment
1653 */
1654 return (sp - framesize) & ~7;
bellard43fff232003-07-09 19:31:39 +00001655}
1656
Riku Voipio0188fad2014-04-23 13:34:15 +03001657static void
Andreas Färber05390242012-02-25 03:37:53 +01001658setup_return(CPUARMState *env, struct target_sigaction *ka,
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001659 abi_ulong *rc, abi_ulong frame_addr, int usig, abi_ulong rc_addr)
bellard43fff232003-07-09 19:31:39 +00001660{
Paolo Bonzinia0e1e6d2016-03-04 11:30:18 +00001661 abi_ulong handler = ka->_sa_handler;
1662 abi_ulong retcode;
1663 int thumb = handler & 1;
1664 uint32_t cpsr = cpsr_read(env);
Peter Maydell964413d2011-01-14 20:39:19 +01001665
Paolo Bonzinia0e1e6d2016-03-04 11:30:18 +00001666 cpsr &= ~CPSR_IT;
1667 if (thumb) {
1668 cpsr |= CPSR_T;
1669 } else {
1670 cpsr &= ~CPSR_T;
1671 }
bellard43fff232003-07-09 19:31:39 +00001672
Paolo Bonzinia0e1e6d2016-03-04 11:30:18 +00001673 if (ka->sa_flags & TARGET_SA_RESTORER) {
1674 retcode = ka->sa_restorer;
1675 } else {
1676 unsigned int idx = thumb;
bellard43fff232003-07-09 19:31:39 +00001677
Paolo Bonzinia0e1e6d2016-03-04 11:30:18 +00001678 if (ka->sa_flags & TARGET_SA_SIGINFO) {
1679 idx += 2;
1680 }
bellard43fff232003-07-09 19:31:39 +00001681
Riku Voipio0188fad2014-04-23 13:34:15 +03001682 __put_user(retcodes[idx], rc);
Stefan Weilca8a2772011-10-03 22:43:19 +02001683
Paolo Bonzinia0e1e6d2016-03-04 11:30:18 +00001684 retcode = rc_addr + thumb;
1685 }
bellard43fff232003-07-09 19:31:39 +00001686
Paolo Bonzinia0e1e6d2016-03-04 11:30:18 +00001687 env->regs[0] = usig;
1688 env->regs[13] = frame_addr;
1689 env->regs[14] = retcode;
1690 env->regs[15] = handler & (thumb ? ~1 : ~3);
1691 cpsr_write(env, cpsr, CPSR_IT | CPSR_T, CPSRWriteByInstr);
bellard43fff232003-07-09 19:31:39 +00001692}
1693
Andreas Färber05390242012-02-25 03:37:53 +01001694static abi_ulong *setup_sigframe_v2_vfp(abi_ulong *regspace, CPUARMState *env)
Peter Maydell0d871bd2010-11-24 15:20:05 +00001695{
1696 int i;
1697 struct target_vfp_sigframe *vfpframe;
1698 vfpframe = (struct target_vfp_sigframe *)regspace;
1699 __put_user(TARGET_VFP_MAGIC, &vfpframe->magic);
1700 __put_user(sizeof(*vfpframe), &vfpframe->size);
1701 for (i = 0; i < 32; i++) {
Peter Maydell005e1a02011-02-10 13:59:35 +00001702 __put_user(float64_val(env->vfp.regs[i]), &vfpframe->ufp.fpregs[i]);
Peter Maydell0d871bd2010-11-24 15:20:05 +00001703 }
1704 __put_user(vfp_get_fpscr(env), &vfpframe->ufp.fpscr);
1705 __put_user(env->vfp.xregs[ARM_VFP_FPEXC], &vfpframe->ufp_exc.fpexc);
1706 __put_user(env->vfp.xregs[ARM_VFP_FPINST], &vfpframe->ufp_exc.fpinst);
1707 __put_user(env->vfp.xregs[ARM_VFP_FPINST2], &vfpframe->ufp_exc.fpinst2);
1708 return (abi_ulong*)(vfpframe+1);
1709}
1710
Andreas Färber05390242012-02-25 03:37:53 +01001711static abi_ulong *setup_sigframe_v2_iwmmxt(abi_ulong *regspace,
1712 CPUARMState *env)
Peter Maydell08e11252010-11-24 15:20:07 +00001713{
1714 int i;
1715 struct target_iwmmxt_sigframe *iwmmxtframe;
1716 iwmmxtframe = (struct target_iwmmxt_sigframe *)regspace;
1717 __put_user(TARGET_IWMMXT_MAGIC, &iwmmxtframe->magic);
1718 __put_user(sizeof(*iwmmxtframe), &iwmmxtframe->size);
1719 for (i = 0; i < 16; i++) {
1720 __put_user(env->iwmmxt.regs[i], &iwmmxtframe->regs[i]);
1721 }
1722 __put_user(env->vfp.xregs[ARM_IWMMXT_wCSSF], &iwmmxtframe->wcssf);
1723 __put_user(env->vfp.xregs[ARM_IWMMXT_wCASF], &iwmmxtframe->wcssf);
1724 __put_user(env->vfp.xregs[ARM_IWMMXT_wCGR0], &iwmmxtframe->wcgr0);
1725 __put_user(env->vfp.xregs[ARM_IWMMXT_wCGR1], &iwmmxtframe->wcgr1);
1726 __put_user(env->vfp.xregs[ARM_IWMMXT_wCGR2], &iwmmxtframe->wcgr2);
1727 __put_user(env->vfp.xregs[ARM_IWMMXT_wCGR3], &iwmmxtframe->wcgr3);
1728 return (abi_ulong*)(iwmmxtframe+1);
1729}
1730
pbrooka8c33202008-05-07 23:22:46 +00001731static void setup_sigframe_v2(struct target_ucontext_v2 *uc,
Andreas Färber05390242012-02-25 03:37:53 +01001732 target_sigset_t *set, CPUARMState *env)
bellard43fff232003-07-09 19:31:39 +00001733{
pbrooka8c33202008-05-07 23:22:46 +00001734 struct target_sigaltstack stack;
1735 int i;
Peter Maydell0d871bd2010-11-24 15:20:05 +00001736 abi_ulong *regspace;
pbrooka8c33202008-05-07 23:22:46 +00001737
1738 /* Clear all the bits of the ucontext we don't use. */
1739 memset(uc, 0, offsetof(struct target_ucontext_v2, tuc_mcontext));
1740
1741 memset(&stack, 0, sizeof(stack));
1742 __put_user(target_sigaltstack_used.ss_sp, &stack.ss_sp);
1743 __put_user(target_sigaltstack_used.ss_size, &stack.ss_size);
1744 __put_user(sas_ss_flags(get_sp_from_cpustate(env)), &stack.ss_flags);
1745 memcpy(&uc->tuc_stack, &stack, sizeof(stack));
1746
1747 setup_sigcontext(&uc->tuc_mcontext, env, set->sig[0]);
Peter Maydell0d871bd2010-11-24 15:20:05 +00001748 /* Save coprocessor signal frame. */
1749 regspace = uc->tuc_regspace;
1750 if (arm_feature(env, ARM_FEATURE_VFP)) {
1751 regspace = setup_sigframe_v2_vfp(regspace, env);
1752 }
Peter Maydell08e11252010-11-24 15:20:07 +00001753 if (arm_feature(env, ARM_FEATURE_IWMMXT)) {
1754 regspace = setup_sigframe_v2_iwmmxt(regspace, env);
1755 }
1756
Peter Maydell0d871bd2010-11-24 15:20:05 +00001757 /* Write terminating magic word */
1758 __put_user(0, regspace);
1759
pbrooka8c33202008-05-07 23:22:46 +00001760 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
1761 __put_user(set->sig[i], &uc->tuc_sigmask.sig[i]);
1762 }
1763}
1764
1765/* compare linux/arch/arm/kernel/signal.c:setup_frame() */
pbrook624f7972008-05-31 16:11:38 +00001766static void setup_frame_v1(int usig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01001767 target_sigset_t *set, CPUARMState *regs)
pbrooka8c33202008-05-07 23:22:46 +00001768{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001769 struct sigframe_v1 *frame;
1770 abi_ulong frame_addr = get_sigframe(ka, regs, sizeof(*frame));
1771 int i;
bellard43fff232003-07-09 19:31:39 +00001772
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001773 trace_user_setup_frame(regs, frame_addr);
1774 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
1775 return;
1776 }
bellard579a97f2007-11-11 14:26:47 +00001777
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001778 setup_sigcontext(&frame->sc, regs, set->sig[0]);
bellard43fff232003-07-09 19:31:39 +00001779
Riku Voipio0188fad2014-04-23 13:34:15 +03001780 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
1781 __put_user(set->sig[i], &frame->extramask[i - 1]);
1782 }
bellard43fff232003-07-09 19:31:39 +00001783
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001784 setup_return(regs, ka, &frame->retcode, frame_addr, usig,
1785 frame_addr + offsetof(struct sigframe_v1, retcode));
bellard579a97f2007-11-11 14:26:47 +00001786
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001787 unlock_user_struct(frame, frame_addr, 1);
pbrooka8c33202008-05-07 23:22:46 +00001788}
1789
pbrook624f7972008-05-31 16:11:38 +00001790static void setup_frame_v2(int usig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01001791 target_sigset_t *set, CPUARMState *regs)
pbrooka8c33202008-05-07 23:22:46 +00001792{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001793 struct sigframe_v2 *frame;
1794 abi_ulong frame_addr = get_sigframe(ka, regs, sizeof(*frame));
pbrooka8c33202008-05-07 23:22:46 +00001795
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001796 trace_user_setup_frame(regs, frame_addr);
1797 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
1798 return;
1799 }
pbrooka8c33202008-05-07 23:22:46 +00001800
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001801 setup_sigframe_v2(&frame->uc, set, regs);
pbrooka8c33202008-05-07 23:22:46 +00001802
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001803 setup_return(regs, ka, &frame->retcode, frame_addr, usig,
1804 frame_addr + offsetof(struct sigframe_v2, retcode));
pbrooka8c33202008-05-07 23:22:46 +00001805
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001806 unlock_user_struct(frame, frame_addr, 1);
pbrooka8c33202008-05-07 23:22:46 +00001807}
1808
pbrook624f7972008-05-31 16:11:38 +00001809static void setup_frame(int usig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01001810 target_sigset_t *set, CPUARMState *regs)
pbrooka8c33202008-05-07 23:22:46 +00001811{
1812 if (get_osversion() >= 0x020612) {
1813 setup_frame_v2(usig, ka, set, regs);
1814 } else {
1815 setup_frame_v1(usig, ka, set, regs);
1816 }
bellard43fff232003-07-09 19:31:39 +00001817}
1818
bellard579a97f2007-11-11 14:26:47 +00001819/* compare linux/arch/arm/kernel/signal.c:setup_rt_frame() */
pbrook624f7972008-05-31 16:11:38 +00001820static void setup_rt_frame_v1(int usig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05001821 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01001822 target_sigset_t *set, CPUARMState *env)
bellard43fff232003-07-09 19:31:39 +00001823{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001824 struct rt_sigframe_v1 *frame;
1825 abi_ulong frame_addr = get_sigframe(ka, env, sizeof(*frame));
1826 struct target_sigaltstack stack;
1827 int i;
1828 abi_ulong info_addr, uc_addr;
bellard43fff232003-07-09 19:31:39 +00001829
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001830 trace_user_setup_rt_frame(env, frame_addr);
1831 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
1832 return /* 1 */;
1833 }
bellardedf779f2004-02-22 13:40:13 +00001834
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001835 info_addr = frame_addr + offsetof(struct rt_sigframe_v1, info);
1836 __put_user(info_addr, &frame->pinfo);
1837 uc_addr = frame_addr + offsetof(struct rt_sigframe_v1, uc);
1838 __put_user(uc_addr, &frame->puc);
1839 tswap_siginfo(&frame->info, info);
bellard43fff232003-07-09 19:31:39 +00001840
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001841 /* Clear all the bits of the ucontext we don't use. */
1842 memset(&frame->uc, 0, offsetof(struct target_ucontext_v1, tuc_mcontext));
bellard43fff232003-07-09 19:31:39 +00001843
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001844 memset(&stack, 0, sizeof(stack));
1845 __put_user(target_sigaltstack_used.ss_sp, &stack.ss_sp);
1846 __put_user(target_sigaltstack_used.ss_size, &stack.ss_size);
1847 __put_user(sas_ss_flags(get_sp_from_cpustate(env)), &stack.ss_flags);
1848 memcpy(&frame->uc.tuc_stack, &stack, sizeof(stack));
thsa04e1342007-09-27 13:57:58 +00001849
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001850 setup_sigcontext(&frame->uc.tuc_mcontext, env, set->sig[0]);
1851 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
1852 __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
1853 }
bellard43fff232003-07-09 19:31:39 +00001854
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001855 setup_return(env, ka, &frame->retcode, frame_addr, usig,
1856 frame_addr + offsetof(struct rt_sigframe_v1, retcode));
pbrooka745ec62008-05-06 15:36:17 +00001857
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001858 env->regs[1] = info_addr;
1859 env->regs[2] = uc_addr;
pbrooka745ec62008-05-06 15:36:17 +00001860
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001861 unlock_user_struct(frame, frame_addr, 1);
pbrooka745ec62008-05-06 15:36:17 +00001862}
1863
pbrook624f7972008-05-31 16:11:38 +00001864static void setup_rt_frame_v2(int usig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05001865 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01001866 target_sigset_t *set, CPUARMState *env)
pbrooka745ec62008-05-06 15:36:17 +00001867{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001868 struct rt_sigframe_v2 *frame;
1869 abi_ulong frame_addr = get_sigframe(ka, env, sizeof(*frame));
1870 abi_ulong info_addr, uc_addr;
pbrooka745ec62008-05-06 15:36:17 +00001871
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001872 trace_user_setup_rt_frame(env, frame_addr);
1873 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
1874 return /* 1 */;
1875 }
pbrooka745ec62008-05-06 15:36:17 +00001876
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001877 info_addr = frame_addr + offsetof(struct rt_sigframe_v2, info);
1878 uc_addr = frame_addr + offsetof(struct rt_sigframe_v2, uc);
1879 tswap_siginfo(&frame->info, info);
pbrooka745ec62008-05-06 15:36:17 +00001880
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001881 setup_sigframe_v2(&frame->uc, set, env);
pbrooka745ec62008-05-06 15:36:17 +00001882
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001883 setup_return(env, ka, &frame->retcode, frame_addr, usig,
1884 frame_addr + offsetof(struct rt_sigframe_v2, retcode));
pbrooka745ec62008-05-06 15:36:17 +00001885
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001886 env->regs[1] = info_addr;
1887 env->regs[2] = uc_addr;
pbrooka745ec62008-05-06 15:36:17 +00001888
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001889 unlock_user_struct(frame, frame_addr, 1);
bellard43fff232003-07-09 19:31:39 +00001890}
1891
pbrook624f7972008-05-31 16:11:38 +00001892static void setup_rt_frame(int usig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05001893 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01001894 target_sigset_t *set, CPUARMState *env)
pbrooka745ec62008-05-06 15:36:17 +00001895{
1896 if (get_osversion() >= 0x020612) {
1897 setup_rt_frame_v2(usig, ka, info, set, env);
1898 } else {
1899 setup_rt_frame_v1(usig, ka, info, set, env);
1900 }
1901}
1902
bellard43fff232003-07-09 19:31:39 +00001903static int
Andreas Färber05390242012-02-25 03:37:53 +01001904restore_sigcontext(CPUARMState *env, struct target_sigcontext *sc)
bellard43fff232003-07-09 19:31:39 +00001905{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001906 int err = 0;
1907 uint32_t cpsr;
bellard43fff232003-07-09 19:31:39 +00001908
Riku Voipio1d8b5122014-04-23 10:26:05 +03001909 __get_user(env->regs[0], &sc->arm_r0);
1910 __get_user(env->regs[1], &sc->arm_r1);
1911 __get_user(env->regs[2], &sc->arm_r2);
1912 __get_user(env->regs[3], &sc->arm_r3);
1913 __get_user(env->regs[4], &sc->arm_r4);
1914 __get_user(env->regs[5], &sc->arm_r5);
1915 __get_user(env->regs[6], &sc->arm_r6);
1916 __get_user(env->regs[7], &sc->arm_r7);
1917 __get_user(env->regs[8], &sc->arm_r8);
1918 __get_user(env->regs[9], &sc->arm_r9);
1919 __get_user(env->regs[10], &sc->arm_r10);
1920 __get_user(env->regs[11], &sc->arm_fp);
1921 __get_user(env->regs[12], &sc->arm_ip);
1922 __get_user(env->regs[13], &sc->arm_sp);
1923 __get_user(env->regs[14], &sc->arm_lr);
1924 __get_user(env->regs[15], &sc->arm_pc);
bellard43fff232003-07-09 19:31:39 +00001925#ifdef TARGET_CONFIG_CPU_32
Riku Voipio1d8b5122014-04-23 10:26:05 +03001926 __get_user(cpsr, &sc->arm_cpsr);
Peter Maydell50866ba2016-02-23 15:36:43 +00001927 cpsr_write(env, cpsr, CPSR_USER | CPSR_EXEC, CPSRWriteByInstr);
bellard43fff232003-07-09 19:31:39 +00001928#endif
1929
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001930 err |= !valid_user_regs(env);
bellard43fff232003-07-09 19:31:39 +00001931
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001932 return err;
bellard43fff232003-07-09 19:31:39 +00001933}
1934
Andreas Färber05390242012-02-25 03:37:53 +01001935static long do_sigreturn_v1(CPUARMState *env)
bellard43fff232003-07-09 19:31:39 +00001936{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001937 abi_ulong frame_addr;
1938 struct sigframe_v1 *frame = NULL;
1939 target_sigset_t set;
1940 sigset_t host_set;
1941 int i;
bellard43fff232003-07-09 19:31:39 +00001942
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001943 /*
1944 * Since we stacked the signal on a 64-bit boundary,
1945 * then 'sp' should be word aligned here. If it's
1946 * not, then the user is trying to mess with us.
1947 */
1948 frame_addr = env->regs[13];
1949 trace_user_do_sigreturn(env, frame_addr);
1950 if (frame_addr & 7) {
1951 goto badframe;
1952 }
Peter Maydell978fae92013-07-29 12:00:32 +01001953
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001954 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
1955 goto badframe;
1956 }
bellard43fff232003-07-09 19:31:39 +00001957
Riku Voipiof5f601a2014-04-23 13:00:17 +03001958 __get_user(set.sig[0], &frame->sc.oldmask);
1959 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
1960 __get_user(set.sig[i], &frame->extramask[i - 1]);
1961 }
bellard43fff232003-07-09 19:31:39 +00001962
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001963 target_to_host_sigset_internal(&host_set, &set);
Peter Maydell9eede5b2016-05-27 15:51:46 +01001964 set_sigmask(&host_set);
bellard43fff232003-07-09 19:31:39 +00001965
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001966 if (restore_sigcontext(env, &frame->sc)) {
1967 goto badframe;
1968 }
bellard43fff232003-07-09 19:31:39 +00001969
1970#if 0
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001971 /* Send SIGTRAP if we're single-stepping */
1972 if (ptrace_cancel_bpt(current))
1973 send_sig(SIGTRAP, current, 1);
bellard43fff232003-07-09 19:31:39 +00001974#endif
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001975 unlock_user_struct(frame, frame_addr, 0);
Timothy E Baldwinf0267ef2016-05-12 18:47:31 +01001976 return -TARGET_QEMU_ESIGRETURN;
bellard43fff232003-07-09 19:31:39 +00001977
1978badframe:
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001979 force_sig(TARGET_SIGSEGV /* , current */);
1980 return 0;
bellard43fff232003-07-09 19:31:39 +00001981}
1982
Andreas Färber05390242012-02-25 03:37:53 +01001983static abi_ulong *restore_sigframe_v2_vfp(CPUARMState *env, abi_ulong *regspace)
Peter Maydell5f9099d2010-11-24 15:20:06 +00001984{
1985 int i;
1986 abi_ulong magic, sz;
1987 uint32_t fpscr, fpexc;
1988 struct target_vfp_sigframe *vfpframe;
1989 vfpframe = (struct target_vfp_sigframe *)regspace;
1990
1991 __get_user(magic, &vfpframe->magic);
1992 __get_user(sz, &vfpframe->size);
1993 if (magic != TARGET_VFP_MAGIC || sz != sizeof(*vfpframe)) {
1994 return 0;
1995 }
1996 for (i = 0; i < 32; i++) {
Peter Maydell005e1a02011-02-10 13:59:35 +00001997 __get_user(float64_val(env->vfp.regs[i]), &vfpframe->ufp.fpregs[i]);
Peter Maydell5f9099d2010-11-24 15:20:06 +00001998 }
1999 __get_user(fpscr, &vfpframe->ufp.fpscr);
2000 vfp_set_fpscr(env, fpscr);
2001 __get_user(fpexc, &vfpframe->ufp_exc.fpexc);
2002 /* Sanitise FPEXC: ensure VFP is enabled, FPINST2 is invalid
2003 * and the exception flag is cleared
2004 */
2005 fpexc |= (1 << 30);
2006 fpexc &= ~((1 << 31) | (1 << 28));
2007 env->vfp.xregs[ARM_VFP_FPEXC] = fpexc;
2008 __get_user(env->vfp.xregs[ARM_VFP_FPINST], &vfpframe->ufp_exc.fpinst);
2009 __get_user(env->vfp.xregs[ARM_VFP_FPINST2], &vfpframe->ufp_exc.fpinst2);
2010 return (abi_ulong*)(vfpframe + 1);
2011}
2012
Andreas Färber05390242012-02-25 03:37:53 +01002013static abi_ulong *restore_sigframe_v2_iwmmxt(CPUARMState *env,
2014 abi_ulong *regspace)
Peter Maydella59d69d2010-11-24 15:20:08 +00002015{
2016 int i;
2017 abi_ulong magic, sz;
2018 struct target_iwmmxt_sigframe *iwmmxtframe;
2019 iwmmxtframe = (struct target_iwmmxt_sigframe *)regspace;
2020
2021 __get_user(magic, &iwmmxtframe->magic);
2022 __get_user(sz, &iwmmxtframe->size);
2023 if (magic != TARGET_IWMMXT_MAGIC || sz != sizeof(*iwmmxtframe)) {
2024 return 0;
2025 }
2026 for (i = 0; i < 16; i++) {
2027 __get_user(env->iwmmxt.regs[i], &iwmmxtframe->regs[i]);
2028 }
2029 __get_user(env->vfp.xregs[ARM_IWMMXT_wCSSF], &iwmmxtframe->wcssf);
2030 __get_user(env->vfp.xregs[ARM_IWMMXT_wCASF], &iwmmxtframe->wcssf);
2031 __get_user(env->vfp.xregs[ARM_IWMMXT_wCGR0], &iwmmxtframe->wcgr0);
2032 __get_user(env->vfp.xregs[ARM_IWMMXT_wCGR1], &iwmmxtframe->wcgr1);
2033 __get_user(env->vfp.xregs[ARM_IWMMXT_wCGR2], &iwmmxtframe->wcgr2);
2034 __get_user(env->vfp.xregs[ARM_IWMMXT_wCGR3], &iwmmxtframe->wcgr3);
2035 return (abi_ulong*)(iwmmxtframe + 1);
2036}
2037
Andreas Färber05390242012-02-25 03:37:53 +01002038static int do_sigframe_return_v2(CPUARMState *env, target_ulong frame_addr,
pbrooka8c33202008-05-07 23:22:46 +00002039 struct target_ucontext_v2 *uc)
2040{
2041 sigset_t host_set;
Peter Maydell5f9099d2010-11-24 15:20:06 +00002042 abi_ulong *regspace;
pbrooka8c33202008-05-07 23:22:46 +00002043
2044 target_to_host_sigset(&host_set, &uc->tuc_sigmask);
Peter Maydell9eede5b2016-05-27 15:51:46 +01002045 set_sigmask(&host_set);
pbrooka8c33202008-05-07 23:22:46 +00002046
2047 if (restore_sigcontext(env, &uc->tuc_mcontext))
2048 return 1;
2049
Peter Maydell5f9099d2010-11-24 15:20:06 +00002050 /* Restore coprocessor signal frame */
2051 regspace = uc->tuc_regspace;
2052 if (arm_feature(env, ARM_FEATURE_VFP)) {
2053 regspace = restore_sigframe_v2_vfp(env, regspace);
2054 if (!regspace) {
2055 return 1;
2056 }
2057 }
Peter Maydella59d69d2010-11-24 15:20:08 +00002058 if (arm_feature(env, ARM_FEATURE_IWMMXT)) {
2059 regspace = restore_sigframe_v2_iwmmxt(env, regspace);
2060 if (!regspace) {
2061 return 1;
2062 }
2063 }
Peter Maydell5f9099d2010-11-24 15:20:06 +00002064
pbrooka8c33202008-05-07 23:22:46 +00002065 if (do_sigaltstack(frame_addr + offsetof(struct target_ucontext_v2, tuc_stack), 0, get_sp_from_cpustate(env)) == -EFAULT)
2066 return 1;
2067
2068#if 0
2069 /* Send SIGTRAP if we're single-stepping */
2070 if (ptrace_cancel_bpt(current))
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002071 send_sig(SIGTRAP, current, 1);
pbrooka8c33202008-05-07 23:22:46 +00002072#endif
2073
2074 return 0;
2075}
2076
Andreas Färber05390242012-02-25 03:37:53 +01002077static long do_sigreturn_v2(CPUARMState *env)
pbrooka8c33202008-05-07 23:22:46 +00002078{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002079 abi_ulong frame_addr;
2080 struct sigframe_v2 *frame = NULL;
pbrooka8c33202008-05-07 23:22:46 +00002081
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002082 /*
2083 * Since we stacked the signal on a 64-bit boundary,
2084 * then 'sp' should be word aligned here. If it's
2085 * not, then the user is trying to mess with us.
2086 */
2087 frame_addr = env->regs[13];
2088 trace_user_do_sigreturn(env, frame_addr);
2089 if (frame_addr & 7) {
2090 goto badframe;
2091 }
Peter Maydell978fae92013-07-29 12:00:32 +01002092
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002093 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
2094 goto badframe;
2095 }
pbrooka8c33202008-05-07 23:22:46 +00002096
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002097 if (do_sigframe_return_v2(env, frame_addr, &frame->uc)) {
2098 goto badframe;
2099 }
pbrooka8c33202008-05-07 23:22:46 +00002100
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002101 unlock_user_struct(frame, frame_addr, 0);
Timothy E Baldwinf0267ef2016-05-12 18:47:31 +01002102 return -TARGET_QEMU_ESIGRETURN;
pbrooka8c33202008-05-07 23:22:46 +00002103
2104badframe:
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002105 unlock_user_struct(frame, frame_addr, 0);
2106 force_sig(TARGET_SIGSEGV /* , current */);
2107 return 0;
pbrooka8c33202008-05-07 23:22:46 +00002108}
2109
Andreas Färber05390242012-02-25 03:37:53 +01002110long do_sigreturn(CPUARMState *env)
pbrooka8c33202008-05-07 23:22:46 +00002111{
2112 if (get_osversion() >= 0x020612) {
2113 return do_sigreturn_v2(env);
2114 } else {
2115 return do_sigreturn_v1(env);
2116 }
2117}
2118
Andreas Färber05390242012-02-25 03:37:53 +01002119static long do_rt_sigreturn_v1(CPUARMState *env)
bellard43fff232003-07-09 19:31:39 +00002120{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002121 abi_ulong frame_addr;
2122 struct rt_sigframe_v1 *frame = NULL;
2123 sigset_t host_set;
bellard43fff232003-07-09 19:31:39 +00002124
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002125 /*
2126 * Since we stacked the signal on a 64-bit boundary,
2127 * then 'sp' should be word aligned here. If it's
2128 * not, then the user is trying to mess with us.
2129 */
2130 frame_addr = env->regs[13];
2131 trace_user_do_rt_sigreturn(env, frame_addr);
2132 if (frame_addr & 7) {
2133 goto badframe;
2134 }
Peter Maydell978fae92013-07-29 12:00:32 +01002135
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002136 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
2137 goto badframe;
2138 }
bellard43fff232003-07-09 19:31:39 +00002139
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002140 target_to_host_sigset(&host_set, &frame->uc.tuc_sigmask);
Peter Maydell9eede5b2016-05-27 15:51:46 +01002141 set_sigmask(&host_set);
bellard43fff232003-07-09 19:31:39 +00002142
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002143 if (restore_sigcontext(env, &frame->uc.tuc_mcontext)) {
2144 goto badframe;
2145 }
bellard43fff232003-07-09 19:31:39 +00002146
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002147 if (do_sigaltstack(frame_addr + offsetof(struct rt_sigframe_v1, uc.tuc_stack), 0, get_sp_from_cpustate(env)) == -EFAULT)
2148 goto badframe;
thsa04e1342007-09-27 13:57:58 +00002149
bellard43fff232003-07-09 19:31:39 +00002150#if 0
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002151 /* Send SIGTRAP if we're single-stepping */
2152 if (ptrace_cancel_bpt(current))
2153 send_sig(SIGTRAP, current, 1);
bellard43fff232003-07-09 19:31:39 +00002154#endif
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002155 unlock_user_struct(frame, frame_addr, 0);
Timothy E Baldwinf0267ef2016-05-12 18:47:31 +01002156 return -TARGET_QEMU_ESIGRETURN;
bellard43fff232003-07-09 19:31:39 +00002157
2158badframe:
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002159 unlock_user_struct(frame, frame_addr, 0);
2160 force_sig(TARGET_SIGSEGV /* , current */);
2161 return 0;
bellard43fff232003-07-09 19:31:39 +00002162}
2163
Andreas Färber05390242012-02-25 03:37:53 +01002164static long do_rt_sigreturn_v2(CPUARMState *env)
pbrooka745ec62008-05-06 15:36:17 +00002165{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002166 abi_ulong frame_addr;
2167 struct rt_sigframe_v2 *frame = NULL;
pbrooka745ec62008-05-06 15:36:17 +00002168
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002169 /*
2170 * Since we stacked the signal on a 64-bit boundary,
2171 * then 'sp' should be word aligned here. If it's
2172 * not, then the user is trying to mess with us.
2173 */
2174 frame_addr = env->regs[13];
2175 trace_user_do_rt_sigreturn(env, frame_addr);
2176 if (frame_addr & 7) {
2177 goto badframe;
2178 }
Peter Maydell978fae92013-07-29 12:00:32 +01002179
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002180 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
2181 goto badframe;
2182 }
pbrooka745ec62008-05-06 15:36:17 +00002183
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002184 if (do_sigframe_return_v2(env, frame_addr, &frame->uc)) {
2185 goto badframe;
2186 }
pbrooka745ec62008-05-06 15:36:17 +00002187
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002188 unlock_user_struct(frame, frame_addr, 0);
Timothy E Baldwinf0267ef2016-05-12 18:47:31 +01002189 return -TARGET_QEMU_ESIGRETURN;
pbrooka745ec62008-05-06 15:36:17 +00002190
2191badframe:
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002192 unlock_user_struct(frame, frame_addr, 0);
2193 force_sig(TARGET_SIGSEGV /* , current */);
2194 return 0;
pbrooka745ec62008-05-06 15:36:17 +00002195}
2196
Andreas Färber05390242012-02-25 03:37:53 +01002197long do_rt_sigreturn(CPUARMState *env)
pbrooka745ec62008-05-06 15:36:17 +00002198{
2199 if (get_osversion() >= 0x020612) {
2200 return do_rt_sigreturn_v2(env);
2201 } else {
2202 return do_rt_sigreturn_v1(env);
2203 }
2204}
2205
bellard6d5e2162004-09-30 22:04:13 +00002206#elif defined(TARGET_SPARC)
bellard80a9d032005-01-03 23:31:27 +00002207
bellard6d5e2162004-09-30 22:04:13 +00002208#define __SUNOS_MAXWIN 31
2209
2210/* This is what SunOS does, so shall I. */
2211struct target_sigcontext {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002212 abi_ulong sigc_onstack; /* state to restore */
bellard6d5e2162004-09-30 22:04:13 +00002213
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002214 abi_ulong sigc_mask; /* sigmask to restore */
2215 abi_ulong sigc_sp; /* stack pointer */
2216 abi_ulong sigc_pc; /* program counter */
2217 abi_ulong sigc_npc; /* next program counter */
2218 abi_ulong sigc_psr; /* for condition codes etc */
2219 abi_ulong sigc_g1; /* User uses these two registers */
2220 abi_ulong sigc_o0; /* within the trampoline code. */
bellard6d5e2162004-09-30 22:04:13 +00002221
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002222 /* Now comes information regarding the users window set
bellard6d5e2162004-09-30 22:04:13 +00002223 * at the time of the signal.
2224 */
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002225 abi_ulong sigc_oswins; /* outstanding windows */
bellard6d5e2162004-09-30 22:04:13 +00002226
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002227 /* stack ptrs for each regwin buf */
2228 char *sigc_spbuf[__SUNOS_MAXWIN];
bellard6d5e2162004-09-30 22:04:13 +00002229
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002230 /* Windows to restore after signal */
2231 struct {
2232 abi_ulong locals[8];
2233 abi_ulong ins[8];
2234 } sigc_wbuf[__SUNOS_MAXWIN];
bellard6d5e2162004-09-30 22:04:13 +00002235};
2236/* A Sparc stack frame */
2237struct sparc_stackf {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002238 abi_ulong locals[8];
2239 abi_ulong ins[8];
2240 /* It's simpler to treat fp and callers_pc as elements of ins[]
Peter Maydelle321c342011-02-01 15:54:52 +00002241 * since we never need to access them ourselves.
2242 */
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002243 char *structptr;
2244 abi_ulong xargs[6];
2245 abi_ulong xxargs[1];
bellard6d5e2162004-09-30 22:04:13 +00002246};
2247
2248typedef struct {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002249 struct {
2250 abi_ulong psr;
2251 abi_ulong pc;
2252 abi_ulong npc;
2253 abi_ulong y;
2254 abi_ulong u_regs[16]; /* globals and ins */
2255 } si_regs;
2256 int si_mask;
bellard6d5e2162004-09-30 22:04:13 +00002257} __siginfo_t;
2258
2259typedef struct {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002260 abi_ulong si_float_regs[32];
2261 unsigned long si_fsr;
2262 unsigned long si_fpqdepth;
2263 struct {
2264 unsigned long *insn_addr;
2265 unsigned long insn;
2266 } si_fpqueue [16];
Anthony Liguoric227f092009-10-01 16:12:16 -05002267} qemu_siginfo_fpu_t;
bellard6d5e2162004-09-30 22:04:13 +00002268
2269
2270struct target_signal_frame {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002271 struct sparc_stackf ss;
2272 __siginfo_t info;
2273 abi_ulong fpu_save;
2274 abi_ulong insns[2] __attribute__ ((aligned (8)));
2275 abi_ulong extramask[TARGET_NSIG_WORDS - 1];
2276 abi_ulong extra_size; /* Should be 0 */
2277 qemu_siginfo_fpu_t fpu_state;
bellard6d5e2162004-09-30 22:04:13 +00002278};
2279struct target_rt_signal_frame {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002280 struct sparc_stackf ss;
2281 siginfo_t info;
2282 abi_ulong regs[20];
2283 sigset_t mask;
2284 abi_ulong fpu_save;
2285 unsigned int insns[2];
2286 stack_t stack;
2287 unsigned int extra_size; /* Should be 0 */
2288 qemu_siginfo_fpu_t fpu_state;
bellard6d5e2162004-09-30 22:04:13 +00002289};
2290
bellarde80cfcf2004-12-19 23:18:01 +00002291#define UREG_O0 16
2292#define UREG_O6 22
2293#define UREG_I0 0
2294#define UREG_I1 1
2295#define UREG_I2 2
blueswir15bfb56b2007-10-05 17:01:51 +00002296#define UREG_I3 3
2297#define UREG_I4 4
2298#define UREG_I5 5
bellarde80cfcf2004-12-19 23:18:01 +00002299#define UREG_I6 6
2300#define UREG_I7 7
2301#define UREG_L0 8
bellard6d5e2162004-09-30 22:04:13 +00002302#define UREG_FP UREG_I6
2303#define UREG_SP UREG_O6
2304
pbrook624f7972008-05-31 16:11:38 +00002305static inline abi_ulong get_sigframe(struct target_sigaction *sa,
Andreas Färber05390242012-02-25 03:37:53 +01002306 CPUSPARCState *env,
2307 unsigned long framesize)
bellard6d5e2162004-09-30 22:04:13 +00002308{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002309 abi_ulong sp;
bellard6d5e2162004-09-30 22:04:13 +00002310
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002311 sp = env->regwptr[UREG_FP];
bellard6d5e2162004-09-30 22:04:13 +00002312
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002313 /* This is the X/Open sanctioned signal stack switching. */
2314 if (sa->sa_flags & TARGET_SA_ONSTACK) {
2315 if (!on_sig_stack(sp)
2316 && !((target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size) & 7)) {
2317 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
2318 }
2319 }
2320 return sp - framesize;
bellard6d5e2162004-09-30 22:04:13 +00002321}
2322
2323static int
Andreas Färber05390242012-02-25 03:37:53 +01002324setup___siginfo(__siginfo_t *si, CPUSPARCState *env, abi_ulong mask)
bellard6d5e2162004-09-30 22:04:13 +00002325{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002326 int err = 0, i;
bellard6d5e2162004-09-30 22:04:13 +00002327
Riku Voipio1d8b5122014-04-23 10:26:05 +03002328 __put_user(env->psr, &si->si_regs.psr);
2329 __put_user(env->pc, &si->si_regs.pc);
2330 __put_user(env->npc, &si->si_regs.npc);
2331 __put_user(env->y, &si->si_regs.y);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002332 for (i=0; i < 8; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002333 __put_user(env->gregs[i], &si->si_regs.u_regs[i]);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002334 }
2335 for (i=0; i < 8; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002336 __put_user(env->regwptr[UREG_I0 + i], &si->si_regs.u_regs[i+8]);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002337 }
Riku Voipio1d8b5122014-04-23 10:26:05 +03002338 __put_user(mask, &si->si_mask);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002339 return err;
bellard6d5e2162004-09-30 22:04:13 +00002340}
bellarde80cfcf2004-12-19 23:18:01 +00002341
bellard80a9d032005-01-03 23:31:27 +00002342#if 0
bellard6d5e2162004-09-30 22:04:13 +00002343static int
2344setup_sigcontext(struct target_sigcontext *sc, /*struct _fpstate *fpstate,*/
Andreas Färber05390242012-02-25 03:37:53 +01002345 CPUSPARCState *env, unsigned long mask)
bellard6d5e2162004-09-30 22:04:13 +00002346{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002347 int err = 0;
bellard6d5e2162004-09-30 22:04:13 +00002348
Riku Voipio1d8b5122014-04-23 10:26:05 +03002349 __put_user(mask, &sc->sigc_mask);
2350 __put_user(env->regwptr[UREG_SP], &sc->sigc_sp);
2351 __put_user(env->pc, &sc->sigc_pc);
2352 __put_user(env->npc, &sc->sigc_npc);
2353 __put_user(env->psr, &sc->sigc_psr);
2354 __put_user(env->gregs[1], &sc->sigc_g1);
2355 __put_user(env->regwptr[UREG_O0], &sc->sigc_o0);
bellard6d5e2162004-09-30 22:04:13 +00002356
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002357 return err;
bellard6d5e2162004-09-30 22:04:13 +00002358}
bellard80a9d032005-01-03 23:31:27 +00002359#endif
bellard6d5e2162004-09-30 22:04:13 +00002360#define NF_ALIGNEDSZ (((sizeof(struct target_signal_frame) + 7) & (~7)))
2361
pbrook624f7972008-05-31 16:11:38 +00002362static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01002363 target_sigset_t *set, CPUSPARCState *env)
bellard6d5e2162004-09-30 22:04:13 +00002364{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002365 abi_ulong sf_addr;
2366 struct target_signal_frame *sf;
2367 int sigframe_size, err, i;
bellard6d5e2162004-09-30 22:04:13 +00002368
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002369 /* 1. Make sure everything is clean */
2370 //synchronize_user_stack();
bellard6d5e2162004-09-30 22:04:13 +00002371
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002372 sigframe_size = NF_ALIGNEDSZ;
2373 sf_addr = get_sigframe(ka, env, sigframe_size);
2374 trace_user_setup_frame(env, sf_addr);
bellard6d5e2162004-09-30 22:04:13 +00002375
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002376 sf = lock_user(VERIFY_WRITE, sf_addr,
2377 sizeof(struct target_signal_frame), 0);
2378 if (!sf) {
2379 goto sigsegv;
2380 }
bellard6d5e2162004-09-30 22:04:13 +00002381#if 0
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002382 if (invalid_frame_pointer(sf, sigframe_size))
2383 goto sigill_and_return;
bellard6d5e2162004-09-30 22:04:13 +00002384#endif
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002385 /* 2. Save the current process state */
2386 err = setup___siginfo(&sf->info, env, set->sig[0]);
Riku Voipio1d8b5122014-04-23 10:26:05 +03002387 __put_user(0, &sf->extra_size);
bellard6d5e2162004-09-30 22:04:13 +00002388
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002389 //save_fpu_state(regs, &sf->fpu_state);
2390 //__put_user(&sf->fpu_state, &sf->fpu_save);
bellard6d5e2162004-09-30 22:04:13 +00002391
Riku Voipio1d8b5122014-04-23 10:26:05 +03002392 __put_user(set->sig[0], &sf->info.si_mask);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002393 for (i = 0; i < TARGET_NSIG_WORDS - 1; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002394 __put_user(set->sig[i + 1], &sf->extramask[i]);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002395 }
bellard6d5e2162004-09-30 22:04:13 +00002396
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002397 for (i = 0; i < 8; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002398 __put_user(env->regwptr[i + UREG_L0], &sf->ss.locals[i]);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002399 }
2400 for (i = 0; i < 8; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002401 __put_user(env->regwptr[i + UREG_I0], &sf->ss.ins[i]);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002402 }
2403 if (err)
2404 goto sigsegv;
bellard6d5e2162004-09-30 22:04:13 +00002405
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002406 /* 3. signal handler back-trampoline and parameters */
2407 env->regwptr[UREG_FP] = sf_addr;
2408 env->regwptr[UREG_I0] = sig;
2409 env->regwptr[UREG_I1] = sf_addr +
2410 offsetof(struct target_signal_frame, info);
2411 env->regwptr[UREG_I2] = sf_addr +
2412 offsetof(struct target_signal_frame, info);
bellard6d5e2162004-09-30 22:04:13 +00002413
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002414 /* 4. signal handler */
2415 env->pc = ka->_sa_handler;
2416 env->npc = (env->pc + 4);
2417 /* 5. return to kernel instructions */
2418 if (ka->sa_restorer) {
2419 env->regwptr[UREG_I7] = ka->sa_restorer;
2420 } else {
2421 uint32_t val32;
bellard459a4012007-11-11 19:45:10 +00002422
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002423 env->regwptr[UREG_I7] = sf_addr +
2424 offsetof(struct target_signal_frame, insns) - 2 * 4;
bellard6d5e2162004-09-30 22:04:13 +00002425
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002426 /* mov __NR_sigreturn, %g1 */
2427 val32 = 0x821020d8;
Riku Voipio1d8b5122014-04-23 10:26:05 +03002428 __put_user(val32, &sf->insns[0]);
bellard6d5e2162004-09-30 22:04:13 +00002429
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002430 /* t 0x10 */
2431 val32 = 0x91d02010;
Riku Voipio1d8b5122014-04-23 10:26:05 +03002432 __put_user(val32, &sf->insns[1]);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002433 if (err)
2434 goto sigsegv;
bellard6d5e2162004-09-30 22:04:13 +00002435
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002436 /* Flush instruction space. */
2437 // flush_sig_insns(current->mm, (unsigned long) &(sf->insns[0]));
2438 // tb_flush(env);
2439 }
2440 unlock_user(sf, sf_addr, sizeof(struct target_signal_frame));
2441 return;
bellard459a4012007-11-11 19:45:10 +00002442#if 0
2443sigill_and_return:
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002444 force_sig(TARGET_SIGILL);
bellard459a4012007-11-11 19:45:10 +00002445#endif
bellard6d5e2162004-09-30 22:04:13 +00002446sigsegv:
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002447 unlock_user(sf, sf_addr, sizeof(struct target_signal_frame));
2448 force_sig(TARGET_SIGSEGV);
bellard6d5e2162004-09-30 22:04:13 +00002449}
bellard6d5e2162004-09-30 22:04:13 +00002450
pbrook624f7972008-05-31 16:11:38 +00002451static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05002452 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01002453 target_sigset_t *set, CPUSPARCState *env)
bellard6d5e2162004-09-30 22:04:13 +00002454{
2455 fprintf(stderr, "setup_rt_frame: not implemented\n");
2456}
2457
Andreas Färber05390242012-02-25 03:37:53 +01002458long do_sigreturn(CPUSPARCState *env)
bellard6d5e2162004-09-30 22:04:13 +00002459{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002460 abi_ulong sf_addr;
2461 struct target_signal_frame *sf;
2462 uint32_t up_psr, pc, npc;
2463 target_sigset_t set;
2464 sigset_t host_set;
2465 int err=0, i;
bellard6d5e2162004-09-30 22:04:13 +00002466
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002467 sf_addr = env->regwptr[UREG_FP];
2468 trace_user_do_sigreturn(env, sf_addr);
2469 if (!lock_user_struct(VERIFY_READ, sf, sf_addr, 1)) {
2470 goto segv_and_exit;
2471 }
bellard6d5e2162004-09-30 22:04:13 +00002472
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002473 /* 1. Make sure we are not getting garbage from the user */
bellard6d5e2162004-09-30 22:04:13 +00002474
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002475 if (sf_addr & 3)
2476 goto segv_and_exit;
bellard6d5e2162004-09-30 22:04:13 +00002477
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002478 __get_user(pc, &sf->info.si_regs.pc);
2479 __get_user(npc, &sf->info.si_regs.npc);
bellard6d5e2162004-09-30 22:04:13 +00002480
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002481 if ((pc | npc) & 3) {
2482 goto segv_and_exit;
2483 }
bellard6d5e2162004-09-30 22:04:13 +00002484
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002485 /* 2. Restore the state */
2486 __get_user(up_psr, &sf->info.si_regs.psr);
bellarde80cfcf2004-12-19 23:18:01 +00002487
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002488 /* User can only change condition codes and FPU enabling in %psr. */
2489 env->psr = (up_psr & (PSR_ICC /* | PSR_EF */))
2490 | (env->psr & ~(PSR_ICC /* | PSR_EF */));
bellarda315a142005-01-30 22:59:18 +00002491
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002492 env->pc = pc;
2493 env->npc = npc;
2494 __get_user(env->y, &sf->info.si_regs.y);
2495 for (i=0; i < 8; i++) {
2496 __get_user(env->gregs[i], &sf->info.si_regs.u_regs[i]);
2497 }
2498 for (i=0; i < 8; i++) {
2499 __get_user(env->regwptr[i + UREG_I0], &sf->info.si_regs.u_regs[i+8]);
2500 }
bellard6d5e2162004-09-30 22:04:13 +00002501
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002502 /* FIXME: implement FPU save/restore:
Peter Maydell2aec3a22011-06-16 17:37:14 +01002503 * __get_user(fpu_save, &sf->fpu_save);
2504 * if (fpu_save)
2505 * err |= restore_fpu_state(env, fpu_save);
2506 */
bellard6d5e2162004-09-30 22:04:13 +00002507
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002508 /* This is pretty much atomic, no amount locking would prevent
bellard6d5e2162004-09-30 22:04:13 +00002509 * the races which exist anyways.
2510 */
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002511 __get_user(set.sig[0], &sf->info.si_mask);
2512 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
2513 __get_user(set.sig[i], &sf->extramask[i - 1]);
2514 }
bellarde80cfcf2004-12-19 23:18:01 +00002515
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002516 target_to_host_sigset_internal(&host_set, &set);
Peter Maydell9eede5b2016-05-27 15:51:46 +01002517 set_sigmask(&host_set);
bellard6d5e2162004-09-30 22:04:13 +00002518
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002519 if (err) {
2520 goto segv_and_exit;
2521 }
2522 unlock_user_struct(sf, sf_addr, 0);
Timothy E Baldwinc0bea682016-05-12 18:47:34 +01002523 return -TARGET_QEMU_ESIGRETURN;
bellard6d5e2162004-09-30 22:04:13 +00002524
2525segv_and_exit:
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002526 unlock_user_struct(sf, sf_addr, 0);
2527 force_sig(TARGET_SIGSEGV);
bellard6d5e2162004-09-30 22:04:13 +00002528}
2529
Andreas Färber05390242012-02-25 03:37:53 +01002530long do_rt_sigreturn(CPUSPARCState *env)
bellard6d5e2162004-09-30 22:04:13 +00002531{
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01002532 trace_user_do_rt_sigreturn(env, 0);
bellard6d5e2162004-09-30 22:04:13 +00002533 fprintf(stderr, "do_rt_sigreturn: not implemented\n");
bellardf8b0aa22007-11-11 23:03:42 +00002534 return -TARGET_ENOSYS;
bellard6d5e2162004-09-30 22:04:13 +00002535}
2536
bellard459a4012007-11-11 19:45:10 +00002537#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
blueswir15bfb56b2007-10-05 17:01:51 +00002538#define MC_TSTATE 0
2539#define MC_PC 1
2540#define MC_NPC 2
2541#define MC_Y 3
2542#define MC_G1 4
2543#define MC_G2 5
2544#define MC_G3 6
2545#define MC_G4 7
2546#define MC_G5 8
2547#define MC_G6 9
2548#define MC_G7 10
2549#define MC_O0 11
2550#define MC_O1 12
2551#define MC_O2 13
2552#define MC_O3 14
2553#define MC_O4 15
2554#define MC_O5 16
2555#define MC_O6 17
2556#define MC_O7 18
2557#define MC_NGREG 19
2558
Anthony Liguoric227f092009-10-01 16:12:16 -05002559typedef abi_ulong target_mc_greg_t;
2560typedef target_mc_greg_t target_mc_gregset_t[MC_NGREG];
blueswir15bfb56b2007-10-05 17:01:51 +00002561
2562struct target_mc_fq {
blueswir1992f48a2007-10-14 16:27:31 +00002563 abi_ulong *mcfq_addr;
blueswir15bfb56b2007-10-05 17:01:51 +00002564 uint32_t mcfq_insn;
2565};
2566
2567struct target_mc_fpu {
2568 union {
2569 uint32_t sregs[32];
2570 uint64_t dregs[32];
2571 //uint128_t qregs[16];
2572 } mcfpu_fregs;
blueswir1992f48a2007-10-14 16:27:31 +00002573 abi_ulong mcfpu_fsr;
2574 abi_ulong mcfpu_fprs;
2575 abi_ulong mcfpu_gsr;
blueswir15bfb56b2007-10-05 17:01:51 +00002576 struct target_mc_fq *mcfpu_fq;
2577 unsigned char mcfpu_qcnt;
2578 unsigned char mcfpu_qentsz;
2579 unsigned char mcfpu_enab;
2580};
Anthony Liguoric227f092009-10-01 16:12:16 -05002581typedef struct target_mc_fpu target_mc_fpu_t;
blueswir15bfb56b2007-10-05 17:01:51 +00002582
2583typedef struct {
Anthony Liguoric227f092009-10-01 16:12:16 -05002584 target_mc_gregset_t mc_gregs;
2585 target_mc_greg_t mc_fp;
2586 target_mc_greg_t mc_i7;
2587 target_mc_fpu_t mc_fpregs;
2588} target_mcontext_t;
blueswir15bfb56b2007-10-05 17:01:51 +00002589
2590struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02002591 struct target_ucontext *tuc_link;
2592 abi_ulong tuc_flags;
2593 target_sigset_t tuc_sigmask;
2594 target_mcontext_t tuc_mcontext;
blueswir15bfb56b2007-10-05 17:01:51 +00002595};
2596
2597/* A V9 register window */
2598struct target_reg_window {
blueswir1992f48a2007-10-14 16:27:31 +00002599 abi_ulong locals[8];
2600 abi_ulong ins[8];
blueswir15bfb56b2007-10-05 17:01:51 +00002601};
2602
2603#define TARGET_STACK_BIAS 2047
2604
2605/* {set, get}context() needed for 64-bit SparcLinux userland. */
2606void sparc64_set_context(CPUSPARCState *env)
2607{
bellard459a4012007-11-11 19:45:10 +00002608 abi_ulong ucp_addr;
2609 struct target_ucontext *ucp;
Anthony Liguoric227f092009-10-01 16:12:16 -05002610 target_mc_gregset_t *grp;
blueswir1992f48a2007-10-14 16:27:31 +00002611 abi_ulong pc, npc, tstate;
bellard459a4012007-11-11 19:45:10 +00002612 abi_ulong fp, i7, w_addr;
blueswir15bfb56b2007-10-05 17:01:51 +00002613 unsigned int i;
blueswir15bfb56b2007-10-05 17:01:51 +00002614
bellard459a4012007-11-11 19:45:10 +00002615 ucp_addr = env->regwptr[UREG_I0];
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002616 if (!lock_user_struct(VERIFY_READ, ucp, ucp_addr, 1)) {
bellard459a4012007-11-11 19:45:10 +00002617 goto do_sigsegv;
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002618 }
Aurelien Jarno60e99242010-03-29 02:12:51 +02002619 grp = &ucp->tuc_mcontext.mc_gregs;
Riku Voipio1d8b5122014-04-23 10:26:05 +03002620 __get_user(pc, &((*grp)[MC_PC]));
2621 __get_user(npc, &((*grp)[MC_NPC]));
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002622 if ((pc | npc) & 3) {
blueswir15bfb56b2007-10-05 17:01:51 +00002623 goto do_sigsegv;
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002624 }
blueswir15bfb56b2007-10-05 17:01:51 +00002625 if (env->regwptr[UREG_I1]) {
Anthony Liguoric227f092009-10-01 16:12:16 -05002626 target_sigset_t target_set;
blueswir15bfb56b2007-10-05 17:01:51 +00002627 sigset_t set;
2628
2629 if (TARGET_NSIG_WORDS == 1) {
Riku Voipiobe3ef5c2014-04-23 14:02:36 +03002630 __get_user(target_set.sig[0], &ucp->tuc_sigmask.sig[0]);
blueswir15bfb56b2007-10-05 17:01:51 +00002631 } else {
bellard459a4012007-11-11 19:45:10 +00002632 abi_ulong *src, *dst;
Aurelien Jarno60e99242010-03-29 02:12:51 +02002633 src = ucp->tuc_sigmask.sig;
bellard459a4012007-11-11 19:45:10 +00002634 dst = target_set.sig;
Stefan Weil0d9e61c2013-12-07 14:48:08 +01002635 for (i = 0; i < TARGET_NSIG_WORDS; i++, dst++, src++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002636 __get_user(*dst, src);
Stefan Weil0d9e61c2013-12-07 14:48:08 +01002637 }
blueswir15bfb56b2007-10-05 17:01:51 +00002638 }
2639 target_to_host_sigset_internal(&set, &target_set);
Peter Maydell9eede5b2016-05-27 15:51:46 +01002640 set_sigmask(&set);
blueswir15bfb56b2007-10-05 17:01:51 +00002641 }
2642 env->pc = pc;
2643 env->npc = npc;
Riku Voipio1d8b5122014-04-23 10:26:05 +03002644 __get_user(env->y, &((*grp)[MC_Y]));
2645 __get_user(tstate, &((*grp)[MC_TSTATE]));
blueswir15bfb56b2007-10-05 17:01:51 +00002646 env->asi = (tstate >> 24) & 0xff;
Blue Swirl5a834bb2010-05-09 20:19:04 +00002647 cpu_put_ccr(env, tstate >> 32);
2648 cpu_put_cwp64(env, tstate & 0x1f);
Riku Voipio1d8b5122014-04-23 10:26:05 +03002649 __get_user(env->gregs[1], (&(*grp)[MC_G1]));
2650 __get_user(env->gregs[2], (&(*grp)[MC_G2]));
2651 __get_user(env->gregs[3], (&(*grp)[MC_G3]));
2652 __get_user(env->gregs[4], (&(*grp)[MC_G4]));
2653 __get_user(env->gregs[5], (&(*grp)[MC_G5]));
2654 __get_user(env->gregs[6], (&(*grp)[MC_G6]));
2655 __get_user(env->gregs[7], (&(*grp)[MC_G7]));
2656 __get_user(env->regwptr[UREG_I0], (&(*grp)[MC_O0]));
2657 __get_user(env->regwptr[UREG_I1], (&(*grp)[MC_O1]));
2658 __get_user(env->regwptr[UREG_I2], (&(*grp)[MC_O2]));
2659 __get_user(env->regwptr[UREG_I3], (&(*grp)[MC_O3]));
2660 __get_user(env->regwptr[UREG_I4], (&(*grp)[MC_O4]));
2661 __get_user(env->regwptr[UREG_I5], (&(*grp)[MC_O5]));
2662 __get_user(env->regwptr[UREG_I6], (&(*grp)[MC_O6]));
2663 __get_user(env->regwptr[UREG_I7], (&(*grp)[MC_O7]));
blueswir15bfb56b2007-10-05 17:01:51 +00002664
Riku Voipio1d8b5122014-04-23 10:26:05 +03002665 __get_user(fp, &(ucp->tuc_mcontext.mc_fp));
2666 __get_user(i7, &(ucp->tuc_mcontext.mc_i7));
blueswir15bfb56b2007-10-05 17:01:51 +00002667
bellard459a4012007-11-11 19:45:10 +00002668 w_addr = TARGET_STACK_BIAS+env->regwptr[UREG_I6];
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002669 if (put_user(fp, w_addr + offsetof(struct target_reg_window, ins[6]),
2670 abi_ulong) != 0) {
bellard459a4012007-11-11 19:45:10 +00002671 goto do_sigsegv;
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002672 }
2673 if (put_user(i7, w_addr + offsetof(struct target_reg_window, ins[7]),
2674 abi_ulong) != 0) {
bellard459a4012007-11-11 19:45:10 +00002675 goto do_sigsegv;
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002676 }
Peter Maydellc7b016b2011-06-16 17:37:15 +01002677 /* FIXME this does not match how the kernel handles the FPU in
2678 * its sparc64_set_context implementation. In particular the FPU
2679 * is only restored if fenab is non-zero in:
2680 * __get_user(fenab, &(ucp->tuc_mcontext.mc_fpregs.mcfpu_enab));
2681 */
Riku Voipiobe3ef5c2014-04-23 14:02:36 +03002682 __get_user(env->fprs, &(ucp->tuc_mcontext.mc_fpregs.mcfpu_fprs));
bellard459a4012007-11-11 19:45:10 +00002683 {
Richard Henderson30038fd2011-10-17 10:42:49 -07002684 uint32_t *src = ucp->tuc_mcontext.mc_fpregs.mcfpu_fregs.sregs;
2685 for (i = 0; i < 64; i++, src++) {
2686 if (i & 1) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002687 __get_user(env->fpr[i/2].l.lower, src);
Richard Henderson30038fd2011-10-17 10:42:49 -07002688 } else {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002689 __get_user(env->fpr[i/2].l.upper, src);
Richard Henderson30038fd2011-10-17 10:42:49 -07002690 }
2691 }
bellard459a4012007-11-11 19:45:10 +00002692 }
Riku Voipio1d8b5122014-04-23 10:26:05 +03002693 __get_user(env->fsr,
2694 &(ucp->tuc_mcontext.mc_fpregs.mcfpu_fsr));
2695 __get_user(env->gsr,
2696 &(ucp->tuc_mcontext.mc_fpregs.mcfpu_gsr));
bellard459a4012007-11-11 19:45:10 +00002697 unlock_user_struct(ucp, ucp_addr, 0);
blueswir15bfb56b2007-10-05 17:01:51 +00002698 return;
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002699do_sigsegv:
bellard459a4012007-11-11 19:45:10 +00002700 unlock_user_struct(ucp, ucp_addr, 0);
Riku Voipio66393fb2009-12-04 15:16:32 +02002701 force_sig(TARGET_SIGSEGV);
blueswir15bfb56b2007-10-05 17:01:51 +00002702}
2703
2704void sparc64_get_context(CPUSPARCState *env)
2705{
bellard459a4012007-11-11 19:45:10 +00002706 abi_ulong ucp_addr;
2707 struct target_ucontext *ucp;
Anthony Liguoric227f092009-10-01 16:12:16 -05002708 target_mc_gregset_t *grp;
2709 target_mcontext_t *mcp;
bellard459a4012007-11-11 19:45:10 +00002710 abi_ulong fp, i7, w_addr;
blueswir15bfb56b2007-10-05 17:01:51 +00002711 int err;
2712 unsigned int i;
Anthony Liguoric227f092009-10-01 16:12:16 -05002713 target_sigset_t target_set;
blueswir15bfb56b2007-10-05 17:01:51 +00002714 sigset_t set;
2715
bellard459a4012007-11-11 19:45:10 +00002716 ucp_addr = env->regwptr[UREG_I0];
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002717 if (!lock_user_struct(VERIFY_WRITE, ucp, ucp_addr, 0)) {
bellard459a4012007-11-11 19:45:10 +00002718 goto do_sigsegv;
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002719 }
bellard459a4012007-11-11 19:45:10 +00002720
Aurelien Jarno60e99242010-03-29 02:12:51 +02002721 mcp = &ucp->tuc_mcontext;
blueswir15bfb56b2007-10-05 17:01:51 +00002722 grp = &mcp->mc_gregs;
2723
2724 /* Skip over the trap instruction, first. */
2725 env->pc = env->npc;
2726 env->npc += 4;
2727
Peter Maydell3d3efba2016-05-27 15:51:49 +01002728 /* If we're only reading the signal mask then do_sigprocmask()
2729 * is guaranteed not to fail, which is important because we don't
2730 * have any way to signal a failure or restart this operation since
2731 * this is not a normal syscall.
2732 */
2733 err = do_sigprocmask(0, NULL, &set);
2734 assert(err == 0);
blueswir15bfb56b2007-10-05 17:01:51 +00002735 host_to_target_sigset_internal(&target_set, &set);
bellard459a4012007-11-11 19:45:10 +00002736 if (TARGET_NSIG_WORDS == 1) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002737 __put_user(target_set.sig[0],
2738 (abi_ulong *)&ucp->tuc_sigmask);
bellard459a4012007-11-11 19:45:10 +00002739 } else {
2740 abi_ulong *src, *dst;
2741 src = target_set.sig;
Aurelien Jarno60e99242010-03-29 02:12:51 +02002742 dst = ucp->tuc_sigmask.sig;
Stefan Weil0d9e61c2013-12-07 14:48:08 +01002743 for (i = 0; i < TARGET_NSIG_WORDS; i++, dst++, src++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002744 __put_user(*src, dst);
Stefan Weil0d9e61c2013-12-07 14:48:08 +01002745 }
blueswir15bfb56b2007-10-05 17:01:51 +00002746 if (err)
2747 goto do_sigsegv;
2748 }
2749
bellard459a4012007-11-11 19:45:10 +00002750 /* XXX: tstate must be saved properly */
Riku Voipio1d8b5122014-04-23 10:26:05 +03002751 // __put_user(env->tstate, &((*grp)[MC_TSTATE]));
2752 __put_user(env->pc, &((*grp)[MC_PC]));
2753 __put_user(env->npc, &((*grp)[MC_NPC]));
2754 __put_user(env->y, &((*grp)[MC_Y]));
2755 __put_user(env->gregs[1], &((*grp)[MC_G1]));
2756 __put_user(env->gregs[2], &((*grp)[MC_G2]));
2757 __put_user(env->gregs[3], &((*grp)[MC_G3]));
2758 __put_user(env->gregs[4], &((*grp)[MC_G4]));
2759 __put_user(env->gregs[5], &((*grp)[MC_G5]));
2760 __put_user(env->gregs[6], &((*grp)[MC_G6]));
2761 __put_user(env->gregs[7], &((*grp)[MC_G7]));
2762 __put_user(env->regwptr[UREG_I0], &((*grp)[MC_O0]));
2763 __put_user(env->regwptr[UREG_I1], &((*grp)[MC_O1]));
2764 __put_user(env->regwptr[UREG_I2], &((*grp)[MC_O2]));
2765 __put_user(env->regwptr[UREG_I3], &((*grp)[MC_O3]));
2766 __put_user(env->regwptr[UREG_I4], &((*grp)[MC_O4]));
2767 __put_user(env->regwptr[UREG_I5], &((*grp)[MC_O5]));
2768 __put_user(env->regwptr[UREG_I6], &((*grp)[MC_O6]));
2769 __put_user(env->regwptr[UREG_I7], &((*grp)[MC_O7]));
blueswir15bfb56b2007-10-05 17:01:51 +00002770
bellard459a4012007-11-11 19:45:10 +00002771 w_addr = TARGET_STACK_BIAS+env->regwptr[UREG_I6];
2772 fp = i7 = 0;
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002773 if (get_user(fp, w_addr + offsetof(struct target_reg_window, ins[6]),
2774 abi_ulong) != 0) {
bellard459a4012007-11-11 19:45:10 +00002775 goto do_sigsegv;
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002776 }
2777 if (get_user(i7, w_addr + offsetof(struct target_reg_window, ins[7]),
2778 abi_ulong) != 0) {
bellard459a4012007-11-11 19:45:10 +00002779 goto do_sigsegv;
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002780 }
Riku Voipio1d8b5122014-04-23 10:26:05 +03002781 __put_user(fp, &(mcp->mc_fp));
2782 __put_user(i7, &(mcp->mc_i7));
blueswir15bfb56b2007-10-05 17:01:51 +00002783
bellard459a4012007-11-11 19:45:10 +00002784 {
Richard Henderson30038fd2011-10-17 10:42:49 -07002785 uint32_t *dst = ucp->tuc_mcontext.mc_fpregs.mcfpu_fregs.sregs;
2786 for (i = 0; i < 64; i++, dst++) {
2787 if (i & 1) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002788 __put_user(env->fpr[i/2].l.lower, dst);
Richard Henderson30038fd2011-10-17 10:42:49 -07002789 } else {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002790 __put_user(env->fpr[i/2].l.upper, dst);
Richard Henderson30038fd2011-10-17 10:42:49 -07002791 }
2792 }
bellard459a4012007-11-11 19:45:10 +00002793 }
Riku Voipio1d8b5122014-04-23 10:26:05 +03002794 __put_user(env->fsr, &(mcp->mc_fpregs.mcfpu_fsr));
2795 __put_user(env->gsr, &(mcp->mc_fpregs.mcfpu_gsr));
2796 __put_user(env->fprs, &(mcp->mc_fpregs.mcfpu_fprs));
blueswir15bfb56b2007-10-05 17:01:51 +00002797
2798 if (err)
2799 goto do_sigsegv;
bellard459a4012007-11-11 19:45:10 +00002800 unlock_user_struct(ucp, ucp_addr, 1);
blueswir15bfb56b2007-10-05 17:01:51 +00002801 return;
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002802do_sigsegv:
bellard459a4012007-11-11 19:45:10 +00002803 unlock_user_struct(ucp, ucp_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02002804 force_sig(TARGET_SIGSEGV);
blueswir15bfb56b2007-10-05 17:01:51 +00002805}
2806#endif
Richard Hendersonff970902013-02-10 10:30:42 -08002807#elif defined(TARGET_MIPS) || defined(TARGET_MIPS64)
bellard106ec872006-06-27 21:08:10 +00002808
Richard Hendersonff970902013-02-10 10:30:42 -08002809# if defined(TARGET_ABI_MIPSO32)
bellard106ec872006-06-27 21:08:10 +00002810struct target_sigcontext {
2811 uint32_t sc_regmask; /* Unused */
2812 uint32_t sc_status;
2813 uint64_t sc_pc;
2814 uint64_t sc_regs[32];
2815 uint64_t sc_fpregs[32];
2816 uint32_t sc_ownedfp; /* Unused */
2817 uint32_t sc_fpc_csr;
2818 uint32_t sc_fpc_eir; /* Unused */
2819 uint32_t sc_used_math;
2820 uint32_t sc_dsp; /* dsp status, was sc_ssflags */
Paul Brook94c54952009-07-09 18:40:15 +01002821 uint32_t pad0;
bellard106ec872006-06-27 21:08:10 +00002822 uint64_t sc_mdhi;
2823 uint64_t sc_mdlo;
2824 target_ulong sc_hi1; /* Was sc_cause */
2825 target_ulong sc_lo1; /* Was sc_badvaddr */
2826 target_ulong sc_hi2; /* Was sc_sigset[4] */
2827 target_ulong sc_lo2;
2828 target_ulong sc_hi3;
2829 target_ulong sc_lo3;
2830};
Richard Hendersonff970902013-02-10 10:30:42 -08002831# else /* N32 || N64 */
2832struct target_sigcontext {
2833 uint64_t sc_regs[32];
2834 uint64_t sc_fpregs[32];
2835 uint64_t sc_mdhi;
2836 uint64_t sc_hi1;
2837 uint64_t sc_hi2;
2838 uint64_t sc_hi3;
2839 uint64_t sc_mdlo;
2840 uint64_t sc_lo1;
2841 uint64_t sc_lo2;
2842 uint64_t sc_lo3;
2843 uint64_t sc_pc;
2844 uint32_t sc_fpc_csr;
2845 uint32_t sc_used_math;
2846 uint32_t sc_dsp;
2847 uint32_t sc_reserved;
2848};
2849# endif /* O32 */
bellard106ec872006-06-27 21:08:10 +00002850
2851struct sigframe {
2852 uint32_t sf_ass[4]; /* argument save space for o32 */
2853 uint32_t sf_code[2]; /* signal trampoline */
2854 struct target_sigcontext sf_sc;
Anthony Liguoric227f092009-10-01 16:12:16 -05002855 target_sigset_t sf_mask;
bellard106ec872006-06-27 21:08:10 +00002856};
2857
pbrook0b1bcb02009-04-21 01:41:10 +00002858struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02002859 target_ulong tuc_flags;
2860 target_ulong tuc_link;
2861 target_stack_t tuc_stack;
Paul Brook94c54952009-07-09 18:40:15 +01002862 target_ulong pad0;
Aurelien Jarno60e99242010-03-29 02:12:51 +02002863 struct target_sigcontext tuc_mcontext;
2864 target_sigset_t tuc_sigmask;
pbrook0b1bcb02009-04-21 01:41:10 +00002865};
2866
2867struct target_rt_sigframe {
2868 uint32_t rs_ass[4]; /* argument save space for o32 */
2869 uint32_t rs_code[2]; /* signal trampoline */
2870 struct target_siginfo rs_info;
2871 struct target_ucontext rs_uc;
2872};
2873
bellard106ec872006-06-27 21:08:10 +00002874/* Install trampoline to jump back from signal handler */
2875static inline int install_sigtramp(unsigned int *tramp, unsigned int syscall)
2876{
Richard Henderson084d0492013-02-10 10:30:44 -08002877 int err = 0;
bellard106ec872006-06-27 21:08:10 +00002878
2879 /*
Richard Henderson084d0492013-02-10 10:30:44 -08002880 * Set up the return code ...
2881 *
2882 * li v0, __NR__foo_sigreturn
2883 * syscall
2884 */
bellard106ec872006-06-27 21:08:10 +00002885
Riku Voipio1d8b5122014-04-23 10:26:05 +03002886 __put_user(0x24020000 + syscall, tramp + 0);
2887 __put_user(0x0000000c , tramp + 1);
bellard106ec872006-06-27 21:08:10 +00002888 return err;
2889}
2890
Riku Voipio41ecc722014-04-23 11:01:00 +03002891static inline void setup_sigcontext(CPUMIPSState *regs,
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002892 struct target_sigcontext *sc)
bellard106ec872006-06-27 21:08:10 +00002893{
Richard Henderson084d0492013-02-10 10:30:44 -08002894 int i;
bellard106ec872006-06-27 21:08:10 +00002895
Riku Voipio1d8b5122014-04-23 10:26:05 +03002896 __put_user(exception_resume_pc(regs), &sc->sc_pc);
Kwok Cheung Yeung1239b472013-05-17 14:51:21 -07002897 regs->hflags &= ~MIPS_HFLAG_BMASK;
bellard106ec872006-06-27 21:08:10 +00002898
Richard Henderson084d0492013-02-10 10:30:44 -08002899 __put_user(0, &sc->sc_regs[0]);
2900 for (i = 1; i < 32; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002901 __put_user(regs->active_tc.gpr[i], &sc->sc_regs[i]);
Richard Henderson084d0492013-02-10 10:30:44 -08002902 }
bellard106ec872006-06-27 21:08:10 +00002903
Riku Voipio1d8b5122014-04-23 10:26:05 +03002904 __put_user(regs->active_tc.HI[0], &sc->sc_mdhi);
2905 __put_user(regs->active_tc.LO[0], &sc->sc_mdlo);
bellard106ec872006-06-27 21:08:10 +00002906
Richard Henderson084d0492013-02-10 10:30:44 -08002907 /* Rather than checking for dsp existence, always copy. The storage
2908 would just be garbage otherwise. */
Riku Voipio1d8b5122014-04-23 10:26:05 +03002909 __put_user(regs->active_tc.HI[1], &sc->sc_hi1);
2910 __put_user(regs->active_tc.HI[2], &sc->sc_hi2);
2911 __put_user(regs->active_tc.HI[3], &sc->sc_hi3);
2912 __put_user(regs->active_tc.LO[1], &sc->sc_lo1);
2913 __put_user(regs->active_tc.LO[2], &sc->sc_lo2);
2914 __put_user(regs->active_tc.LO[3], &sc->sc_lo3);
Richard Henderson084d0492013-02-10 10:30:44 -08002915 {
2916 uint32_t dsp = cpu_rddsp(0x3ff, regs);
Riku Voipio1d8b5122014-04-23 10:26:05 +03002917 __put_user(dsp, &sc->sc_dsp);
bellard106ec872006-06-27 21:08:10 +00002918 }
Richard Henderson084d0492013-02-10 10:30:44 -08002919
Riku Voipio1d8b5122014-04-23 10:26:05 +03002920 __put_user(1, &sc->sc_used_math);
Richard Henderson084d0492013-02-10 10:30:44 -08002921
2922 for (i = 0; i < 32; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002923 __put_user(regs->active_fpu.fpr[i].d, &sc->sc_fpregs[i]);
bellard106ec872006-06-27 21:08:10 +00002924 }
bellard106ec872006-06-27 21:08:10 +00002925}
2926
Riku Voipio016d2e12014-04-23 11:19:48 +03002927static inline void
Andreas Färber05390242012-02-25 03:37:53 +01002928restore_sigcontext(CPUMIPSState *regs, struct target_sigcontext *sc)
bellard106ec872006-06-27 21:08:10 +00002929{
Richard Henderson084d0492013-02-10 10:30:44 -08002930 int i;
bellard106ec872006-06-27 21:08:10 +00002931
Riku Voipio1d8b5122014-04-23 10:26:05 +03002932 __get_user(regs->CP0_EPC, &sc->sc_pc);
bellard106ec872006-06-27 21:08:10 +00002933
Riku Voipio1d8b5122014-04-23 10:26:05 +03002934 __get_user(regs->active_tc.HI[0], &sc->sc_mdhi);
2935 __get_user(regs->active_tc.LO[0], &sc->sc_mdlo);
bellard106ec872006-06-27 21:08:10 +00002936
Richard Henderson084d0492013-02-10 10:30:44 -08002937 for (i = 1; i < 32; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002938 __get_user(regs->active_tc.gpr[i], &sc->sc_regs[i]);
bellard106ec872006-06-27 21:08:10 +00002939 }
2940
Riku Voipio1d8b5122014-04-23 10:26:05 +03002941 __get_user(regs->active_tc.HI[1], &sc->sc_hi1);
2942 __get_user(regs->active_tc.HI[2], &sc->sc_hi2);
2943 __get_user(regs->active_tc.HI[3], &sc->sc_hi3);
2944 __get_user(regs->active_tc.LO[1], &sc->sc_lo1);
2945 __get_user(regs->active_tc.LO[2], &sc->sc_lo2);
2946 __get_user(regs->active_tc.LO[3], &sc->sc_lo3);
Richard Henderson084d0492013-02-10 10:30:44 -08002947 {
2948 uint32_t dsp;
Riku Voipio1d8b5122014-04-23 10:26:05 +03002949 __get_user(dsp, &sc->sc_dsp);
Richard Henderson084d0492013-02-10 10:30:44 -08002950 cpu_wrdsp(dsp, 0x3ff, regs);
2951 }
2952
2953 for (i = 0; i < 32; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002954 __get_user(regs->active_fpu.fpr[i].d, &sc->sc_fpregs[i]);
Richard Henderson084d0492013-02-10 10:30:44 -08002955 }
bellard106ec872006-06-27 21:08:10 +00002956}
Richard Hendersonff970902013-02-10 10:30:42 -08002957
bellard106ec872006-06-27 21:08:10 +00002958/*
2959 * Determine which stack to use..
2960 */
bellard579a97f2007-11-11 14:26:47 +00002961static inline abi_ulong
Andreas Färber05390242012-02-25 03:37:53 +01002962get_sigframe(struct target_sigaction *ka, CPUMIPSState *regs, size_t frame_size)
bellard106ec872006-06-27 21:08:10 +00002963{
2964 unsigned long sp;
2965
2966 /* Default to using normal stack */
thsb5dc7732008-06-27 10:02:35 +00002967 sp = regs->active_tc.gpr[29];
bellard106ec872006-06-27 21:08:10 +00002968
2969 /*
Stefan Weil93148aa2012-02-26 18:46:12 +01002970 * FPU emulator may have its own trampoline active just
bellard106ec872006-06-27 21:08:10 +00002971 * above the user stack, 16-bytes before the next lowest
2972 * 16 byte boundary. Try to avoid trashing it.
2973 */
2974 sp -= 32;
2975
bellard106ec872006-06-27 21:08:10 +00002976 /* This is the X/Open sanctioned signal stack switching. */
pbrook624f7972008-05-31 16:11:38 +00002977 if ((ka->sa_flags & TARGET_SA_ONSTACK) && (sas_ss_flags (sp) == 0)) {
thsa04e1342007-09-27 13:57:58 +00002978 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
2979 }
bellard106ec872006-06-27 21:08:10 +00002980
bellard579a97f2007-11-11 14:26:47 +00002981 return (sp - frame_size) & ~7;
bellard106ec872006-06-27 21:08:10 +00002982}
2983
Kwok Cheung Yeungea3164a2013-05-17 14:51:20 -07002984static void mips_set_hflags_isa_mode_from_pc(CPUMIPSState *env)
2985{
2986 if (env->insn_flags & (ASE_MIPS16 | ASE_MICROMIPS)) {
2987 env->hflags &= ~MIPS_HFLAG_M16;
2988 env->hflags |= (env->active_tc.PC & 1) << MIPS_HFLAG_M16_SHIFT;
2989 env->active_tc.PC &= ~(target_ulong) 1;
2990 }
2991}
2992
Richard Hendersonff970902013-02-10 10:30:42 -08002993# if defined(TARGET_ABI_MIPSO32)
bellard579a97f2007-11-11 14:26:47 +00002994/* compare linux/arch/mips/kernel/signal.c:setup_frame() */
pbrook624f7972008-05-31 16:11:38 +00002995static void setup_frame(int sig, struct target_sigaction * ka,
Andreas Färber05390242012-02-25 03:37:53 +01002996 target_sigset_t *set, CPUMIPSState *regs)
bellard106ec872006-06-27 21:08:10 +00002997{
2998 struct sigframe *frame;
bellard579a97f2007-11-11 14:26:47 +00002999 abi_ulong frame_addr;
bellard106ec872006-06-27 21:08:10 +00003000 int i;
3001
bellard579a97f2007-11-11 14:26:47 +00003002 frame_addr = get_sigframe(ka, regs, sizeof(*frame));
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01003003 trace_user_setup_frame(regs, frame_addr);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003004 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
3005 goto give_sigsegv;
3006 }
bellard106ec872006-06-27 21:08:10 +00003007
3008 install_sigtramp(frame->sf_code, TARGET_NR_sigreturn);
3009
Riku Voipio41ecc722014-04-23 11:01:00 +03003010 setup_sigcontext(regs, &frame->sf_sc);
bellard106ec872006-06-27 21:08:10 +00003011
3012 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
Riku Voipio0188fad2014-04-23 13:34:15 +03003013 __put_user(set->sig[i], &frame->sf_mask.sig[i]);
bellard106ec872006-06-27 21:08:10 +00003014 }
3015
3016 /*
3017 * Arguments to signal handler:
3018 *
3019 * a0 = signal number
3020 * a1 = 0 (should be cause)
3021 * a2 = pointer to struct sigcontext
3022 *
3023 * $25 and PC point to the signal handler, $29 points to the
3024 * struct sigframe.
3025 */
thsb5dc7732008-06-27 10:02:35 +00003026 regs->active_tc.gpr[ 4] = sig;
3027 regs->active_tc.gpr[ 5] = 0;
3028 regs->active_tc.gpr[ 6] = frame_addr + offsetof(struct sigframe, sf_sc);
3029 regs->active_tc.gpr[29] = frame_addr;
3030 regs->active_tc.gpr[31] = frame_addr + offsetof(struct sigframe, sf_code);
bellard106ec872006-06-27 21:08:10 +00003031 /* The original kernel code sets CP0_EPC to the handler
3032 * since it returns to userland using eret
3033 * we cannot do this here, and we must set PC directly */
thsb5dc7732008-06-27 10:02:35 +00003034 regs->active_tc.PC = regs->active_tc.gpr[25] = ka->_sa_handler;
Kwok Cheung Yeungea3164a2013-05-17 14:51:20 -07003035 mips_set_hflags_isa_mode_from_pc(regs);
bellard579a97f2007-11-11 14:26:47 +00003036 unlock_user_struct(frame, frame_addr, 1);
bellard106ec872006-06-27 21:08:10 +00003037 return;
3038
3039give_sigsegv:
3040 force_sig(TARGET_SIGSEGV/*, current*/);
bellard106ec872006-06-27 21:08:10 +00003041}
3042
Andreas Färber05390242012-02-25 03:37:53 +01003043long do_sigreturn(CPUMIPSState *regs)
bellard106ec872006-06-27 21:08:10 +00003044{
ths388bb212007-05-13 13:58:00 +00003045 struct sigframe *frame;
bellard579a97f2007-11-11 14:26:47 +00003046 abi_ulong frame_addr;
ths388bb212007-05-13 13:58:00 +00003047 sigset_t blocked;
Anthony Liguoric227f092009-10-01 16:12:16 -05003048 target_sigset_t target_set;
ths388bb212007-05-13 13:58:00 +00003049 int i;
bellard106ec872006-06-27 21:08:10 +00003050
thsb5dc7732008-06-27 10:02:35 +00003051 frame_addr = regs->active_tc.gpr[29];
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01003052 trace_user_do_sigreturn(regs, frame_addr);
bellard579a97f2007-11-11 14:26:47 +00003053 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003054 goto badframe;
bellard106ec872006-06-27 21:08:10 +00003055
ths388bb212007-05-13 13:58:00 +00003056 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
Riku Voipiof5f601a2014-04-23 13:00:17 +03003057 __get_user(target_set.sig[i], &frame->sf_mask.sig[i]);
ths388bb212007-05-13 13:58:00 +00003058 }
bellard106ec872006-06-27 21:08:10 +00003059
ths388bb212007-05-13 13:58:00 +00003060 target_to_host_sigset_internal(&blocked, &target_set);
Peter Maydell9eede5b2016-05-27 15:51:46 +01003061 set_sigmask(&blocked);
bellard106ec872006-06-27 21:08:10 +00003062
Riku Voipio016d2e12014-04-23 11:19:48 +03003063 restore_sigcontext(regs, &frame->sf_sc);
bellard106ec872006-06-27 21:08:10 +00003064
3065#if 0
ths388bb212007-05-13 13:58:00 +00003066 /*
3067 * Don't let your children do this ...
3068 */
3069 __asm__ __volatile__(
bellard106ec872006-06-27 21:08:10 +00003070 "move\t$29, %0\n\t"
3071 "j\tsyscall_exit"
3072 :/* no outputs */
3073 :"r" (&regs));
ths388bb212007-05-13 13:58:00 +00003074 /* Unreached */
bellard106ec872006-06-27 21:08:10 +00003075#endif
ths3b46e622007-09-17 08:09:54 +00003076
thsb5dc7732008-06-27 10:02:35 +00003077 regs->active_tc.PC = regs->CP0_EPC;
Kwok Cheung Yeungea3164a2013-05-17 14:51:20 -07003078 mips_set_hflags_isa_mode_from_pc(regs);
ths388bb212007-05-13 13:58:00 +00003079 /* I am not sure this is right, but it seems to work
bellard106ec872006-06-27 21:08:10 +00003080 * maybe a problem with nested signals ? */
3081 regs->CP0_EPC = 0;
pbrook0b1bcb02009-04-21 01:41:10 +00003082 return -TARGET_QEMU_ESIGRETURN;
bellard106ec872006-06-27 21:08:10 +00003083
3084badframe:
ths388bb212007-05-13 13:58:00 +00003085 force_sig(TARGET_SIGSEGV/*, current*/);
3086 return 0;
bellard106ec872006-06-27 21:08:10 +00003087}
Richard Hendersonff970902013-02-10 10:30:42 -08003088# endif /* O32 */
bellard106ec872006-06-27 21:08:10 +00003089
pbrook624f7972008-05-31 16:11:38 +00003090static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05003091 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01003092 target_sigset_t *set, CPUMIPSState *env)
bellard106ec872006-06-27 21:08:10 +00003093{
pbrook0b1bcb02009-04-21 01:41:10 +00003094 struct target_rt_sigframe *frame;
3095 abi_ulong frame_addr;
3096 int i;
3097
3098 frame_addr = get_sigframe(ka, env, sizeof(*frame));
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01003099 trace_user_setup_rt_frame(env, frame_addr);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003100 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
3101 goto give_sigsegv;
3102 }
pbrook0b1bcb02009-04-21 01:41:10 +00003103
3104 install_sigtramp(frame->rs_code, TARGET_NR_rt_sigreturn);
3105
Peter Maydellf6c7a052015-01-08 12:19:48 +00003106 tswap_siginfo(&frame->rs_info, info);
pbrook0b1bcb02009-04-21 01:41:10 +00003107
Aurelien Jarno60e99242010-03-29 02:12:51 +02003108 __put_user(0, &frame->rs_uc.tuc_flags);
3109 __put_user(0, &frame->rs_uc.tuc_link);
3110 __put_user(target_sigaltstack_used.ss_sp, &frame->rs_uc.tuc_stack.ss_sp);
3111 __put_user(target_sigaltstack_used.ss_size, &frame->rs_uc.tuc_stack.ss_size);
pbrook0b1bcb02009-04-21 01:41:10 +00003112 __put_user(sas_ss_flags(get_sp_from_cpustate(env)),
Aurelien Jarno60e99242010-03-29 02:12:51 +02003113 &frame->rs_uc.tuc_stack.ss_flags);
pbrook0b1bcb02009-04-21 01:41:10 +00003114
Aurelien Jarno60e99242010-03-29 02:12:51 +02003115 setup_sigcontext(env, &frame->rs_uc.tuc_mcontext);
pbrook0b1bcb02009-04-21 01:41:10 +00003116
3117 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
Aurelien Jarno60e99242010-03-29 02:12:51 +02003118 __put_user(set->sig[i], &frame->rs_uc.tuc_sigmask.sig[i]);
pbrook0b1bcb02009-04-21 01:41:10 +00003119 }
3120
3121 /*
3122 * Arguments to signal handler:
3123 *
3124 * a0 = signal number
Richard W.M. Jones02d2bd52012-07-05 03:32:44 +00003125 * a1 = pointer to siginfo_t
pbrook0b1bcb02009-04-21 01:41:10 +00003126 * a2 = pointer to struct ucontext
3127 *
3128 * $25 and PC point to the signal handler, $29 points to the
3129 * struct sigframe.
3130 */
3131 env->active_tc.gpr[ 4] = sig;
3132 env->active_tc.gpr[ 5] = frame_addr
3133 + offsetof(struct target_rt_sigframe, rs_info);
3134 env->active_tc.gpr[ 6] = frame_addr
3135 + offsetof(struct target_rt_sigframe, rs_uc);
3136 env->active_tc.gpr[29] = frame_addr;
3137 env->active_tc.gpr[31] = frame_addr
3138 + offsetof(struct target_rt_sigframe, rs_code);
3139 /* The original kernel code sets CP0_EPC to the handler
3140 * since it returns to userland using eret
3141 * we cannot do this here, and we must set PC directly */
3142 env->active_tc.PC = env->active_tc.gpr[25] = ka->_sa_handler;
Kwok Cheung Yeungea3164a2013-05-17 14:51:20 -07003143 mips_set_hflags_isa_mode_from_pc(env);
pbrook0b1bcb02009-04-21 01:41:10 +00003144 unlock_user_struct(frame, frame_addr, 1);
3145 return;
3146
3147give_sigsegv:
3148 unlock_user_struct(frame, frame_addr, 1);
3149 force_sig(TARGET_SIGSEGV/*, current*/);
bellard106ec872006-06-27 21:08:10 +00003150}
3151
Andreas Färber05390242012-02-25 03:37:53 +01003152long do_rt_sigreturn(CPUMIPSState *env)
bellard106ec872006-06-27 21:08:10 +00003153{
pbrook0b1bcb02009-04-21 01:41:10 +00003154 struct target_rt_sigframe *frame;
3155 abi_ulong frame_addr;
3156 sigset_t blocked;
3157
pbrook0b1bcb02009-04-21 01:41:10 +00003158 frame_addr = env->active_tc.gpr[29];
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01003159 trace_user_do_rt_sigreturn(env, frame_addr);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003160 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
3161 goto badframe;
3162 }
pbrook0b1bcb02009-04-21 01:41:10 +00003163
Aurelien Jarno60e99242010-03-29 02:12:51 +02003164 target_to_host_sigset(&blocked, &frame->rs_uc.tuc_sigmask);
Peter Maydell9eede5b2016-05-27 15:51:46 +01003165 set_sigmask(&blocked);
pbrook0b1bcb02009-04-21 01:41:10 +00003166
Riku Voipio016d2e12014-04-23 11:19:48 +03003167 restore_sigcontext(env, &frame->rs_uc.tuc_mcontext);
pbrook0b1bcb02009-04-21 01:41:10 +00003168
3169 if (do_sigaltstack(frame_addr +
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003170 offsetof(struct target_rt_sigframe, rs_uc.tuc_stack),
3171 0, get_sp_from_cpustate(env)) == -EFAULT)
pbrook0b1bcb02009-04-21 01:41:10 +00003172 goto badframe;
3173
3174 env->active_tc.PC = env->CP0_EPC;
Kwok Cheung Yeungea3164a2013-05-17 14:51:20 -07003175 mips_set_hflags_isa_mode_from_pc(env);
pbrook0b1bcb02009-04-21 01:41:10 +00003176 /* I am not sure this is right, but it seems to work
3177 * maybe a problem with nested signals ? */
3178 env->CP0_EPC = 0;
3179 return -TARGET_QEMU_ESIGRETURN;
3180
3181badframe:
3182 force_sig(TARGET_SIGSEGV/*, current*/);
3183 return 0;
bellard106ec872006-06-27 21:08:10 +00003184}
bellard6d5e2162004-09-30 22:04:13 +00003185
thsc3b5bc82007-12-02 06:31:25 +00003186#elif defined(TARGET_SH4)
3187
3188/*
3189 * code and data structures from linux kernel:
3190 * include/asm-sh/sigcontext.h
3191 * arch/sh/kernel/signal.c
3192 */
3193
3194struct target_sigcontext {
3195 target_ulong oldmask;
3196
3197 /* CPU registers */
3198 target_ulong sc_gregs[16];
3199 target_ulong sc_pc;
3200 target_ulong sc_pr;
3201 target_ulong sc_sr;
3202 target_ulong sc_gbr;
3203 target_ulong sc_mach;
3204 target_ulong sc_macl;
3205
3206 /* FPU registers */
3207 target_ulong sc_fpregs[16];
3208 target_ulong sc_xfpregs[16];
3209 unsigned int sc_fpscr;
3210 unsigned int sc_fpul;
3211 unsigned int sc_ownedfp;
3212};
3213
3214struct target_sigframe
3215{
3216 struct target_sigcontext sc;
3217 target_ulong extramask[TARGET_NSIG_WORDS-1];
3218 uint16_t retcode[3];
3219};
3220
3221
3222struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02003223 target_ulong tuc_flags;
3224 struct target_ucontext *tuc_link;
3225 target_stack_t tuc_stack;
3226 struct target_sigcontext tuc_mcontext;
3227 target_sigset_t tuc_sigmask; /* mask last for extensibility */
thsc3b5bc82007-12-02 06:31:25 +00003228};
3229
3230struct target_rt_sigframe
3231{
3232 struct target_siginfo info;
3233 struct target_ucontext uc;
3234 uint16_t retcode[3];
3235};
3236
3237
3238#define MOVW(n) (0x9300|((n)-2)) /* Move mem word at PC+n to R3 */
3239#define TRAP_NOARG 0xc310 /* Syscall w/no args (NR in R3) SH3/4 */
3240
pbrook624f7972008-05-31 16:11:38 +00003241static abi_ulong get_sigframe(struct target_sigaction *ka,
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003242 unsigned long sp, size_t frame_size)
thsc3b5bc82007-12-02 06:31:25 +00003243{
pbrook624f7972008-05-31 16:11:38 +00003244 if ((ka->sa_flags & TARGET_SA_ONSTACK) && (sas_ss_flags(sp) == 0)) {
thsc3b5bc82007-12-02 06:31:25 +00003245 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
3246 }
3247
3248 return (sp - frame_size) & -8ul;
3249}
3250
Riku Voipio41ecc722014-04-23 11:01:00 +03003251static void setup_sigcontext(struct target_sigcontext *sc,
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003252 CPUSH4State *regs, unsigned long mask)
thsc3b5bc82007-12-02 06:31:25 +00003253{
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003254 int i;
thsc3b5bc82007-12-02 06:31:25 +00003255
Riku Voipio1d8b5122014-04-23 10:26:05 +03003256#define COPY(x) __put_user(regs->x, &sc->sc_##x)
thsc3b5bc82007-12-02 06:31:25 +00003257 COPY(gregs[0]); COPY(gregs[1]);
3258 COPY(gregs[2]); COPY(gregs[3]);
3259 COPY(gregs[4]); COPY(gregs[5]);
3260 COPY(gregs[6]); COPY(gregs[7]);
3261 COPY(gregs[8]); COPY(gregs[9]);
3262 COPY(gregs[10]); COPY(gregs[11]);
3263 COPY(gregs[12]); COPY(gregs[13]);
3264 COPY(gregs[14]); COPY(gregs[15]);
3265 COPY(gbr); COPY(mach);
3266 COPY(macl); COPY(pr);
3267 COPY(sr); COPY(pc);
3268#undef COPY
3269
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003270 for (i=0; i<16; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03003271 __put_user(regs->fregs[i], &sc->sc_fpregs[i]);
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003272 }
Riku Voipio1d8b5122014-04-23 10:26:05 +03003273 __put_user(regs->fpscr, &sc->sc_fpscr);
3274 __put_user(regs->fpul, &sc->sc_fpul);
thsc3b5bc82007-12-02 06:31:25 +00003275
3276 /* non-iBCS2 extensions.. */
Riku Voipio1d8b5122014-04-23 10:26:05 +03003277 __put_user(mask, &sc->oldmask);
thsc3b5bc82007-12-02 06:31:25 +00003278}
3279
Timothy E Baldwinba412492016-05-12 18:47:35 +01003280static void restore_sigcontext(CPUSH4State *regs, struct target_sigcontext *sc)
thsc3b5bc82007-12-02 06:31:25 +00003281{
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003282 int i;
thsc3b5bc82007-12-02 06:31:25 +00003283
Riku Voipio1d8b5122014-04-23 10:26:05 +03003284#define COPY(x) __get_user(regs->x, &sc->sc_##x)
Timothy E Baldwinba412492016-05-12 18:47:35 +01003285 COPY(gregs[0]); COPY(gregs[1]);
thsc3b5bc82007-12-02 06:31:25 +00003286 COPY(gregs[2]); COPY(gregs[3]);
3287 COPY(gregs[4]); COPY(gregs[5]);
3288 COPY(gregs[6]); COPY(gregs[7]);
3289 COPY(gregs[8]); COPY(gregs[9]);
3290 COPY(gregs[10]); COPY(gregs[11]);
3291 COPY(gregs[12]); COPY(gregs[13]);
3292 COPY(gregs[14]); COPY(gregs[15]);
3293 COPY(gbr); COPY(mach);
3294 COPY(macl); COPY(pr);
3295 COPY(sr); COPY(pc);
3296#undef COPY
3297
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003298 for (i=0; i<16; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03003299 __get_user(regs->fregs[i], &sc->sc_fpregs[i]);
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003300 }
Riku Voipio1d8b5122014-04-23 10:26:05 +03003301 __get_user(regs->fpscr, &sc->sc_fpscr);
3302 __get_user(regs->fpul, &sc->sc_fpul);
thsc3b5bc82007-12-02 06:31:25 +00003303
3304 regs->tra = -1; /* disable syscall checks */
thsc3b5bc82007-12-02 06:31:25 +00003305}
3306
pbrook624f7972008-05-31 16:11:38 +00003307static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01003308 target_sigset_t *set, CPUSH4State *regs)
thsc3b5bc82007-12-02 06:31:25 +00003309{
3310 struct target_sigframe *frame;
3311 abi_ulong frame_addr;
3312 int i;
thsc3b5bc82007-12-02 06:31:25 +00003313
3314 frame_addr = get_sigframe(ka, regs->gregs[15], sizeof(*frame));
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01003315 trace_user_setup_frame(regs, frame_addr);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003316 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
3317 goto give_sigsegv;
3318 }
thsc3b5bc82007-12-02 06:31:25 +00003319
Riku Voipio41ecc722014-04-23 11:01:00 +03003320 setup_sigcontext(&frame->sc, regs, set->sig[0]);
thsc3b5bc82007-12-02 06:31:25 +00003321
3322 for (i = 0; i < TARGET_NSIG_WORDS - 1; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03003323 __put_user(set->sig[i + 1], &frame->extramask[i]);
thsc3b5bc82007-12-02 06:31:25 +00003324 }
3325
3326 /* Set up to return from userspace. If provided, use a stub
3327 already in userspace. */
pbrook624f7972008-05-31 16:11:38 +00003328 if (ka->sa_flags & TARGET_SA_RESTORER) {
3329 regs->pr = (unsigned long) ka->sa_restorer;
thsc3b5bc82007-12-02 06:31:25 +00003330 } else {
3331 /* Generate return code (system call to sigreturn) */
Laurent Vivier2a0fa682015-11-23 11:38:26 +01003332 abi_ulong retcode_addr = frame_addr +
3333 offsetof(struct target_sigframe, retcode);
Riku Voipio1d8b5122014-04-23 10:26:05 +03003334 __put_user(MOVW(2), &frame->retcode[0]);
3335 __put_user(TRAP_NOARG, &frame->retcode[1]);
3336 __put_user((TARGET_NR_sigreturn), &frame->retcode[2]);
Laurent Vivier2a0fa682015-11-23 11:38:26 +01003337 regs->pr = (unsigned long) retcode_addr;
thsc3b5bc82007-12-02 06:31:25 +00003338 }
3339
thsc3b5bc82007-12-02 06:31:25 +00003340 /* Set up registers for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003341 regs->gregs[15] = frame_addr;
Peter Maydellb6e2c932015-01-08 12:19:43 +00003342 regs->gregs[4] = sig; /* Arg for signal handler */
thsc3b5bc82007-12-02 06:31:25 +00003343 regs->gregs[5] = 0;
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003344 regs->gregs[6] = frame_addr += offsetof(typeof(*frame), sc);
pbrook624f7972008-05-31 16:11:38 +00003345 regs->pc = (unsigned long) ka->_sa_handler;
thsc3b5bc82007-12-02 06:31:25 +00003346
3347 unlock_user_struct(frame, frame_addr, 1);
3348 return;
3349
3350give_sigsegv:
3351 unlock_user_struct(frame, frame_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02003352 force_sig(TARGET_SIGSEGV);
thsc3b5bc82007-12-02 06:31:25 +00003353}
3354
pbrook624f7972008-05-31 16:11:38 +00003355static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05003356 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01003357 target_sigset_t *set, CPUSH4State *regs)
thsc3b5bc82007-12-02 06:31:25 +00003358{
3359 struct target_rt_sigframe *frame;
3360 abi_ulong frame_addr;
3361 int i;
thsc3b5bc82007-12-02 06:31:25 +00003362
3363 frame_addr = get_sigframe(ka, regs->gregs[15], sizeof(*frame));
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01003364 trace_user_setup_rt_frame(regs, frame_addr);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003365 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
3366 goto give_sigsegv;
3367 }
thsc3b5bc82007-12-02 06:31:25 +00003368
Peter Maydellf6c7a052015-01-08 12:19:48 +00003369 tswap_siginfo(&frame->info, info);
thsc3b5bc82007-12-02 06:31:25 +00003370
3371 /* Create the ucontext. */
Riku Voipio1d8b5122014-04-23 10:26:05 +03003372 __put_user(0, &frame->uc.tuc_flags);
3373 __put_user(0, (unsigned long *)&frame->uc.tuc_link);
3374 __put_user((unsigned long)target_sigaltstack_used.ss_sp,
3375 &frame->uc.tuc_stack.ss_sp);
3376 __put_user(sas_ss_flags(regs->gregs[15]),
3377 &frame->uc.tuc_stack.ss_flags);
3378 __put_user(target_sigaltstack_used.ss_size,
3379 &frame->uc.tuc_stack.ss_size);
3380 setup_sigcontext(&frame->uc.tuc_mcontext,
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003381 regs, set->sig[0]);
thsc3b5bc82007-12-02 06:31:25 +00003382 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03003383 __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
thsc3b5bc82007-12-02 06:31:25 +00003384 }
3385
3386 /* Set up to return from userspace. If provided, use a stub
3387 already in userspace. */
pbrook624f7972008-05-31 16:11:38 +00003388 if (ka->sa_flags & TARGET_SA_RESTORER) {
3389 regs->pr = (unsigned long) ka->sa_restorer;
thsc3b5bc82007-12-02 06:31:25 +00003390 } else {
3391 /* Generate return code (system call to sigreturn) */
Laurent Vivier2a0fa682015-11-23 11:38:26 +01003392 abi_ulong retcode_addr = frame_addr +
3393 offsetof(struct target_rt_sigframe, retcode);
Riku Voipio1d8b5122014-04-23 10:26:05 +03003394 __put_user(MOVW(2), &frame->retcode[0]);
3395 __put_user(TRAP_NOARG, &frame->retcode[1]);
3396 __put_user((TARGET_NR_rt_sigreturn), &frame->retcode[2]);
Laurent Vivier2a0fa682015-11-23 11:38:26 +01003397 regs->pr = (unsigned long) retcode_addr;
thsc3b5bc82007-12-02 06:31:25 +00003398 }
3399
thsc3b5bc82007-12-02 06:31:25 +00003400 /* Set up registers for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003401 regs->gregs[15] = frame_addr;
Peter Maydellb6e2c932015-01-08 12:19:43 +00003402 regs->gregs[4] = sig; /* Arg for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003403 regs->gregs[5] = frame_addr + offsetof(typeof(*frame), info);
3404 regs->gregs[6] = frame_addr + offsetof(typeof(*frame), uc);
pbrook624f7972008-05-31 16:11:38 +00003405 regs->pc = (unsigned long) ka->_sa_handler;
thsc3b5bc82007-12-02 06:31:25 +00003406
3407 unlock_user_struct(frame, frame_addr, 1);
3408 return;
3409
3410give_sigsegv:
3411 unlock_user_struct(frame, frame_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02003412 force_sig(TARGET_SIGSEGV);
thsc3b5bc82007-12-02 06:31:25 +00003413}
3414
Andreas Färber05390242012-02-25 03:37:53 +01003415long do_sigreturn(CPUSH4State *regs)
thsc3b5bc82007-12-02 06:31:25 +00003416{
3417 struct target_sigframe *frame;
3418 abi_ulong frame_addr;
3419 sigset_t blocked;
Anthony Liguoric227f092009-10-01 16:12:16 -05003420 target_sigset_t target_set;
thsc3b5bc82007-12-02 06:31:25 +00003421 int i;
3422 int err = 0;
3423
thsc3b5bc82007-12-02 06:31:25 +00003424 frame_addr = regs->gregs[15];
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01003425 trace_user_do_sigreturn(regs, frame_addr);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003426 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
3427 goto badframe;
3428 }
thsc3b5bc82007-12-02 06:31:25 +00003429
Riku Voipio1d8b5122014-04-23 10:26:05 +03003430 __get_user(target_set.sig[0], &frame->sc.oldmask);
thsc3b5bc82007-12-02 06:31:25 +00003431 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03003432 __get_user(target_set.sig[i], &frame->extramask[i - 1]);
thsc3b5bc82007-12-02 06:31:25 +00003433 }
3434
3435 if (err)
3436 goto badframe;
3437
3438 target_to_host_sigset_internal(&blocked, &target_set);
Peter Maydell9eede5b2016-05-27 15:51:46 +01003439 set_sigmask(&blocked);
thsc3b5bc82007-12-02 06:31:25 +00003440
Timothy E Baldwinba412492016-05-12 18:47:35 +01003441 restore_sigcontext(regs, &frame->sc);
thsc3b5bc82007-12-02 06:31:25 +00003442
3443 unlock_user_struct(frame, frame_addr, 0);
Timothy E Baldwinba412492016-05-12 18:47:35 +01003444 return -TARGET_QEMU_ESIGRETURN;
thsc3b5bc82007-12-02 06:31:25 +00003445
3446badframe:
3447 unlock_user_struct(frame, frame_addr, 0);
3448 force_sig(TARGET_SIGSEGV);
3449 return 0;
3450}
3451
Andreas Färber05390242012-02-25 03:37:53 +01003452long do_rt_sigreturn(CPUSH4State *regs)
thsc3b5bc82007-12-02 06:31:25 +00003453{
3454 struct target_rt_sigframe *frame;
3455 abi_ulong frame_addr;
3456 sigset_t blocked;
3457
thsc3b5bc82007-12-02 06:31:25 +00003458 frame_addr = regs->gregs[15];
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01003459 trace_user_do_rt_sigreturn(regs, frame_addr);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003460 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
3461 goto badframe;
3462 }
thsc3b5bc82007-12-02 06:31:25 +00003463
Aurelien Jarno60e99242010-03-29 02:12:51 +02003464 target_to_host_sigset(&blocked, &frame->uc.tuc_sigmask);
Peter Maydell9eede5b2016-05-27 15:51:46 +01003465 set_sigmask(&blocked);
thsc3b5bc82007-12-02 06:31:25 +00003466
Timothy E Baldwinba412492016-05-12 18:47:35 +01003467 restore_sigcontext(regs, &frame->uc.tuc_mcontext);
thsc3b5bc82007-12-02 06:31:25 +00003468
3469 if (do_sigaltstack(frame_addr +
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003470 offsetof(struct target_rt_sigframe, uc.tuc_stack),
3471 0, get_sp_from_cpustate(regs)) == -EFAULT) {
thsc3b5bc82007-12-02 06:31:25 +00003472 goto badframe;
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003473 }
thsc3b5bc82007-12-02 06:31:25 +00003474
3475 unlock_user_struct(frame, frame_addr, 0);
Timothy E Baldwinba412492016-05-12 18:47:35 +01003476 return -TARGET_QEMU_ESIGRETURN;
thsc3b5bc82007-12-02 06:31:25 +00003477
3478badframe:
3479 unlock_user_struct(frame, frame_addr, 0);
3480 force_sig(TARGET_SIGSEGV);
3481 return 0;
3482}
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003483#elif defined(TARGET_MICROBLAZE)
3484
3485struct target_sigcontext {
3486 struct target_pt_regs regs; /* needs to be first */
3487 uint32_t oldmask;
3488};
3489
Edgar E. Iglesiasb2178702010-07-23 09:30:37 +02003490struct target_stack_t {
3491 abi_ulong ss_sp;
3492 int ss_flags;
3493 unsigned int ss_size;
3494};
3495
3496struct target_ucontext {
Richard Hendersonf711df62010-11-22 14:57:52 -08003497 abi_ulong tuc_flags;
3498 abi_ulong tuc_link;
3499 struct target_stack_t tuc_stack;
3500 struct target_sigcontext tuc_mcontext;
3501 uint32_t tuc_extramask[TARGET_NSIG_WORDS - 1];
Edgar E. Iglesiasb2178702010-07-23 09:30:37 +02003502};
3503
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003504/* Signal frames. */
3505struct target_signal_frame {
Edgar E. Iglesiasb2178702010-07-23 09:30:37 +02003506 struct target_ucontext uc;
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003507 uint32_t extramask[TARGET_NSIG_WORDS - 1];
3508 uint32_t tramp[2];
3509};
3510
3511struct rt_signal_frame {
Richard W.M. Jones02d2bd52012-07-05 03:32:44 +00003512 siginfo_t info;
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003513 struct ucontext uc;
3514 uint32_t tramp[2];
3515};
3516
Andreas Färber05390242012-02-25 03:37:53 +01003517static void setup_sigcontext(struct target_sigcontext *sc, CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003518{
3519 __put_user(env->regs[0], &sc->regs.r0);
3520 __put_user(env->regs[1], &sc->regs.r1);
3521 __put_user(env->regs[2], &sc->regs.r2);
3522 __put_user(env->regs[3], &sc->regs.r3);
3523 __put_user(env->regs[4], &sc->regs.r4);
3524 __put_user(env->regs[5], &sc->regs.r5);
3525 __put_user(env->regs[6], &sc->regs.r6);
3526 __put_user(env->regs[7], &sc->regs.r7);
3527 __put_user(env->regs[8], &sc->regs.r8);
3528 __put_user(env->regs[9], &sc->regs.r9);
3529 __put_user(env->regs[10], &sc->regs.r10);
3530 __put_user(env->regs[11], &sc->regs.r11);
3531 __put_user(env->regs[12], &sc->regs.r12);
3532 __put_user(env->regs[13], &sc->regs.r13);
3533 __put_user(env->regs[14], &sc->regs.r14);
3534 __put_user(env->regs[15], &sc->regs.r15);
3535 __put_user(env->regs[16], &sc->regs.r16);
3536 __put_user(env->regs[17], &sc->regs.r17);
3537 __put_user(env->regs[18], &sc->regs.r18);
3538 __put_user(env->regs[19], &sc->regs.r19);
3539 __put_user(env->regs[20], &sc->regs.r20);
3540 __put_user(env->regs[21], &sc->regs.r21);
3541 __put_user(env->regs[22], &sc->regs.r22);
3542 __put_user(env->regs[23], &sc->regs.r23);
3543 __put_user(env->regs[24], &sc->regs.r24);
3544 __put_user(env->regs[25], &sc->regs.r25);
3545 __put_user(env->regs[26], &sc->regs.r26);
3546 __put_user(env->regs[27], &sc->regs.r27);
3547 __put_user(env->regs[28], &sc->regs.r28);
3548 __put_user(env->regs[29], &sc->regs.r29);
3549 __put_user(env->regs[30], &sc->regs.r30);
3550 __put_user(env->regs[31], &sc->regs.r31);
3551 __put_user(env->sregs[SR_PC], &sc->regs.pc);
3552}
3553
Andreas Färber05390242012-02-25 03:37:53 +01003554static void restore_sigcontext(struct target_sigcontext *sc, CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003555{
3556 __get_user(env->regs[0], &sc->regs.r0);
3557 __get_user(env->regs[1], &sc->regs.r1);
3558 __get_user(env->regs[2], &sc->regs.r2);
3559 __get_user(env->regs[3], &sc->regs.r3);
3560 __get_user(env->regs[4], &sc->regs.r4);
3561 __get_user(env->regs[5], &sc->regs.r5);
3562 __get_user(env->regs[6], &sc->regs.r6);
3563 __get_user(env->regs[7], &sc->regs.r7);
3564 __get_user(env->regs[8], &sc->regs.r8);
3565 __get_user(env->regs[9], &sc->regs.r9);
3566 __get_user(env->regs[10], &sc->regs.r10);
3567 __get_user(env->regs[11], &sc->regs.r11);
3568 __get_user(env->regs[12], &sc->regs.r12);
3569 __get_user(env->regs[13], &sc->regs.r13);
3570 __get_user(env->regs[14], &sc->regs.r14);
3571 __get_user(env->regs[15], &sc->regs.r15);
3572 __get_user(env->regs[16], &sc->regs.r16);
3573 __get_user(env->regs[17], &sc->regs.r17);
3574 __get_user(env->regs[18], &sc->regs.r18);
3575 __get_user(env->regs[19], &sc->regs.r19);
3576 __get_user(env->regs[20], &sc->regs.r20);
3577 __get_user(env->regs[21], &sc->regs.r21);
3578 __get_user(env->regs[22], &sc->regs.r22);
3579 __get_user(env->regs[23], &sc->regs.r23);
3580 __get_user(env->regs[24], &sc->regs.r24);
3581 __get_user(env->regs[25], &sc->regs.r25);
3582 __get_user(env->regs[26], &sc->regs.r26);
3583 __get_user(env->regs[27], &sc->regs.r27);
3584 __get_user(env->regs[28], &sc->regs.r28);
3585 __get_user(env->regs[29], &sc->regs.r29);
3586 __get_user(env->regs[30], &sc->regs.r30);
3587 __get_user(env->regs[31], &sc->regs.r31);
3588 __get_user(env->sregs[SR_PC], &sc->regs.pc);
3589}
3590
3591static abi_ulong get_sigframe(struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01003592 CPUMBState *env, int frame_size)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003593{
3594 abi_ulong sp = env->regs[1];
3595
Riku Voipiob545f632014-07-15 17:01:55 +03003596 if ((ka->sa_flags & TARGET_SA_ONSTACK) != 0 && !on_sig_stack(sp)) {
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003597 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
Riku Voipiob545f632014-07-15 17:01:55 +03003598 }
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003599
3600 return ((sp - frame_size) & -8UL);
3601}
3602
3603static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01003604 target_sigset_t *set, CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003605{
3606 struct target_signal_frame *frame;
3607 abi_ulong frame_addr;
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003608 int i;
3609
3610 frame_addr = get_sigframe(ka, env, sizeof *frame);
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01003611 trace_user_setup_frame(env, frame_addr);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003612 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
3613 goto badframe;
3614
3615 /* Save the mask. */
Riku Voipio1d8b5122014-04-23 10:26:05 +03003616 __put_user(set->sig[0], &frame->uc.tuc_mcontext.oldmask);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003617
3618 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
Riku Voipio0188fad2014-04-23 13:34:15 +03003619 __put_user(set->sig[i], &frame->extramask[i - 1]);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003620 }
3621
Richard Hendersonf711df62010-11-22 14:57:52 -08003622 setup_sigcontext(&frame->uc.tuc_mcontext, env);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003623
3624 /* Set up to return from userspace. If provided, use a stub
3625 already in userspace. */
3626 /* minus 8 is offset to cater for "rtsd r15,8" offset */
3627 if (ka->sa_flags & TARGET_SA_RESTORER) {
3628 env->regs[15] = ((unsigned long)ka->sa_restorer)-8;
3629 } else {
3630 uint32_t t;
3631 /* Note, these encodings are _big endian_! */
3632 /* addi r12, r0, __NR_sigreturn */
3633 t = 0x31800000UL | TARGET_NR_sigreturn;
Riku Voipio1d8b5122014-04-23 10:26:05 +03003634 __put_user(t, frame->tramp + 0);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003635 /* brki r14, 0x8 */
3636 t = 0xb9cc0008UL;
Riku Voipio1d8b5122014-04-23 10:26:05 +03003637 __put_user(t, frame->tramp + 1);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003638
3639 /* Return from sighandler will jump to the tramp.
3640 Negative 8 offset because return is rtsd r15, 8 */
Chen Gang166c97e2016-03-29 22:13:45 +08003641 env->regs[15] = frame_addr + offsetof(struct target_signal_frame, tramp)
3642 - 8;
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003643 }
3644
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003645 /* Set up registers for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003646 env->regs[1] = frame_addr;
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003647 /* Signal handler args: */
3648 env->regs[5] = sig; /* Arg 0: signum */
Edgar E. Iglesias187b4e02010-07-15 15:32:51 +02003649 env->regs[6] = 0;
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003650 /* arg 1: sigcontext */
3651 env->regs[7] = frame_addr += offsetof(typeof(*frame), uc);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003652
3653 /* Offset of 4 to handle microblaze rtid r14, 0 */
3654 env->sregs[SR_PC] = (unsigned long)ka->_sa_handler;
3655
3656 unlock_user_struct(frame, frame_addr, 1);
3657 return;
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003658badframe:
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003659 force_sig(TARGET_SIGSEGV);
3660}
3661
3662static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05003663 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01003664 target_sigset_t *set, CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003665{
3666 fprintf(stderr, "Microblaze setup_rt_frame: not implemented\n");
3667}
3668
Andreas Färber05390242012-02-25 03:37:53 +01003669long do_sigreturn(CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003670{
3671 struct target_signal_frame *frame;
3672 abi_ulong frame_addr;
Anthony Liguoric227f092009-10-01 16:12:16 -05003673 target_sigset_t target_set;
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003674 sigset_t set;
3675 int i;
3676
3677 frame_addr = env->regs[R_SP];
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01003678 trace_user_do_sigreturn(env, frame_addr);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003679 /* Make sure the guest isn't playing games. */
3680 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 1))
3681 goto badframe;
3682
3683 /* Restore blocked signals */
Riku Voipiof5f601a2014-04-23 13:00:17 +03003684 __get_user(target_set.sig[0], &frame->uc.tuc_mcontext.oldmask);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003685 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003686 __get_user(target_set.sig[i], &frame->extramask[i - 1]);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003687 }
3688 target_to_host_sigset_internal(&set, &target_set);
Peter Maydell9eede5b2016-05-27 15:51:46 +01003689 set_sigmask(&set);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003690
Richard Hendersonf711df62010-11-22 14:57:52 -08003691 restore_sigcontext(&frame->uc.tuc_mcontext, env);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003692 /* We got here through a sigreturn syscall, our path back is via an
3693 rtb insn so setup r14 for that. */
3694 env->regs[14] = env->sregs[SR_PC];
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003695
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003696 unlock_user_struct(frame, frame_addr, 0);
Timothy E Baldwin4134ecf2016-05-12 18:47:44 +01003697 return -TARGET_QEMU_ESIGRETURN;
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003698badframe:
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003699 force_sig(TARGET_SIGSEGV);
3700}
3701
Andreas Färber05390242012-02-25 03:37:53 +01003702long do_rt_sigreturn(CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003703{
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01003704 trace_user_do_rt_sigreturn(env, 0);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003705 fprintf(stderr, "Microblaze do_rt_sigreturn: not implemented\n");
3706 return -TARGET_ENOSYS;
3707}
3708
edgar_iglb6d3abd2008-02-28 11:29:27 +00003709#elif defined(TARGET_CRIS)
3710
3711struct target_sigcontext {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003712 struct target_pt_regs regs; /* needs to be first */
3713 uint32_t oldmask;
3714 uint32_t usp; /* usp before stacking this gunk on it */
edgar_iglb6d3abd2008-02-28 11:29:27 +00003715};
3716
3717/* Signal frames. */
3718struct target_signal_frame {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003719 struct target_sigcontext sc;
3720 uint32_t extramask[TARGET_NSIG_WORDS - 1];
3721 uint16_t retcode[4]; /* Trampoline code. */
edgar_iglb6d3abd2008-02-28 11:29:27 +00003722};
3723
3724struct rt_signal_frame {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003725 siginfo_t *pinfo;
3726 void *puc;
3727 siginfo_t info;
3728 struct ucontext uc;
3729 uint16_t retcode[4]; /* Trampoline code. */
edgar_iglb6d3abd2008-02-28 11:29:27 +00003730};
3731
Andreas Färber05390242012-02-25 03:37:53 +01003732static void setup_sigcontext(struct target_sigcontext *sc, CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003733{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003734 __put_user(env->regs[0], &sc->regs.r0);
3735 __put_user(env->regs[1], &sc->regs.r1);
3736 __put_user(env->regs[2], &sc->regs.r2);
3737 __put_user(env->regs[3], &sc->regs.r3);
3738 __put_user(env->regs[4], &sc->regs.r4);
3739 __put_user(env->regs[5], &sc->regs.r5);
3740 __put_user(env->regs[6], &sc->regs.r6);
3741 __put_user(env->regs[7], &sc->regs.r7);
3742 __put_user(env->regs[8], &sc->regs.r8);
3743 __put_user(env->regs[9], &sc->regs.r9);
3744 __put_user(env->regs[10], &sc->regs.r10);
3745 __put_user(env->regs[11], &sc->regs.r11);
3746 __put_user(env->regs[12], &sc->regs.r12);
3747 __put_user(env->regs[13], &sc->regs.r13);
3748 __put_user(env->regs[14], &sc->usp);
3749 __put_user(env->regs[15], &sc->regs.acr);
3750 __put_user(env->pregs[PR_MOF], &sc->regs.mof);
3751 __put_user(env->pregs[PR_SRP], &sc->regs.srp);
3752 __put_user(env->pc, &sc->regs.erp);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003753}
edgar_igl9664d922008-03-03 22:23:53 +00003754
Andreas Färber05390242012-02-25 03:37:53 +01003755static void restore_sigcontext(struct target_sigcontext *sc, CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003756{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003757 __get_user(env->regs[0], &sc->regs.r0);
3758 __get_user(env->regs[1], &sc->regs.r1);
3759 __get_user(env->regs[2], &sc->regs.r2);
3760 __get_user(env->regs[3], &sc->regs.r3);
3761 __get_user(env->regs[4], &sc->regs.r4);
3762 __get_user(env->regs[5], &sc->regs.r5);
3763 __get_user(env->regs[6], &sc->regs.r6);
3764 __get_user(env->regs[7], &sc->regs.r7);
3765 __get_user(env->regs[8], &sc->regs.r8);
3766 __get_user(env->regs[9], &sc->regs.r9);
3767 __get_user(env->regs[10], &sc->regs.r10);
3768 __get_user(env->regs[11], &sc->regs.r11);
3769 __get_user(env->regs[12], &sc->regs.r12);
3770 __get_user(env->regs[13], &sc->regs.r13);
3771 __get_user(env->regs[14], &sc->usp);
3772 __get_user(env->regs[15], &sc->regs.acr);
3773 __get_user(env->pregs[PR_MOF], &sc->regs.mof);
3774 __get_user(env->pregs[PR_SRP], &sc->regs.srp);
3775 __get_user(env->pc, &sc->regs.erp);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003776}
3777
Andreas Färber05390242012-02-25 03:37:53 +01003778static abi_ulong get_sigframe(CPUCRISState *env, int framesize)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003779{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003780 abi_ulong sp;
3781 /* Align the stack downwards to 4. */
3782 sp = (env->regs[R_SP] & ~3);
3783 return sp - framesize;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003784}
3785
pbrook624f7972008-05-31 16:11:38 +00003786static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01003787 target_sigset_t *set, CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003788{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003789 struct target_signal_frame *frame;
3790 abi_ulong frame_addr;
3791 int i;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003792
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003793 frame_addr = get_sigframe(env, sizeof *frame);
3794 trace_user_setup_frame(env, frame_addr);
3795 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
3796 goto badframe;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003797
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003798 /*
3799 * The CRIS signal return trampoline. A real linux/CRIS kernel doesn't
3800 * use this trampoline anymore but it sets it up for GDB.
3801 * In QEMU, using the trampoline simplifies things a bit so we use it.
3802 *
3803 * This is movu.w __NR_sigreturn, r9; break 13;
3804 */
Riku Voipio1d8b5122014-04-23 10:26:05 +03003805 __put_user(0x9c5f, frame->retcode+0);
3806 __put_user(TARGET_NR_sigreturn,
3807 frame->retcode + 1);
3808 __put_user(0xe93d, frame->retcode + 2);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003809
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003810 /* Save the mask. */
Riku Voipio1d8b5122014-04-23 10:26:05 +03003811 __put_user(set->sig[0], &frame->sc.oldmask);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003812
Riku Voipio0188fad2014-04-23 13:34:15 +03003813 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
3814 __put_user(set->sig[i], &frame->extramask[i - 1]);
3815 }
edgar_iglb6d3abd2008-02-28 11:29:27 +00003816
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003817 setup_sigcontext(&frame->sc, env);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003818
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003819 /* Move the stack and setup the arguments for the handler. */
3820 env->regs[R_SP] = frame_addr;
3821 env->regs[10] = sig;
3822 env->pc = (unsigned long) ka->_sa_handler;
3823 /* Link SRP so the guest returns through the trampoline. */
3824 env->pregs[PR_SRP] = frame_addr + offsetof(typeof(*frame), retcode);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003825
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003826 unlock_user_struct(frame, frame_addr, 1);
3827 return;
3828badframe:
3829 force_sig(TARGET_SIGSEGV);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003830}
3831
pbrook624f7972008-05-31 16:11:38 +00003832static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05003833 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01003834 target_sigset_t *set, CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003835{
3836 fprintf(stderr, "CRIS setup_rt_frame: not implemented\n");
3837}
3838
Andreas Färber05390242012-02-25 03:37:53 +01003839long do_sigreturn(CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003840{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003841 struct target_signal_frame *frame;
3842 abi_ulong frame_addr;
3843 target_sigset_t target_set;
3844 sigset_t set;
3845 int i;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003846
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003847 frame_addr = env->regs[R_SP];
3848 trace_user_do_sigreturn(env, frame_addr);
3849 /* Make sure the guest isn't playing games. */
3850 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 1)) {
3851 goto badframe;
3852 }
edgar_iglb6d3abd2008-02-28 11:29:27 +00003853
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003854 /* Restore blocked signals */
Riku Voipiof5f601a2014-04-23 13:00:17 +03003855 __get_user(target_set.sig[0], &frame->sc.oldmask);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003856 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
Riku Voipiof5f601a2014-04-23 13:00:17 +03003857 __get_user(target_set.sig[i], &frame->extramask[i - 1]);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003858 }
3859 target_to_host_sigset_internal(&set, &target_set);
Peter Maydell9eede5b2016-05-27 15:51:46 +01003860 set_sigmask(&set);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003861
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003862 restore_sigcontext(&frame->sc, env);
3863 unlock_user_struct(frame, frame_addr, 0);
Timothy E Baldwin62050862016-05-12 18:47:41 +01003864 return -TARGET_QEMU_ESIGRETURN;
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003865badframe:
3866 force_sig(TARGET_SIGSEGV);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003867}
3868
Andreas Färber05390242012-02-25 03:37:53 +01003869long do_rt_sigreturn(CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003870{
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01003871 trace_user_do_rt_sigreturn(env, 0);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003872 fprintf(stderr, "CRIS do_rt_sigreturn: not implemented\n");
3873 return -TARGET_ENOSYS;
3874}
thsc3b5bc82007-12-02 06:31:25 +00003875
Jia Liud9627832012-07-20 15:50:52 +08003876#elif defined(TARGET_OPENRISC)
3877
3878struct target_sigcontext {
3879 struct target_pt_regs regs;
3880 abi_ulong oldmask;
3881 abi_ulong usp;
3882};
3883
3884struct target_ucontext {
3885 abi_ulong tuc_flags;
3886 abi_ulong tuc_link;
3887 target_stack_t tuc_stack;
3888 struct target_sigcontext tuc_mcontext;
3889 target_sigset_t tuc_sigmask; /* mask last for extensibility */
3890};
3891
3892struct target_rt_sigframe {
3893 abi_ulong pinfo;
3894 uint64_t puc;
3895 struct target_siginfo info;
3896 struct target_sigcontext sc;
3897 struct target_ucontext uc;
3898 unsigned char retcode[16]; /* trampoline code */
3899};
3900
3901/* This is the asm-generic/ucontext.h version */
3902#if 0
3903static int restore_sigcontext(CPUOpenRISCState *regs,
3904 struct target_sigcontext *sc)
3905{
3906 unsigned int err = 0;
3907 unsigned long old_usp;
3908
3909 /* Alwys make any pending restarted system call return -EINTR */
3910 current_thread_info()->restart_block.fn = do_no_restart_syscall;
3911
3912 /* restore the regs from &sc->regs (same as sc, since regs is first)
3913 * (sc is already checked for VERIFY_READ since the sigframe was
3914 * checked in sys_sigreturn previously)
3915 */
3916
3917 if (copy_from_user(regs, &sc, sizeof(struct target_pt_regs))) {
3918 goto badframe;
3919 }
3920
3921 /* make sure the U-flag is set so user-mode cannot fool us */
3922
3923 regs->sr &= ~SR_SM;
3924
3925 /* restore the old USP as it was before we stacked the sc etc.
3926 * (we cannot just pop the sigcontext since we aligned the sp and
3927 * stuff after pushing it)
3928 */
3929
Riku Voipio1d8b5122014-04-23 10:26:05 +03003930 __get_user(old_usp, &sc->usp);
Jia Liud9627832012-07-20 15:50:52 +08003931 phx_signal("old_usp 0x%lx", old_usp);
3932
3933 __PHX__ REALLY /* ??? */
3934 wrusp(old_usp);
3935 regs->gpr[1] = old_usp;
3936
3937 /* TODO: the other ports use regs->orig_XX to disable syscall checks
3938 * after this completes, but we don't use that mechanism. maybe we can
3939 * use it now ?
3940 */
3941
3942 return err;
3943
3944badframe:
3945 return 1;
3946}
3947#endif
3948
3949/* Set up a signal frame. */
3950
Riku Voipio41ecc722014-04-23 11:01:00 +03003951static void setup_sigcontext(struct target_sigcontext *sc,
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003952 CPUOpenRISCState *regs,
3953 unsigned long mask)
Jia Liud9627832012-07-20 15:50:52 +08003954{
Jia Liud9627832012-07-20 15:50:52 +08003955 unsigned long usp = regs->gpr[1];
3956
3957 /* copy the regs. they are first in sc so we can use sc directly */
3958
Riku Voipio1d8b5122014-04-23 10:26:05 +03003959 /*copy_to_user(&sc, regs, sizeof(struct target_pt_regs));*/
Jia Liud9627832012-07-20 15:50:52 +08003960
3961 /* Set the frametype to CRIS_FRAME_NORMAL for the execution of
3962 the signal handler. The frametype will be restored to its previous
3963 value in restore_sigcontext. */
3964 /*regs->frametype = CRIS_FRAME_NORMAL;*/
3965
3966 /* then some other stuff */
Riku Voipio1d8b5122014-04-23 10:26:05 +03003967 __put_user(mask, &sc->oldmask);
Riku Voipio41ecc722014-04-23 11:01:00 +03003968 __put_user(usp, &sc->usp);
Jia Liud9627832012-07-20 15:50:52 +08003969}
3970
3971static inline unsigned long align_sigframe(unsigned long sp)
3972{
Eduardo Habkost9be38592016-06-13 18:57:58 -03003973 return sp & ~3UL;
Jia Liud9627832012-07-20 15:50:52 +08003974}
3975
3976static inline abi_ulong get_sigframe(struct target_sigaction *ka,
3977 CPUOpenRISCState *regs,
3978 size_t frame_size)
3979{
3980 unsigned long sp = regs->gpr[1];
3981 int onsigstack = on_sig_stack(sp);
3982
3983 /* redzone */
3984 /* This is the X/Open sanctioned signal stack switching. */
Riku Voipiob545f632014-07-15 17:01:55 +03003985 if ((ka->sa_flags & TARGET_SA_ONSTACK) != 0 && !onsigstack) {
Jia Liud9627832012-07-20 15:50:52 +08003986 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
3987 }
3988
3989 sp = align_sigframe(sp - frame_size);
3990
3991 /*
3992 * If we are on the alternate signal stack and would overflow it, don't.
3993 * Return an always-bogus address instead so we will die with SIGSEGV.
3994 */
3995
3996 if (onsigstack && !likely(on_sig_stack(sp))) {
3997 return -1L;
3998 }
3999
4000 return sp;
4001}
4002
Jia Liud9627832012-07-20 15:50:52 +08004003static void setup_rt_frame(int sig, struct target_sigaction *ka,
4004 target_siginfo_t *info,
4005 target_sigset_t *set, CPUOpenRISCState *env)
4006{
4007 int err = 0;
4008 abi_ulong frame_addr;
4009 unsigned long return_ip;
4010 struct target_rt_sigframe *frame;
4011 abi_ulong info_addr, uc_addr;
4012
Jia Liud9627832012-07-20 15:50:52 +08004013 frame_addr = get_sigframe(ka, env, sizeof(*frame));
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01004014 trace_user_setup_rt_frame(env, frame_addr);
Jia Liud9627832012-07-20 15:50:52 +08004015 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
4016 goto give_sigsegv;
4017 }
4018
4019 info_addr = frame_addr + offsetof(struct target_rt_sigframe, info);
Riku Voipio1d8b5122014-04-23 10:26:05 +03004020 __put_user(info_addr, &frame->pinfo);
Jia Liud9627832012-07-20 15:50:52 +08004021 uc_addr = frame_addr + offsetof(struct target_rt_sigframe, uc);
Riku Voipio1d8b5122014-04-23 10:26:05 +03004022 __put_user(uc_addr, &frame->puc);
Jia Liud9627832012-07-20 15:50:52 +08004023
4024 if (ka->sa_flags & SA_SIGINFO) {
Peter Maydellf6c7a052015-01-08 12:19:48 +00004025 tswap_siginfo(&frame->info, info);
Jia Liud9627832012-07-20 15:50:52 +08004026 }
4027
4028 /*err |= __clear_user(&frame->uc, offsetof(struct ucontext, uc_mcontext));*/
Riku Voipio1d8b5122014-04-23 10:26:05 +03004029 __put_user(0, &frame->uc.tuc_flags);
4030 __put_user(0, &frame->uc.tuc_link);
4031 __put_user(target_sigaltstack_used.ss_sp,
4032 &frame->uc.tuc_stack.ss_sp);
4033 __put_user(sas_ss_flags(env->gpr[1]), &frame->uc.tuc_stack.ss_flags);
4034 __put_user(target_sigaltstack_used.ss_size,
4035 &frame->uc.tuc_stack.ss_size);
Riku Voipio41ecc722014-04-23 11:01:00 +03004036 setup_sigcontext(&frame->sc, env, set->sig[0]);
Jia Liud9627832012-07-20 15:50:52 +08004037
4038 /*err |= copy_to_user(frame->uc.tuc_sigmask, set, sizeof(*set));*/
4039
Jia Liud9627832012-07-20 15:50:52 +08004040 /* trampoline - the desired return ip is the retcode itself */
4041 return_ip = (unsigned long)&frame->retcode;
4042 /* This is l.ori r11,r0,__NR_sigreturn, l.sys 1 */
Riku Voipio1d8b5122014-04-23 10:26:05 +03004043 __put_user(0xa960, (short *)(frame->retcode + 0));
4044 __put_user(TARGET_NR_rt_sigreturn, (short *)(frame->retcode + 2));
4045 __put_user(0x20000001, (unsigned long *)(frame->retcode + 4));
4046 __put_user(0x15000000, (unsigned long *)(frame->retcode + 8));
Jia Liud9627832012-07-20 15:50:52 +08004047
4048 if (err) {
4049 goto give_sigsegv;
4050 }
4051
4052 /* TODO what is the current->exec_domain stuff and invmap ? */
4053
4054 /* Set up registers for signal handler */
4055 env->pc = (unsigned long)ka->_sa_handler; /* what we enter NOW */
4056 env->gpr[9] = (unsigned long)return_ip; /* what we enter LATER */
4057 env->gpr[3] = (unsigned long)sig; /* arg 1: signo */
4058 env->gpr[4] = (unsigned long)&frame->info; /* arg 2: (siginfo_t*) */
4059 env->gpr[5] = (unsigned long)&frame->uc; /* arg 3: ucontext */
4060
4061 /* actually move the usp to reflect the stacked frame */
4062 env->gpr[1] = (unsigned long)frame;
4063
4064 return;
4065
4066give_sigsegv:
4067 unlock_user_struct(frame, frame_addr, 1);
4068 if (sig == TARGET_SIGSEGV) {
4069 ka->_sa_handler = TARGET_SIG_DFL;
4070 }
4071 force_sig(TARGET_SIGSEGV);
4072}
4073
4074long do_sigreturn(CPUOpenRISCState *env)
4075{
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01004076 trace_user_do_sigreturn(env, 0);
4077 fprintf(stderr, "do_sigreturn: not implemented\n");
Jia Liud9627832012-07-20 15:50:52 +08004078 return -TARGET_ENOSYS;
4079}
4080
4081long do_rt_sigreturn(CPUOpenRISCState *env)
4082{
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01004083 trace_user_do_rt_sigreturn(env, 0);
4084 fprintf(stderr, "do_rt_sigreturn: not implemented\n");
Jia Liud9627832012-07-20 15:50:52 +08004085 return -TARGET_ENOSYS;
4086}
4087/* TARGET_OPENRISC */
4088
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004089#elif defined(TARGET_S390X)
4090
4091#define __NUM_GPRS 16
4092#define __NUM_FPRS 16
4093#define __NUM_ACRS 16
4094
4095#define S390_SYSCALL_SIZE 2
4096#define __SIGNAL_FRAMESIZE 160 /* FIXME: 31-bit mode -> 96 */
4097
4098#define _SIGCONTEXT_NSIG 64
4099#define _SIGCONTEXT_NSIG_BPW 64 /* FIXME: 31-bit mode -> 32 */
4100#define _SIGCONTEXT_NSIG_WORDS (_SIGCONTEXT_NSIG / _SIGCONTEXT_NSIG_BPW)
4101#define _SIGMASK_COPY_SIZE (sizeof(unsigned long)*_SIGCONTEXT_NSIG_WORDS)
4102#define PSW_ADDR_AMODE 0x0000000000000000UL /* 0x80000000UL for 31-bit */
4103#define S390_SYSCALL_OPCODE ((uint16_t)0x0a00)
4104
4105typedef struct {
4106 target_psw_t psw;
4107 target_ulong gprs[__NUM_GPRS];
4108 unsigned int acrs[__NUM_ACRS];
4109} target_s390_regs_common;
4110
4111typedef struct {
4112 unsigned int fpc;
4113 double fprs[__NUM_FPRS];
4114} target_s390_fp_regs;
4115
4116typedef struct {
4117 target_s390_regs_common regs;
4118 target_s390_fp_regs fpregs;
4119} target_sigregs;
4120
4121struct target_sigcontext {
4122 target_ulong oldmask[_SIGCONTEXT_NSIG_WORDS];
4123 target_sigregs *sregs;
4124};
4125
4126typedef struct {
4127 uint8_t callee_used_stack[__SIGNAL_FRAMESIZE];
4128 struct target_sigcontext sc;
4129 target_sigregs sregs;
4130 int signo;
4131 uint8_t retcode[S390_SYSCALL_SIZE];
4132} sigframe;
4133
4134struct target_ucontext {
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004135 target_ulong tuc_flags;
4136 struct target_ucontext *tuc_link;
4137 target_stack_t tuc_stack;
4138 target_sigregs tuc_mcontext;
4139 target_sigset_t tuc_sigmask; /* mask last for extensibility */
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004140};
4141
4142typedef struct {
4143 uint8_t callee_used_stack[__SIGNAL_FRAMESIZE];
4144 uint8_t retcode[S390_SYSCALL_SIZE];
4145 struct target_siginfo info;
4146 struct target_ucontext uc;
4147} rt_sigframe;
4148
4149static inline abi_ulong
Andreas Färber05390242012-02-25 03:37:53 +01004150get_sigframe(struct target_sigaction *ka, CPUS390XState *env, size_t frame_size)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004151{
4152 abi_ulong sp;
4153
4154 /* Default to using normal stack */
4155 sp = env->regs[15];
4156
4157 /* This is the X/Open sanctioned signal stack switching. */
4158 if (ka->sa_flags & TARGET_SA_ONSTACK) {
4159 if (!sas_ss_flags(sp)) {
4160 sp = target_sigaltstack_used.ss_sp +
4161 target_sigaltstack_used.ss_size;
4162 }
4163 }
4164
4165 /* This is the legacy signal stack switching. */
4166 else if (/* FIXME !user_mode(regs) */ 0 &&
4167 !(ka->sa_flags & TARGET_SA_RESTORER) &&
4168 ka->sa_restorer) {
4169 sp = (abi_ulong) ka->sa_restorer;
4170 }
4171
4172 return (sp - frame_size) & -8ul;
4173}
4174
Andreas Färber05390242012-02-25 03:37:53 +01004175static void save_sigregs(CPUS390XState *env, target_sigregs *sregs)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004176{
4177 int i;
4178 //save_access_regs(current->thread.acrs); FIXME
4179
4180 /* Copy a 'clean' PSW mask to the user to avoid leaking
4181 information about whether PER is currently on. */
4182 __put_user(env->psw.mask, &sregs->regs.psw.mask);
4183 __put_user(env->psw.addr, &sregs->regs.psw.addr);
4184 for (i = 0; i < 16; i++) {
4185 __put_user(env->regs[i], &sregs->regs.gprs[i]);
4186 }
4187 for (i = 0; i < 16; i++) {
4188 __put_user(env->aregs[i], &sregs->regs.acrs[i]);
4189 }
4190 /*
4191 * We have to store the fp registers to current->thread.fp_regs
4192 * to merge them with the emulated registers.
4193 */
4194 //save_fp_regs(&current->thread.fp_regs); FIXME
4195 for (i = 0; i < 16; i++) {
Eric Farmanc498d8e2015-05-07 14:35:44 -04004196 __put_user(get_freg(env, i)->ll, &sregs->fpregs.fprs[i]);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004197 }
4198}
4199
4200static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01004201 target_sigset_t *set, CPUS390XState *env)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004202{
4203 sigframe *frame;
4204 abi_ulong frame_addr;
4205
4206 frame_addr = get_sigframe(ka, env, sizeof(*frame));
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01004207 trace_user_setup_frame(env, frame_addr);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004208 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01004209 goto give_sigsegv;
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004210 }
4211
Riku Voipio0188fad2014-04-23 13:34:15 +03004212 __put_user(set->sig[0], &frame->sc.oldmask[0]);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004213
4214 save_sigregs(env, &frame->sregs);
4215
4216 __put_user((abi_ulong)(unsigned long)&frame->sregs,
4217 (abi_ulong *)&frame->sc.sregs);
4218
4219 /* Set up to return from userspace. If provided, use a stub
4220 already in userspace. */
4221 if (ka->sa_flags & TARGET_SA_RESTORER) {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01004222 env->regs[14] = (unsigned long)
4223 ka->sa_restorer | PSW_ADDR_AMODE;
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004224 } else {
Chen Gang5b1d59d2016-05-24 14:54:32 +03004225 env->regs[14] = (frame_addr + offsetof(sigframe, retcode))
4226 | PSW_ADDR_AMODE;
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01004227 __put_user(S390_SYSCALL_OPCODE | TARGET_NR_sigreturn,
4228 (uint16_t *)(frame->retcode));
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004229 }
4230
4231 /* Set up backchain. */
Riku Voipio0188fad2014-04-23 13:34:15 +03004232 __put_user(env->regs[15], (abi_ulong *) frame);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004233
4234 /* Set up registers for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02004235 env->regs[15] = frame_addr;
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004236 env->psw.addr = (target_ulong) ka->_sa_handler | PSW_ADDR_AMODE;
4237
4238 env->regs[2] = sig; //map_signal(sig);
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02004239 env->regs[3] = frame_addr += offsetof(typeof(*frame), sc);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004240
4241 /* We forgot to include these in the sigcontext.
4242 To avoid breaking binary compatibility, they are passed as args. */
4243 env->regs[4] = 0; // FIXME: no clue... current->thread.trap_no;
4244 env->regs[5] = 0; // FIXME: no clue... current->thread.prot_addr;
4245
4246 /* Place signal number on stack to allow backtrace from handler. */
Riku Voipio0188fad2014-04-23 13:34:15 +03004247 __put_user(env->regs[2], (int *) &frame->signo);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004248 unlock_user_struct(frame, frame_addr, 1);
4249 return;
4250
4251give_sigsegv:
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004252 force_sig(TARGET_SIGSEGV);
4253}
4254
4255static void setup_rt_frame(int sig, struct target_sigaction *ka,
4256 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01004257 target_sigset_t *set, CPUS390XState *env)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004258{
4259 int i;
4260 rt_sigframe *frame;
4261 abi_ulong frame_addr;
4262
4263 frame_addr = get_sigframe(ka, env, sizeof *frame);
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01004264 trace_user_setup_rt_frame(env, frame_addr);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004265 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
4266 goto give_sigsegv;
4267 }
4268
Peter Maydellf6c7a052015-01-08 12:19:48 +00004269 tswap_siginfo(&frame->info, info);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004270
4271 /* Create the ucontext. */
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004272 __put_user(0, &frame->uc.tuc_flags);
4273 __put_user((abi_ulong)0, (abi_ulong *)&frame->uc.tuc_link);
4274 __put_user(target_sigaltstack_used.ss_sp, &frame->uc.tuc_stack.ss_sp);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004275 __put_user(sas_ss_flags(get_sp_from_cpustate(env)),
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01004276 &frame->uc.tuc_stack.ss_flags);
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004277 __put_user(target_sigaltstack_used.ss_size, &frame->uc.tuc_stack.ss_size);
4278 save_sigregs(env, &frame->uc.tuc_mcontext);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004279 for (i = 0; i < TARGET_NSIG_WORDS; i++) {
4280 __put_user((abi_ulong)set->sig[i],
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01004281 (abi_ulong *)&frame->uc.tuc_sigmask.sig[i]);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004282 }
4283
4284 /* Set up to return from userspace. If provided, use a stub
4285 already in userspace. */
4286 if (ka->sa_flags & TARGET_SA_RESTORER) {
4287 env->regs[14] = (unsigned long) ka->sa_restorer | PSW_ADDR_AMODE;
4288 } else {
4289 env->regs[14] = (unsigned long) frame->retcode | PSW_ADDR_AMODE;
Riku Voipio0188fad2014-04-23 13:34:15 +03004290 __put_user(S390_SYSCALL_OPCODE | TARGET_NR_rt_sigreturn,
4291 (uint16_t *)(frame->retcode));
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004292 }
4293
4294 /* Set up backchain. */
Riku Voipio0188fad2014-04-23 13:34:15 +03004295 __put_user(env->regs[15], (abi_ulong *) frame);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004296
4297 /* Set up registers for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02004298 env->regs[15] = frame_addr;
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004299 env->psw.addr = (target_ulong) ka->_sa_handler | PSW_ADDR_AMODE;
4300
4301 env->regs[2] = sig; //map_signal(sig);
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02004302 env->regs[3] = frame_addr + offsetof(typeof(*frame), info);
4303 env->regs[4] = frame_addr + offsetof(typeof(*frame), uc);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004304 return;
4305
4306give_sigsegv:
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004307 force_sig(TARGET_SIGSEGV);
4308}
4309
4310static int
Andreas Färber05390242012-02-25 03:37:53 +01004311restore_sigregs(CPUS390XState *env, target_sigregs *sc)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004312{
4313 int err = 0;
4314 int i;
4315
4316 for (i = 0; i < 16; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03004317 __get_user(env->regs[i], &sc->regs.gprs[i]);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004318 }
4319
Riku Voipio1d8b5122014-04-23 10:26:05 +03004320 __get_user(env->psw.mask, &sc->regs.psw.mask);
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01004321 trace_user_s390x_restore_sigregs(env, (unsigned long long)sc->regs.psw.addr,
4322 (unsigned long long)env->psw.addr);
Riku Voipio1d8b5122014-04-23 10:26:05 +03004323 __get_user(env->psw.addr, &sc->regs.psw.addr);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004324 /* FIXME: 31-bit -> | PSW_ADDR_AMODE */
4325
4326 for (i = 0; i < 16; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03004327 __get_user(env->aregs[i], &sc->regs.acrs[i]);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004328 }
4329 for (i = 0; i < 16; i++) {
Eric Farmanc498d8e2015-05-07 14:35:44 -04004330 __get_user(get_freg(env, i)->ll, &sc->fpregs.fprs[i]);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004331 }
4332
4333 return err;
4334}
4335
Andreas Färber05390242012-02-25 03:37:53 +01004336long do_sigreturn(CPUS390XState *env)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004337{
4338 sigframe *frame;
4339 abi_ulong frame_addr = env->regs[15];
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004340 target_sigset_t target_set;
4341 sigset_t set;
4342
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01004343 trace_user_do_sigreturn(env, frame_addr);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004344 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
4345 goto badframe;
4346 }
Riku Voipiof5f601a2014-04-23 13:00:17 +03004347 __get_user(target_set.sig[0], &frame->sc.oldmask[0]);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004348
4349 target_to_host_sigset_internal(&set, &target_set);
Peter Maydell9eede5b2016-05-27 15:51:46 +01004350 set_sigmask(&set); /* ~_BLOCKABLE? */
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004351
4352 if (restore_sigregs(env, &frame->sregs)) {
4353 goto badframe;
4354 }
4355
4356 unlock_user_struct(frame, frame_addr, 0);
Timothy E Baldwin47405ab2016-05-12 18:47:40 +01004357 return -TARGET_QEMU_ESIGRETURN;
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004358
4359badframe:
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004360 force_sig(TARGET_SIGSEGV);
4361 return 0;
4362}
4363
Andreas Färber05390242012-02-25 03:37:53 +01004364long do_rt_sigreturn(CPUS390XState *env)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004365{
4366 rt_sigframe *frame;
4367 abi_ulong frame_addr = env->regs[15];
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004368 sigset_t set;
4369
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01004370 trace_user_do_rt_sigreturn(env, frame_addr);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004371 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
4372 goto badframe;
4373 }
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004374 target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004375
Peter Maydell9eede5b2016-05-27 15:51:46 +01004376 set_sigmask(&set); /* ~_BLOCKABLE? */
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004377
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004378 if (restore_sigregs(env, &frame->uc.tuc_mcontext)) {
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004379 goto badframe;
4380 }
4381
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004382 if (do_sigaltstack(frame_addr + offsetof(rt_sigframe, uc.tuc_stack), 0,
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004383 get_sp_from_cpustate(env)) == -EFAULT) {
4384 goto badframe;
4385 }
4386 unlock_user_struct(frame, frame_addr, 0);
Timothy E Baldwin47405ab2016-05-12 18:47:40 +01004387 return -TARGET_QEMU_ESIGRETURN;
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004388
4389badframe:
4390 unlock_user_struct(frame, frame_addr, 0);
4391 force_sig(TARGET_SIGSEGV);
4392 return 0;
4393}
4394
Tom Musta61e75fe2014-06-30 08:13:38 -05004395#elif defined(TARGET_PPC)
Nathan Froydbcd49332009-05-12 19:13:18 -07004396
4397/* Size of dummy stack frame allocated when calling signal handler.
4398 See arch/powerpc/include/asm/ptrace.h. */
4399#if defined(TARGET_PPC64)
4400#define SIGNAL_FRAMESIZE 128
4401#else
4402#define SIGNAL_FRAMESIZE 64
4403#endif
4404
Tom Musta61e75fe2014-06-30 08:13:38 -05004405/* See arch/powerpc/include/asm/ucontext.h. Only used for 32-bit PPC;
4406 on 64-bit PPC, sigcontext and mcontext are one and the same. */
4407struct target_mcontext {
4408 target_ulong mc_gregs[48];
4409 /* Includes fpscr. */
4410 uint64_t mc_fregs[33];
4411 target_ulong mc_pad[2];
4412 /* We need to handle Altivec and SPE at the same time, which no
4413 kernel needs to do. Fortunately, the kernel defines this bit to
4414 be Altivec-register-large all the time, rather than trying to
4415 twiddle it based on the specific platform. */
4416 union {
4417 /* SPE vector registers. One extra for SPEFSCR. */
4418 uint32_t spe[33];
4419 /* Altivec vector registers. The packing of VSCR and VRSAVE
4420 varies depending on whether we're PPC64 or not: PPC64 splits
4421 them apart; PPC32 stuffs them together. */
4422#if defined(TARGET_PPC64)
4423#define QEMU_NVRREG 34
4424#else
4425#define QEMU_NVRREG 33
4426#endif
4427 ppc_avr_t altivec[QEMU_NVRREG];
4428#undef QEMU_NVRREG
4429 } mc_vregs __attribute__((__aligned__(16)));
4430};
4431
Nathan Froydbcd49332009-05-12 19:13:18 -07004432/* See arch/powerpc/include/asm/sigcontext.h. */
4433struct target_sigcontext {
4434 target_ulong _unused[4];
4435 int32_t signal;
4436#if defined(TARGET_PPC64)
4437 int32_t pad0;
4438#endif
4439 target_ulong handler;
4440 target_ulong oldmask;
4441 target_ulong regs; /* struct pt_regs __user * */
Tom Musta61e75fe2014-06-30 08:13:38 -05004442#if defined(TARGET_PPC64)
4443 struct target_mcontext mcontext;
4444#endif
Nathan Froydbcd49332009-05-12 19:13:18 -07004445};
4446
4447/* Indices for target_mcontext.mc_gregs, below.
4448 See arch/powerpc/include/asm/ptrace.h for details. */
4449enum {
4450 TARGET_PT_R0 = 0,
4451 TARGET_PT_R1 = 1,
4452 TARGET_PT_R2 = 2,
4453 TARGET_PT_R3 = 3,
4454 TARGET_PT_R4 = 4,
4455 TARGET_PT_R5 = 5,
4456 TARGET_PT_R6 = 6,
4457 TARGET_PT_R7 = 7,
4458 TARGET_PT_R8 = 8,
4459 TARGET_PT_R9 = 9,
4460 TARGET_PT_R10 = 10,
4461 TARGET_PT_R11 = 11,
4462 TARGET_PT_R12 = 12,
4463 TARGET_PT_R13 = 13,
4464 TARGET_PT_R14 = 14,
4465 TARGET_PT_R15 = 15,
4466 TARGET_PT_R16 = 16,
4467 TARGET_PT_R17 = 17,
4468 TARGET_PT_R18 = 18,
4469 TARGET_PT_R19 = 19,
4470 TARGET_PT_R20 = 20,
4471 TARGET_PT_R21 = 21,
4472 TARGET_PT_R22 = 22,
4473 TARGET_PT_R23 = 23,
4474 TARGET_PT_R24 = 24,
4475 TARGET_PT_R25 = 25,
4476 TARGET_PT_R26 = 26,
4477 TARGET_PT_R27 = 27,
4478 TARGET_PT_R28 = 28,
4479 TARGET_PT_R29 = 29,
4480 TARGET_PT_R30 = 30,
4481 TARGET_PT_R31 = 31,
4482 TARGET_PT_NIP = 32,
4483 TARGET_PT_MSR = 33,
4484 TARGET_PT_ORIG_R3 = 34,
4485 TARGET_PT_CTR = 35,
4486 TARGET_PT_LNK = 36,
4487 TARGET_PT_XER = 37,
4488 TARGET_PT_CCR = 38,
4489 /* Yes, there are two registers with #39. One is 64-bit only. */
4490 TARGET_PT_MQ = 39,
4491 TARGET_PT_SOFTE = 39,
4492 TARGET_PT_TRAP = 40,
4493 TARGET_PT_DAR = 41,
4494 TARGET_PT_DSISR = 42,
4495 TARGET_PT_RESULT = 43,
4496 TARGET_PT_REGS_COUNT = 44
4497};
4498
Nathan Froydbcd49332009-05-12 19:13:18 -07004499
4500struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02004501 target_ulong tuc_flags;
4502 target_ulong tuc_link; /* struct ucontext __user * */
4503 struct target_sigaltstack tuc_stack;
Nathan Froydbcd49332009-05-12 19:13:18 -07004504#if !defined(TARGET_PPC64)
Aurelien Jarno60e99242010-03-29 02:12:51 +02004505 int32_t tuc_pad[7];
4506 target_ulong tuc_regs; /* struct mcontext __user *
Nathan Froydbcd49332009-05-12 19:13:18 -07004507 points to uc_mcontext field */
4508#endif
Aurelien Jarno60e99242010-03-29 02:12:51 +02004509 target_sigset_t tuc_sigmask;
Nathan Froydbcd49332009-05-12 19:13:18 -07004510#if defined(TARGET_PPC64)
Anthony Liguoric227f092009-10-01 16:12:16 -05004511 target_sigset_t unused[15]; /* Allow for uc_sigmask growth */
Tom Musta61e75fe2014-06-30 08:13:38 -05004512 struct target_sigcontext tuc_sigcontext;
Nathan Froydbcd49332009-05-12 19:13:18 -07004513#else
Aurelien Jarno60e99242010-03-29 02:12:51 +02004514 int32_t tuc_maskext[30];
4515 int32_t tuc_pad2[3];
4516 struct target_mcontext tuc_mcontext;
Nathan Froydbcd49332009-05-12 19:13:18 -07004517#endif
4518};
4519
4520/* See arch/powerpc/kernel/signal_32.c. */
4521struct target_sigframe {
4522 struct target_sigcontext sctx;
4523 struct target_mcontext mctx;
4524 int32_t abigap[56];
4525};
4526
Tom Musta61e75fe2014-06-30 08:13:38 -05004527#if defined(TARGET_PPC64)
4528
4529#define TARGET_TRAMP_SIZE 6
4530
4531struct target_rt_sigframe {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01004532 /* sys_rt_sigreturn requires the ucontext be the first field */
4533 struct target_ucontext uc;
4534 target_ulong _unused[2];
4535 uint32_t trampoline[TARGET_TRAMP_SIZE];
4536 target_ulong pinfo; /* struct siginfo __user * */
4537 target_ulong puc; /* void __user * */
4538 struct target_siginfo info;
4539 /* 64 bit ABI allows for 288 bytes below sp before decrementing it. */
4540 char abigap[288];
Tom Musta61e75fe2014-06-30 08:13:38 -05004541} __attribute__((aligned(16)));
4542
4543#else
4544
Nathan Froydbcd49332009-05-12 19:13:18 -07004545struct target_rt_sigframe {
4546 struct target_siginfo info;
4547 struct target_ucontext uc;
4548 int32_t abigap[56];
4549};
4550
Tom Musta61e75fe2014-06-30 08:13:38 -05004551#endif
4552
Tom Musta8d6ab332014-06-30 08:13:39 -05004553#if defined(TARGET_PPC64)
4554
4555struct target_func_ptr {
4556 target_ulong entry;
4557 target_ulong toc;
4558};
4559
4560#endif
4561
Nathan Froydbcd49332009-05-12 19:13:18 -07004562/* We use the mc_pad field for the signal return trampoline. */
4563#define tramp mc_pad
4564
4565/* See arch/powerpc/kernel/signal.c. */
4566static target_ulong get_sigframe(struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01004567 CPUPPCState *env,
Nathan Froydbcd49332009-05-12 19:13:18 -07004568 int frame_size)
4569{
Eduardo Habkost9be38592016-06-13 18:57:58 -03004570 target_ulong oldsp;
Nathan Froydbcd49332009-05-12 19:13:18 -07004571
4572 oldsp = env->gpr[1];
4573
4574 if ((ka->sa_flags & TARGET_SA_ONSTACK) &&
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01004575 (sas_ss_flags(oldsp) == 0)) {
Nathan Froydbcd49332009-05-12 19:13:18 -07004576 oldsp = (target_sigaltstack_used.ss_sp
4577 + target_sigaltstack_used.ss_size);
4578 }
4579
Eduardo Habkost9be38592016-06-13 18:57:58 -03004580 return (oldsp - frame_size) & ~0xFUL;
Nathan Froydbcd49332009-05-12 19:13:18 -07004581}
4582
Tom Musta76781082014-06-30 08:13:37 -05004583static void save_user_regs(CPUPPCState *env, struct target_mcontext *frame)
Nathan Froydbcd49332009-05-12 19:13:18 -07004584{
4585 target_ulong msr = env->msr;
4586 int i;
4587 target_ulong ccr = 0;
4588
4589 /* In general, the kernel attempts to be intelligent about what it
4590 needs to save for Altivec/FP/SPE registers. We don't care that
4591 much, so we just go ahead and save everything. */
4592
4593 /* Save general registers. */
4594 for (i = 0; i < ARRAY_SIZE(env->gpr); i++) {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01004595 __put_user(env->gpr[i], &frame->mc_gregs[i]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004596 }
Riku Voipioc650c002014-04-23 13:53:45 +03004597 __put_user(env->nip, &frame->mc_gregs[TARGET_PT_NIP]);
4598 __put_user(env->ctr, &frame->mc_gregs[TARGET_PT_CTR]);
4599 __put_user(env->lr, &frame->mc_gregs[TARGET_PT_LNK]);
4600 __put_user(env->xer, &frame->mc_gregs[TARGET_PT_XER]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004601
4602 for (i = 0; i < ARRAY_SIZE(env->crf); i++) {
4603 ccr |= env->crf[i] << (32 - ((i + 1) * 4));
4604 }
Riku Voipioc650c002014-04-23 13:53:45 +03004605 __put_user(ccr, &frame->mc_gregs[TARGET_PT_CCR]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004606
4607 /* Save Altivec registers if necessary. */
4608 if (env->insns_flags & PPC_ALTIVEC) {
4609 for (i = 0; i < ARRAY_SIZE(env->avr); i++) {
Anthony Liguoric227f092009-10-01 16:12:16 -05004610 ppc_avr_t *avr = &env->avr[i];
4611 ppc_avr_t *vreg = &frame->mc_vregs.altivec[i];
Nathan Froydbcd49332009-05-12 19:13:18 -07004612
Riku Voipioc650c002014-04-23 13:53:45 +03004613 __put_user(avr->u64[0], &vreg->u64[0]);
4614 __put_user(avr->u64[1], &vreg->u64[1]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004615 }
4616 /* Set MSR_VR in the saved MSR value to indicate that
4617 frame->mc_vregs contains valid data. */
4618 msr |= MSR_VR;
Riku Voipioc650c002014-04-23 13:53:45 +03004619 __put_user((uint32_t)env->spr[SPR_VRSAVE],
4620 &frame->mc_vregs.altivec[32].u32[3]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004621 }
4622
4623 /* Save floating point registers. */
4624 if (env->insns_flags & PPC_FLOAT) {
4625 for (i = 0; i < ARRAY_SIZE(env->fpr); i++) {
Riku Voipioc650c002014-04-23 13:53:45 +03004626 __put_user(env->fpr[i], &frame->mc_fregs[i]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004627 }
Riku Voipioc650c002014-04-23 13:53:45 +03004628 __put_user((uint64_t) env->fpscr, &frame->mc_fregs[32]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004629 }
4630
4631 /* Save SPE registers. The kernel only saves the high half. */
4632 if (env->insns_flags & PPC_SPE) {
4633#if defined(TARGET_PPC64)
4634 for (i = 0; i < ARRAY_SIZE(env->gpr); i++) {
Riku Voipioc650c002014-04-23 13:53:45 +03004635 __put_user(env->gpr[i] >> 32, &frame->mc_vregs.spe[i]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004636 }
4637#else
4638 for (i = 0; i < ARRAY_SIZE(env->gprh); i++) {
Riku Voipioc650c002014-04-23 13:53:45 +03004639 __put_user(env->gprh[i], &frame->mc_vregs.spe[i]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004640 }
4641#endif
4642 /* Set MSR_SPE in the saved MSR value to indicate that
4643 frame->mc_vregs contains valid data. */
4644 msr |= MSR_SPE;
Riku Voipioc650c002014-04-23 13:53:45 +03004645 __put_user(env->spe_fscr, &frame->mc_vregs.spe[32]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004646 }
4647
4648 /* Store MSR. */
Riku Voipioc650c002014-04-23 13:53:45 +03004649 __put_user(msr, &frame->mc_gregs[TARGET_PT_MSR]);
Tom Musta76781082014-06-30 08:13:37 -05004650}
Nathan Froydbcd49332009-05-12 19:13:18 -07004651
Tom Musta76781082014-06-30 08:13:37 -05004652static void encode_trampoline(int sigret, uint32_t *tramp)
4653{
Nathan Froydbcd49332009-05-12 19:13:18 -07004654 /* Set up the sigreturn trampoline: li r0,sigret; sc. */
4655 if (sigret) {
Tom Musta76781082014-06-30 08:13:37 -05004656 __put_user(0x38000000 | sigret, &tramp[0]);
4657 __put_user(0x44000002, &tramp[1]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004658 }
Nathan Froydbcd49332009-05-12 19:13:18 -07004659}
4660
Riku Voipioc650c002014-04-23 13:53:45 +03004661static void restore_user_regs(CPUPPCState *env,
4662 struct target_mcontext *frame, int sig)
Nathan Froydbcd49332009-05-12 19:13:18 -07004663{
4664 target_ulong save_r2 = 0;
4665 target_ulong msr;
4666 target_ulong ccr;
4667
4668 int i;
4669
4670 if (!sig) {
4671 save_r2 = env->gpr[2];
4672 }
4673
4674 /* Restore general registers. */
4675 for (i = 0; i < ARRAY_SIZE(env->gpr); i++) {
Riku Voipioc650c002014-04-23 13:53:45 +03004676 __get_user(env->gpr[i], &frame->mc_gregs[i]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004677 }
Riku Voipioc650c002014-04-23 13:53:45 +03004678 __get_user(env->nip, &frame->mc_gregs[TARGET_PT_NIP]);
4679 __get_user(env->ctr, &frame->mc_gregs[TARGET_PT_CTR]);
4680 __get_user(env->lr, &frame->mc_gregs[TARGET_PT_LNK]);
4681 __get_user(env->xer, &frame->mc_gregs[TARGET_PT_XER]);
4682 __get_user(ccr, &frame->mc_gregs[TARGET_PT_CCR]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004683
4684 for (i = 0; i < ARRAY_SIZE(env->crf); i++) {
4685 env->crf[i] = (ccr >> (32 - ((i + 1) * 4))) & 0xf;
4686 }
4687
4688 if (!sig) {
4689 env->gpr[2] = save_r2;
4690 }
4691 /* Restore MSR. */
Riku Voipioc650c002014-04-23 13:53:45 +03004692 __get_user(msr, &frame->mc_gregs[TARGET_PT_MSR]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004693
4694 /* If doing signal return, restore the previous little-endian mode. */
4695 if (sig)
Laurent Vivier49e55cb2016-03-30 18:36:51 +02004696 env->msr = (env->msr & ~(1ull << MSR_LE)) | (msr & (1ull << MSR_LE));
Nathan Froydbcd49332009-05-12 19:13:18 -07004697
4698 /* Restore Altivec registers if necessary. */
4699 if (env->insns_flags & PPC_ALTIVEC) {
4700 for (i = 0; i < ARRAY_SIZE(env->avr); i++) {
Anthony Liguoric227f092009-10-01 16:12:16 -05004701 ppc_avr_t *avr = &env->avr[i];
4702 ppc_avr_t *vreg = &frame->mc_vregs.altivec[i];
Nathan Froydbcd49332009-05-12 19:13:18 -07004703
Riku Voipioc650c002014-04-23 13:53:45 +03004704 __get_user(avr->u64[0], &vreg->u64[0]);
4705 __get_user(avr->u64[1], &vreg->u64[1]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004706 }
4707 /* Set MSR_VEC in the saved MSR value to indicate that
4708 frame->mc_vregs contains valid data. */
Riku Voipioc650c002014-04-23 13:53:45 +03004709 __get_user(env->spr[SPR_VRSAVE],
4710 (target_ulong *)(&frame->mc_vregs.altivec[32].u32[3]));
Nathan Froydbcd49332009-05-12 19:13:18 -07004711 }
4712
4713 /* Restore floating point registers. */
4714 if (env->insns_flags & PPC_FLOAT) {
4715 uint64_t fpscr;
4716 for (i = 0; i < ARRAY_SIZE(env->fpr); i++) {
Riku Voipioc650c002014-04-23 13:53:45 +03004717 __get_user(env->fpr[i], &frame->mc_fregs[i]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004718 }
Riku Voipioc650c002014-04-23 13:53:45 +03004719 __get_user(fpscr, &frame->mc_fregs[32]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004720 env->fpscr = (uint32_t) fpscr;
4721 }
4722
4723 /* Save SPE registers. The kernel only saves the high half. */
4724 if (env->insns_flags & PPC_SPE) {
4725#if defined(TARGET_PPC64)
4726 for (i = 0; i < ARRAY_SIZE(env->gpr); i++) {
4727 uint32_t hi;
4728
Riku Voipioc650c002014-04-23 13:53:45 +03004729 __get_user(hi, &frame->mc_vregs.spe[i]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004730 env->gpr[i] = ((uint64_t)hi << 32) | ((uint32_t) env->gpr[i]);
4731 }
4732#else
4733 for (i = 0; i < ARRAY_SIZE(env->gprh); i++) {
Riku Voipioc650c002014-04-23 13:53:45 +03004734 __get_user(env->gprh[i], &frame->mc_vregs.spe[i]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004735 }
4736#endif
Riku Voipioc650c002014-04-23 13:53:45 +03004737 __get_user(env->spe_fscr, &frame->mc_vregs.spe[32]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004738 }
Nathan Froydbcd49332009-05-12 19:13:18 -07004739}
4740
4741static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01004742 target_sigset_t *set, CPUPPCState *env)
Nathan Froydbcd49332009-05-12 19:13:18 -07004743{
4744 struct target_sigframe *frame;
4745 struct target_sigcontext *sc;
4746 target_ulong frame_addr, newsp;
4747 int err = 0;
Tom Musta14585582014-06-30 08:13:42 -05004748#if defined(TARGET_PPC64)
4749 struct image_info *image = ((TaskState *)thread_cpu->opaque)->info;
4750#endif
Nathan Froydbcd49332009-05-12 19:13:18 -07004751
4752 frame_addr = get_sigframe(ka, env, sizeof(*frame));
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01004753 trace_user_setup_frame(env, frame_addr);
Nathan Froydbcd49332009-05-12 19:13:18 -07004754 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 1))
4755 goto sigsegv;
4756 sc = &frame->sctx;
4757
Riku Voipio1d8b5122014-04-23 10:26:05 +03004758 __put_user(ka->_sa_handler, &sc->handler);
4759 __put_user(set->sig[0], &sc->oldmask);
Tom Musta61e75fe2014-06-30 08:13:38 -05004760#if TARGET_ABI_BITS == 64
Riku Voipio1d8b5122014-04-23 10:26:05 +03004761 __put_user(set->sig[0] >> 32, &sc->_unused[3]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004762#else
Riku Voipio1d8b5122014-04-23 10:26:05 +03004763 __put_user(set->sig[1], &sc->_unused[3]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004764#endif
Riku Voipio1d8b5122014-04-23 10:26:05 +03004765 __put_user(h2g(&frame->mctx), &sc->regs);
4766 __put_user(sig, &sc->signal);
Nathan Froydbcd49332009-05-12 19:13:18 -07004767
4768 /* Save user regs. */
Tom Musta76781082014-06-30 08:13:37 -05004769 save_user_regs(env, &frame->mctx);
4770
4771 /* Construct the trampoline code on the stack. */
4772 encode_trampoline(TARGET_NR_sigreturn, (uint32_t *)&frame->mctx.tramp);
Nathan Froydbcd49332009-05-12 19:13:18 -07004773
4774 /* The kernel checks for the presence of a VDSO here. We don't
4775 emulate a vdso, so use a sigreturn system call. */
4776 env->lr = (target_ulong) h2g(frame->mctx.tramp);
4777
4778 /* Turn off all fp exceptions. */
4779 env->fpscr = 0;
4780
4781 /* Create a stack frame for the caller of the handler. */
4782 newsp = frame_addr - SIGNAL_FRAMESIZE;
Samuel Seaybeb526b2013-01-02 10:53:46 +00004783 err |= put_user(env->gpr[1], newsp, target_ulong);
Nathan Froydbcd49332009-05-12 19:13:18 -07004784
4785 if (err)
4786 goto sigsegv;
4787
4788 /* Set up registers for signal handler. */
4789 env->gpr[1] = newsp;
Peter Maydellb6e2c932015-01-08 12:19:43 +00004790 env->gpr[3] = sig;
Samuel Seay61993a62013-01-04 14:35:48 +00004791 env->gpr[4] = frame_addr + offsetof(struct target_sigframe, sctx);
Tom Musta8d6ab332014-06-30 08:13:39 -05004792
4793#if defined(TARGET_PPC64)
Tom Musta14585582014-06-30 08:13:42 -05004794 if (get_ppc64_abi(image) < 2) {
4795 /* ELFv1 PPC64 function pointers are pointers to OPD entries. */
4796 struct target_func_ptr *handler =
4797 (struct target_func_ptr *)g2h(ka->_sa_handler);
4798 env->nip = tswapl(handler->entry);
4799 env->gpr[2] = tswapl(handler->toc);
4800 } else {
4801 /* ELFv2 PPC64 function pointers are entry points, but R12
4802 * must also be set */
4803 env->nip = tswapl((target_ulong) ka->_sa_handler);
4804 env->gpr[12] = env->nip;
4805 }
Tom Musta8d6ab332014-06-30 08:13:39 -05004806#else
Nathan Froydbcd49332009-05-12 19:13:18 -07004807 env->nip = (target_ulong) ka->_sa_handler;
Tom Musta8d6ab332014-06-30 08:13:39 -05004808#endif
4809
Nathan Froydbcd49332009-05-12 19:13:18 -07004810 /* Signal handlers are entered in big-endian mode. */
Laurent Vivier49e55cb2016-03-30 18:36:51 +02004811 env->msr &= ~(1ull << MSR_LE);
Nathan Froydbcd49332009-05-12 19:13:18 -07004812
4813 unlock_user_struct(frame, frame_addr, 1);
4814 return;
4815
4816sigsegv:
4817 unlock_user_struct(frame, frame_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02004818 force_sig(TARGET_SIGSEGV);
Nathan Froydbcd49332009-05-12 19:13:18 -07004819}
4820
4821static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05004822 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01004823 target_sigset_t *set, CPUPPCState *env)
Nathan Froydbcd49332009-05-12 19:13:18 -07004824{
4825 struct target_rt_sigframe *rt_sf;
Tom Musta61e75fe2014-06-30 08:13:38 -05004826 uint32_t *trampptr = 0;
4827 struct target_mcontext *mctx = 0;
Nathan Froydbcd49332009-05-12 19:13:18 -07004828 target_ulong rt_sf_addr, newsp = 0;
4829 int i, err = 0;
Tom Musta14585582014-06-30 08:13:42 -05004830#if defined(TARGET_PPC64)
4831 struct image_info *image = ((TaskState *)thread_cpu->opaque)->info;
4832#endif
Nathan Froydbcd49332009-05-12 19:13:18 -07004833
4834 rt_sf_addr = get_sigframe(ka, env, sizeof(*rt_sf));
4835 if (!lock_user_struct(VERIFY_WRITE, rt_sf, rt_sf_addr, 1))
4836 goto sigsegv;
4837
Peter Maydellf6c7a052015-01-08 12:19:48 +00004838 tswap_siginfo(&rt_sf->info, info);
Nathan Froydbcd49332009-05-12 19:13:18 -07004839
Riku Voipio1d8b5122014-04-23 10:26:05 +03004840 __put_user(0, &rt_sf->uc.tuc_flags);
4841 __put_user(0, &rt_sf->uc.tuc_link);
4842 __put_user((target_ulong)target_sigaltstack_used.ss_sp,
4843 &rt_sf->uc.tuc_stack.ss_sp);
4844 __put_user(sas_ss_flags(env->gpr[1]),
4845 &rt_sf->uc.tuc_stack.ss_flags);
4846 __put_user(target_sigaltstack_used.ss_size,
4847 &rt_sf->uc.tuc_stack.ss_size);
Tom Musta61e75fe2014-06-30 08:13:38 -05004848#if !defined(TARGET_PPC64)
Riku Voipio1d8b5122014-04-23 10:26:05 +03004849 __put_user(h2g (&rt_sf->uc.tuc_mcontext),
4850 &rt_sf->uc.tuc_regs);
Tom Musta61e75fe2014-06-30 08:13:38 -05004851#endif
Nathan Froydbcd49332009-05-12 19:13:18 -07004852 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03004853 __put_user(set->sig[i], &rt_sf->uc.tuc_sigmask.sig[i]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004854 }
4855
Tom Musta61e75fe2014-06-30 08:13:38 -05004856#if defined(TARGET_PPC64)
4857 mctx = &rt_sf->uc.tuc_sigcontext.mcontext;
4858 trampptr = &rt_sf->trampoline[0];
4859#else
4860 mctx = &rt_sf->uc.tuc_mcontext;
4861 trampptr = (uint32_t *)&rt_sf->uc.tuc_mcontext.tramp;
4862#endif
4863
4864 save_user_regs(env, mctx);
4865 encode_trampoline(TARGET_NR_rt_sigreturn, trampptr);
Nathan Froydbcd49332009-05-12 19:13:18 -07004866
4867 /* The kernel checks for the presence of a VDSO here. We don't
4868 emulate a vdso, so use a sigreturn system call. */
Tom Musta61e75fe2014-06-30 08:13:38 -05004869 env->lr = (target_ulong) h2g(trampptr);
Nathan Froydbcd49332009-05-12 19:13:18 -07004870
4871 /* Turn off all fp exceptions. */
4872 env->fpscr = 0;
4873
4874 /* Create a stack frame for the caller of the handler. */
4875 newsp = rt_sf_addr - (SIGNAL_FRAMESIZE + 16);
Tom Mustafbdc2002014-06-30 08:13:36 -05004876 err |= put_user(env->gpr[1], newsp, target_ulong);
Nathan Froydbcd49332009-05-12 19:13:18 -07004877
4878 if (err)
4879 goto sigsegv;
4880
4881 /* Set up registers for signal handler. */
4882 env->gpr[1] = newsp;
Peter Maydellb6e2c932015-01-08 12:19:43 +00004883 env->gpr[3] = (target_ulong) sig;
Nathan Froydbcd49332009-05-12 19:13:18 -07004884 env->gpr[4] = (target_ulong) h2g(&rt_sf->info);
4885 env->gpr[5] = (target_ulong) h2g(&rt_sf->uc);
4886 env->gpr[6] = (target_ulong) h2g(rt_sf);
Tom Musta8d6ab332014-06-30 08:13:39 -05004887
4888#if defined(TARGET_PPC64)
Tom Musta14585582014-06-30 08:13:42 -05004889 if (get_ppc64_abi(image) < 2) {
4890 /* ELFv1 PPC64 function pointers are pointers to OPD entries. */
4891 struct target_func_ptr *handler =
4892 (struct target_func_ptr *)g2h(ka->_sa_handler);
4893 env->nip = tswapl(handler->entry);
4894 env->gpr[2] = tswapl(handler->toc);
4895 } else {
4896 /* ELFv2 PPC64 function pointers are entry points, but R12
4897 * must also be set */
4898 env->nip = tswapl((target_ulong) ka->_sa_handler);
4899 env->gpr[12] = env->nip;
4900 }
Tom Musta8d6ab332014-06-30 08:13:39 -05004901#else
Nathan Froydbcd49332009-05-12 19:13:18 -07004902 env->nip = (target_ulong) ka->_sa_handler;
Tom Musta8d6ab332014-06-30 08:13:39 -05004903#endif
4904
Nathan Froydbcd49332009-05-12 19:13:18 -07004905 /* Signal handlers are entered in big-endian mode. */
Laurent Vivier49e55cb2016-03-30 18:36:51 +02004906 env->msr &= ~(1ull << MSR_LE);
Nathan Froydbcd49332009-05-12 19:13:18 -07004907
4908 unlock_user_struct(rt_sf, rt_sf_addr, 1);
4909 return;
4910
4911sigsegv:
4912 unlock_user_struct(rt_sf, rt_sf_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02004913 force_sig(TARGET_SIGSEGV);
Nathan Froydbcd49332009-05-12 19:13:18 -07004914
4915}
4916
Andreas Färber05390242012-02-25 03:37:53 +01004917long do_sigreturn(CPUPPCState *env)
Nathan Froydbcd49332009-05-12 19:13:18 -07004918{
4919 struct target_sigcontext *sc = NULL;
4920 struct target_mcontext *sr = NULL;
Peter Maydellb04636f2013-07-29 12:00:31 +01004921 target_ulong sr_addr = 0, sc_addr;
Nathan Froydbcd49332009-05-12 19:13:18 -07004922 sigset_t blocked;
Anthony Liguoric227f092009-10-01 16:12:16 -05004923 target_sigset_t set;
Nathan Froydbcd49332009-05-12 19:13:18 -07004924
4925 sc_addr = env->gpr[1] + SIGNAL_FRAMESIZE;
4926 if (!lock_user_struct(VERIFY_READ, sc, sc_addr, 1))
4927 goto sigsegv;
4928
4929#if defined(TARGET_PPC64)
Tom Musta61e75fe2014-06-30 08:13:38 -05004930 set.sig[0] = sc->oldmask + ((uint64_t)(sc->_unused[3]) << 32);
Nathan Froydbcd49332009-05-12 19:13:18 -07004931#else
Riku Voipiof5f601a2014-04-23 13:00:17 +03004932 __get_user(set.sig[0], &sc->oldmask);
4933 __get_user(set.sig[1], &sc->_unused[3]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004934#endif
4935 target_to_host_sigset_internal(&blocked, &set);
Peter Maydell9eede5b2016-05-27 15:51:46 +01004936 set_sigmask(&blocked);
Nathan Froydbcd49332009-05-12 19:13:18 -07004937
Riku Voipiof5f601a2014-04-23 13:00:17 +03004938 __get_user(sr_addr, &sc->regs);
Nathan Froydbcd49332009-05-12 19:13:18 -07004939 if (!lock_user_struct(VERIFY_READ, sr, sr_addr, 1))
4940 goto sigsegv;
Riku Voipioc650c002014-04-23 13:53:45 +03004941 restore_user_regs(env, sr, 1);
Nathan Froydbcd49332009-05-12 19:13:18 -07004942
4943 unlock_user_struct(sr, sr_addr, 1);
4944 unlock_user_struct(sc, sc_addr, 1);
4945 return -TARGET_QEMU_ESIGRETURN;
4946
4947sigsegv:
4948 unlock_user_struct(sr, sr_addr, 1);
4949 unlock_user_struct(sc, sc_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02004950 force_sig(TARGET_SIGSEGV);
Nathan Froydbcd49332009-05-12 19:13:18 -07004951 return 0;
4952}
4953
4954/* See arch/powerpc/kernel/signal_32.c. */
Andreas Färber05390242012-02-25 03:37:53 +01004955static int do_setcontext(struct target_ucontext *ucp, CPUPPCState *env, int sig)
Nathan Froydbcd49332009-05-12 19:13:18 -07004956{
4957 struct target_mcontext *mcp;
4958 target_ulong mcp_addr;
4959 sigset_t blocked;
Anthony Liguoric227f092009-10-01 16:12:16 -05004960 target_sigset_t set;
Nathan Froydbcd49332009-05-12 19:13:18 -07004961
Aurelien Jarno60e99242010-03-29 02:12:51 +02004962 if (copy_from_user(&set, h2g(ucp) + offsetof(struct target_ucontext, tuc_sigmask),
Nathan Froydbcd49332009-05-12 19:13:18 -07004963 sizeof (set)))
4964 return 1;
4965
Tom Musta19774ec2014-06-30 08:13:40 -05004966#if defined(TARGET_PPC64)
4967 mcp_addr = h2g(ucp) +
4968 offsetof(struct target_ucontext, tuc_sigcontext.mcontext);
4969#else
Riku Voipio9e918dc2014-04-23 14:05:09 +03004970 __get_user(mcp_addr, &ucp->tuc_regs);
Tom Musta19774ec2014-06-30 08:13:40 -05004971#endif
Nathan Froydbcd49332009-05-12 19:13:18 -07004972
4973 if (!lock_user_struct(VERIFY_READ, mcp, mcp_addr, 1))
4974 return 1;
4975
4976 target_to_host_sigset_internal(&blocked, &set);
Peter Maydell9eede5b2016-05-27 15:51:46 +01004977 set_sigmask(&blocked);
Riku Voipioc650c002014-04-23 13:53:45 +03004978 restore_user_regs(env, mcp, sig);
Nathan Froydbcd49332009-05-12 19:13:18 -07004979
4980 unlock_user_struct(mcp, mcp_addr, 1);
4981 return 0;
Nathan Froydbcd49332009-05-12 19:13:18 -07004982}
4983
Andreas Färber05390242012-02-25 03:37:53 +01004984long do_rt_sigreturn(CPUPPCState *env)
Nathan Froydbcd49332009-05-12 19:13:18 -07004985{
4986 struct target_rt_sigframe *rt_sf = NULL;
4987 target_ulong rt_sf_addr;
4988
4989 rt_sf_addr = env->gpr[1] + SIGNAL_FRAMESIZE + 16;
4990 if (!lock_user_struct(VERIFY_READ, rt_sf, rt_sf_addr, 1))
4991 goto sigsegv;
4992
4993 if (do_setcontext(&rt_sf->uc, env, 1))
4994 goto sigsegv;
4995
4996 do_sigaltstack(rt_sf_addr
Aurelien Jarno60e99242010-03-29 02:12:51 +02004997 + offsetof(struct target_rt_sigframe, uc.tuc_stack),
Nathan Froydbcd49332009-05-12 19:13:18 -07004998 0, env->gpr[1]);
4999
5000 unlock_user_struct(rt_sf, rt_sf_addr, 1);
5001 return -TARGET_QEMU_ESIGRETURN;
5002
5003sigsegv:
5004 unlock_user_struct(rt_sf, rt_sf_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02005005 force_sig(TARGET_SIGSEGV);
Nathan Froydbcd49332009-05-12 19:13:18 -07005006 return 0;
5007}
5008
Laurent Vivier492a8742009-08-03 16:12:17 +02005009#elif defined(TARGET_M68K)
5010
5011struct target_sigcontext {
5012 abi_ulong sc_mask;
5013 abi_ulong sc_usp;
5014 abi_ulong sc_d0;
5015 abi_ulong sc_d1;
5016 abi_ulong sc_a0;
5017 abi_ulong sc_a1;
5018 unsigned short sc_sr;
5019 abi_ulong sc_pc;
5020};
5021
5022struct target_sigframe
5023{
5024 abi_ulong pretcode;
5025 int sig;
5026 int code;
5027 abi_ulong psc;
5028 char retcode[8];
5029 abi_ulong extramask[TARGET_NSIG_WORDS-1];
5030 struct target_sigcontext sc;
5031};
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01005032
Anthony Liguoric227f092009-10-01 16:12:16 -05005033typedef int target_greg_t;
Laurent Vivier71811552009-08-03 16:12:18 +02005034#define TARGET_NGREG 18
Anthony Liguoric227f092009-10-01 16:12:16 -05005035typedef target_greg_t target_gregset_t[TARGET_NGREG];
Laurent Vivier71811552009-08-03 16:12:18 +02005036
5037typedef struct target_fpregset {
5038 int f_fpcntl[3];
5039 int f_fpregs[8*3];
Anthony Liguoric227f092009-10-01 16:12:16 -05005040} target_fpregset_t;
Laurent Vivier71811552009-08-03 16:12:18 +02005041
5042struct target_mcontext {
5043 int version;
Anthony Liguoric227f092009-10-01 16:12:16 -05005044 target_gregset_t gregs;
5045 target_fpregset_t fpregs;
Laurent Vivier71811552009-08-03 16:12:18 +02005046};
5047
5048#define TARGET_MCONTEXT_VERSION 2
5049
5050struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02005051 abi_ulong tuc_flags;
5052 abi_ulong tuc_link;
5053 target_stack_t tuc_stack;
5054 struct target_mcontext tuc_mcontext;
5055 abi_long tuc_filler[80];
5056 target_sigset_t tuc_sigmask;
Laurent Vivier71811552009-08-03 16:12:18 +02005057};
5058
5059struct target_rt_sigframe
5060{
5061 abi_ulong pretcode;
5062 int sig;
5063 abi_ulong pinfo;
5064 abi_ulong puc;
5065 char retcode[8];
5066 struct target_siginfo info;
5067 struct target_ucontext uc;
5068};
Laurent Vivier492a8742009-08-03 16:12:17 +02005069
Riku Voipio41ecc722014-04-23 11:01:00 +03005070static void setup_sigcontext(struct target_sigcontext *sc, CPUM68KState *env,
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01005071 abi_ulong mask)
Laurent Vivier492a8742009-08-03 16:12:17 +02005072{
Riku Voipio1d8b5122014-04-23 10:26:05 +03005073 __put_user(mask, &sc->sc_mask);
5074 __put_user(env->aregs[7], &sc->sc_usp);
5075 __put_user(env->dregs[0], &sc->sc_d0);
5076 __put_user(env->dregs[1], &sc->sc_d1);
5077 __put_user(env->aregs[0], &sc->sc_a0);
5078 __put_user(env->aregs[1], &sc->sc_a1);
5079 __put_user(env->sr, &sc->sc_sr);
5080 __put_user(env->pc, &sc->sc_pc);
Laurent Vivier492a8742009-08-03 16:12:17 +02005081}
5082
Riku Voipio016d2e12014-04-23 11:19:48 +03005083static void
Timothy E Baldwin7ccb84a2016-05-12 18:47:39 +01005084restore_sigcontext(CPUM68KState *env, struct target_sigcontext *sc)
Laurent Vivier492a8742009-08-03 16:12:17 +02005085{
Laurent Vivier492a8742009-08-03 16:12:17 +02005086 int temp;
5087
Riku Voipio1d8b5122014-04-23 10:26:05 +03005088 __get_user(env->aregs[7], &sc->sc_usp);
Timothy E Baldwin7ccb84a2016-05-12 18:47:39 +01005089 __get_user(env->dregs[0], &sc->sc_d0);
Riku Voipio1d8b5122014-04-23 10:26:05 +03005090 __get_user(env->dregs[1], &sc->sc_d1);
5091 __get_user(env->aregs[0], &sc->sc_a0);
5092 __get_user(env->aregs[1], &sc->sc_a1);
5093 __get_user(env->pc, &sc->sc_pc);
5094 __get_user(temp, &sc->sc_sr);
Laurent Vivier492a8742009-08-03 16:12:17 +02005095 env->sr = (env->sr & 0xff00) | (temp & 0xff);
Laurent Vivier492a8742009-08-03 16:12:17 +02005096}
5097
5098/*
5099 * Determine which stack to use..
5100 */
5101static inline abi_ulong
Andreas Färber05390242012-02-25 03:37:53 +01005102get_sigframe(struct target_sigaction *ka, CPUM68KState *regs,
5103 size_t frame_size)
Laurent Vivier492a8742009-08-03 16:12:17 +02005104{
5105 unsigned long sp;
5106
5107 sp = regs->aregs[7];
5108
5109 /* This is the X/Open sanctioned signal stack switching. */
5110 if ((ka->sa_flags & TARGET_SA_ONSTACK) && (sas_ss_flags (sp) == 0)) {
5111 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
5112 }
5113
5114 return ((sp - frame_size) & -8UL);
5115}
5116
5117static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01005118 target_sigset_t *set, CPUM68KState *env)
Laurent Vivier492a8742009-08-03 16:12:17 +02005119{
5120 struct target_sigframe *frame;
5121 abi_ulong frame_addr;
5122 abi_ulong retcode_addr;
5123 abi_ulong sc_addr;
Laurent Vivier492a8742009-08-03 16:12:17 +02005124 int i;
5125
5126 frame_addr = get_sigframe(ka, env, sizeof *frame);
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01005127 trace_user_setup_frame(env, frame_addr);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01005128 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
5129 goto give_sigsegv;
5130 }
Laurent Vivier492a8742009-08-03 16:12:17 +02005131
Riku Voipio1d8b5122014-04-23 10:26:05 +03005132 __put_user(sig, &frame->sig);
Laurent Vivier492a8742009-08-03 16:12:17 +02005133
5134 sc_addr = frame_addr + offsetof(struct target_sigframe, sc);
Riku Voipio1d8b5122014-04-23 10:26:05 +03005135 __put_user(sc_addr, &frame->psc);
Laurent Vivier492a8742009-08-03 16:12:17 +02005136
Riku Voipio41ecc722014-04-23 11:01:00 +03005137 setup_sigcontext(&frame->sc, env, set->sig[0]);
Laurent Vivier492a8742009-08-03 16:12:17 +02005138
5139 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
Riku Voipio0188fad2014-04-23 13:34:15 +03005140 __put_user(set->sig[i], &frame->extramask[i - 1]);
Laurent Vivier492a8742009-08-03 16:12:17 +02005141 }
5142
5143 /* Set up to return from userspace. */
5144
5145 retcode_addr = frame_addr + offsetof(struct target_sigframe, retcode);
Riku Voipio1d8b5122014-04-23 10:26:05 +03005146 __put_user(retcode_addr, &frame->pretcode);
Laurent Vivier492a8742009-08-03 16:12:17 +02005147
5148 /* moveq #,d0; trap #0 */
5149
Riku Voipio1d8b5122014-04-23 10:26:05 +03005150 __put_user(0x70004e40 + (TARGET_NR_sigreturn << 16),
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01005151 (uint32_t *)(frame->retcode));
Laurent Vivier492a8742009-08-03 16:12:17 +02005152
Laurent Vivier492a8742009-08-03 16:12:17 +02005153 /* Set up to return from userspace */
5154
5155 env->aregs[7] = frame_addr;
5156 env->pc = ka->_sa_handler;
5157
5158 unlock_user_struct(frame, frame_addr, 1);
5159 return;
5160
5161give_sigsegv:
Riku Voipio66393fb2009-12-04 15:16:32 +02005162 force_sig(TARGET_SIGSEGV);
Laurent Vivier492a8742009-08-03 16:12:17 +02005163}
5164
Laurent Vivier71811552009-08-03 16:12:18 +02005165static inline int target_rt_setup_ucontext(struct target_ucontext *uc,
Andreas Färber05390242012-02-25 03:37:53 +01005166 CPUM68KState *env)
Laurent Vivier71811552009-08-03 16:12:18 +02005167{
Aurelien Jarno60e99242010-03-29 02:12:51 +02005168 target_greg_t *gregs = uc->tuc_mcontext.gregs;
Laurent Vivier71811552009-08-03 16:12:18 +02005169
Riku Voipio1d8b5122014-04-23 10:26:05 +03005170 __put_user(TARGET_MCONTEXT_VERSION, &uc->tuc_mcontext.version);
5171 __put_user(env->dregs[0], &gregs[0]);
5172 __put_user(env->dregs[1], &gregs[1]);
5173 __put_user(env->dregs[2], &gregs[2]);
5174 __put_user(env->dregs[3], &gregs[3]);
5175 __put_user(env->dregs[4], &gregs[4]);
5176 __put_user(env->dregs[5], &gregs[5]);
5177 __put_user(env->dregs[6], &gregs[6]);
5178 __put_user(env->dregs[7], &gregs[7]);
5179 __put_user(env->aregs[0], &gregs[8]);
5180 __put_user(env->aregs[1], &gregs[9]);
5181 __put_user(env->aregs[2], &gregs[10]);
5182 __put_user(env->aregs[3], &gregs[11]);
5183 __put_user(env->aregs[4], &gregs[12]);
5184 __put_user(env->aregs[5], &gregs[13]);
5185 __put_user(env->aregs[6], &gregs[14]);
5186 __put_user(env->aregs[7], &gregs[15]);
5187 __put_user(env->pc, &gregs[16]);
5188 __put_user(env->sr, &gregs[17]);
Laurent Vivier71811552009-08-03 16:12:18 +02005189
Riku Voipio1d8b5122014-04-23 10:26:05 +03005190 return 0;
Laurent Vivier71811552009-08-03 16:12:18 +02005191}
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01005192
Andreas Färber05390242012-02-25 03:37:53 +01005193static inline int target_rt_restore_ucontext(CPUM68KState *env,
Timothy E Baldwin7ccb84a2016-05-12 18:47:39 +01005194 struct target_ucontext *uc)
Laurent Vivier71811552009-08-03 16:12:18 +02005195{
5196 int temp;
Aurelien Jarno60e99242010-03-29 02:12:51 +02005197 target_greg_t *gregs = uc->tuc_mcontext.gregs;
Laurent Vivier71811552009-08-03 16:12:18 +02005198
Riku Voipio1d8b5122014-04-23 10:26:05 +03005199 __get_user(temp, &uc->tuc_mcontext.version);
Laurent Vivier71811552009-08-03 16:12:18 +02005200 if (temp != TARGET_MCONTEXT_VERSION)
5201 goto badframe;
5202
5203 /* restore passed registers */
Riku Voipio1d8b5122014-04-23 10:26:05 +03005204 __get_user(env->dregs[0], &gregs[0]);
5205 __get_user(env->dregs[1], &gregs[1]);
5206 __get_user(env->dregs[2], &gregs[2]);
5207 __get_user(env->dregs[3], &gregs[3]);
5208 __get_user(env->dregs[4], &gregs[4]);
5209 __get_user(env->dregs[5], &gregs[5]);
5210 __get_user(env->dregs[6], &gregs[6]);
5211 __get_user(env->dregs[7], &gregs[7]);
5212 __get_user(env->aregs[0], &gregs[8]);
5213 __get_user(env->aregs[1], &gregs[9]);
5214 __get_user(env->aregs[2], &gregs[10]);
5215 __get_user(env->aregs[3], &gregs[11]);
5216 __get_user(env->aregs[4], &gregs[12]);
5217 __get_user(env->aregs[5], &gregs[13]);
5218 __get_user(env->aregs[6], &gregs[14]);
5219 __get_user(env->aregs[7], &gregs[15]);
5220 __get_user(env->pc, &gregs[16]);
5221 __get_user(temp, &gregs[17]);
Laurent Vivier71811552009-08-03 16:12:18 +02005222 env->sr = (env->sr & 0xff00) | (temp & 0xff);
5223
Riku Voipio1d8b5122014-04-23 10:26:05 +03005224 return 0;
Laurent Vivier71811552009-08-03 16:12:18 +02005225
5226badframe:
5227 return 1;
5228}
5229
Laurent Vivier492a8742009-08-03 16:12:17 +02005230static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05005231 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01005232 target_sigset_t *set, CPUM68KState *env)
Laurent Vivier492a8742009-08-03 16:12:17 +02005233{
Laurent Vivier71811552009-08-03 16:12:18 +02005234 struct target_rt_sigframe *frame;
5235 abi_ulong frame_addr;
5236 abi_ulong retcode_addr;
5237 abi_ulong info_addr;
5238 abi_ulong uc_addr;
5239 int err = 0;
5240 int i;
5241
5242 frame_addr = get_sigframe(ka, env, sizeof *frame);
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01005243 trace_user_setup_rt_frame(env, frame_addr);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01005244 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
5245 goto give_sigsegv;
5246 }
Laurent Vivier71811552009-08-03 16:12:18 +02005247
Riku Voipio1d8b5122014-04-23 10:26:05 +03005248 __put_user(sig, &frame->sig);
Laurent Vivier71811552009-08-03 16:12:18 +02005249
5250 info_addr = frame_addr + offsetof(struct target_rt_sigframe, info);
Riku Voipio1d8b5122014-04-23 10:26:05 +03005251 __put_user(info_addr, &frame->pinfo);
Laurent Vivier71811552009-08-03 16:12:18 +02005252
5253 uc_addr = frame_addr + offsetof(struct target_rt_sigframe, uc);
Riku Voipio1d8b5122014-04-23 10:26:05 +03005254 __put_user(uc_addr, &frame->puc);
Laurent Vivier71811552009-08-03 16:12:18 +02005255
Peter Maydellf6c7a052015-01-08 12:19:48 +00005256 tswap_siginfo(&frame->info, info);
Laurent Vivier71811552009-08-03 16:12:18 +02005257
5258 /* Create the ucontext */
5259
Riku Voipio1d8b5122014-04-23 10:26:05 +03005260 __put_user(0, &frame->uc.tuc_flags);
5261 __put_user(0, &frame->uc.tuc_link);
5262 __put_user(target_sigaltstack_used.ss_sp,
5263 &frame->uc.tuc_stack.ss_sp);
5264 __put_user(sas_ss_flags(env->aregs[7]),
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01005265 &frame->uc.tuc_stack.ss_flags);
Riku Voipio1d8b5122014-04-23 10:26:05 +03005266 __put_user(target_sigaltstack_used.ss_size,
5267 &frame->uc.tuc_stack.ss_size);
Laurent Vivier71811552009-08-03 16:12:18 +02005268 err |= target_rt_setup_ucontext(&frame->uc, env);
5269
5270 if (err)
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01005271 goto give_sigsegv;
Laurent Vivier71811552009-08-03 16:12:18 +02005272
5273 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
Riku Voipio0188fad2014-04-23 13:34:15 +03005274 __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
Laurent Vivier71811552009-08-03 16:12:18 +02005275 }
5276
5277 /* Set up to return from userspace. */
5278
5279 retcode_addr = frame_addr + offsetof(struct target_sigframe, retcode);
Riku Voipio1d8b5122014-04-23 10:26:05 +03005280 __put_user(retcode_addr, &frame->pretcode);
Laurent Vivier71811552009-08-03 16:12:18 +02005281
5282 /* moveq #,d0; notb d0; trap #0 */
5283
Riku Voipio1d8b5122014-04-23 10:26:05 +03005284 __put_user(0x70004600 + ((TARGET_NR_rt_sigreturn ^ 0xff) << 16),
Peter Maydell1669add2014-12-22 17:47:00 +00005285 (uint32_t *)(frame->retcode + 0));
5286 __put_user(0x4e40, (uint16_t *)(frame->retcode + 4));
Laurent Vivier71811552009-08-03 16:12:18 +02005287
5288 if (err)
5289 goto give_sigsegv;
5290
5291 /* Set up to return from userspace */
5292
5293 env->aregs[7] = frame_addr;
5294 env->pc = ka->_sa_handler;
5295
5296 unlock_user_struct(frame, frame_addr, 1);
5297 return;
5298
5299give_sigsegv:
5300 unlock_user_struct(frame, frame_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02005301 force_sig(TARGET_SIGSEGV);
Laurent Vivier492a8742009-08-03 16:12:17 +02005302}
5303
Andreas Färber05390242012-02-25 03:37:53 +01005304long do_sigreturn(CPUM68KState *env)
Laurent Vivier492a8742009-08-03 16:12:17 +02005305{
5306 struct target_sigframe *frame;
5307 abi_ulong frame_addr = env->aregs[7] - 4;
Anthony Liguoric227f092009-10-01 16:12:16 -05005308 target_sigset_t target_set;
Laurent Vivier492a8742009-08-03 16:12:17 +02005309 sigset_t set;
Timothy E Baldwin7ccb84a2016-05-12 18:47:39 +01005310 int i;
Laurent Vivier492a8742009-08-03 16:12:17 +02005311
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01005312 trace_user_do_sigreturn(env, frame_addr);
Laurent Vivier492a8742009-08-03 16:12:17 +02005313 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
5314 goto badframe;
5315
5316 /* set blocked signals */
5317
Riku Voipiof5f601a2014-04-23 13:00:17 +03005318 __get_user(target_set.sig[0], &frame->sc.sc_mask);
Laurent Vivier492a8742009-08-03 16:12:17 +02005319
5320 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
Riku Voipiof5f601a2014-04-23 13:00:17 +03005321 __get_user(target_set.sig[i], &frame->extramask[i - 1]);
Laurent Vivier492a8742009-08-03 16:12:17 +02005322 }
5323
5324 target_to_host_sigset_internal(&set, &target_set);
Peter Maydell9eede5b2016-05-27 15:51:46 +01005325 set_sigmask(&set);
Laurent Vivier492a8742009-08-03 16:12:17 +02005326
5327 /* restore registers */
5328
Timothy E Baldwin7ccb84a2016-05-12 18:47:39 +01005329 restore_sigcontext(env, &frame->sc);
Laurent Vivier492a8742009-08-03 16:12:17 +02005330
5331 unlock_user_struct(frame, frame_addr, 0);
Timothy E Baldwin7ccb84a2016-05-12 18:47:39 +01005332 return -TARGET_QEMU_ESIGRETURN;
Laurent Vivier492a8742009-08-03 16:12:17 +02005333
5334badframe:
Laurent Vivier492a8742009-08-03 16:12:17 +02005335 force_sig(TARGET_SIGSEGV);
5336 return 0;
5337}
5338
Andreas Färber05390242012-02-25 03:37:53 +01005339long do_rt_sigreturn(CPUM68KState *env)
Laurent Vivier492a8742009-08-03 16:12:17 +02005340{
Laurent Vivier71811552009-08-03 16:12:18 +02005341 struct target_rt_sigframe *frame;
5342 abi_ulong frame_addr = env->aregs[7] - 4;
Anthony Liguoric227f092009-10-01 16:12:16 -05005343 target_sigset_t target_set;
Laurent Vivier71811552009-08-03 16:12:18 +02005344 sigset_t set;
Laurent Vivier71811552009-08-03 16:12:18 +02005345
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01005346 trace_user_do_rt_sigreturn(env, frame_addr);
Laurent Vivier71811552009-08-03 16:12:18 +02005347 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
5348 goto badframe;
5349
5350 target_to_host_sigset_internal(&set, &target_set);
Peter Maydell9eede5b2016-05-27 15:51:46 +01005351 set_sigmask(&set);
Laurent Vivier71811552009-08-03 16:12:18 +02005352
5353 /* restore registers */
5354
Timothy E Baldwin7ccb84a2016-05-12 18:47:39 +01005355 if (target_rt_restore_ucontext(env, &frame->uc))
Laurent Vivier71811552009-08-03 16:12:18 +02005356 goto badframe;
5357
5358 if (do_sigaltstack(frame_addr +
Aurelien Jarno60e99242010-03-29 02:12:51 +02005359 offsetof(struct target_rt_sigframe, uc.tuc_stack),
Laurent Vivier71811552009-08-03 16:12:18 +02005360 0, get_sp_from_cpustate(env)) == -EFAULT)
5361 goto badframe;
5362
5363 unlock_user_struct(frame, frame_addr, 0);
Timothy E Baldwin7ccb84a2016-05-12 18:47:39 +01005364 return -TARGET_QEMU_ESIGRETURN;
Laurent Vivier71811552009-08-03 16:12:18 +02005365
5366badframe:
5367 unlock_user_struct(frame, frame_addr, 0);
5368 force_sig(TARGET_SIGSEGV);
5369 return 0;
Laurent Vivier492a8742009-08-03 16:12:17 +02005370}
5371
Richard Henderson6049f4f2009-12-27 18:30:03 -08005372#elif defined(TARGET_ALPHA)
5373
5374struct target_sigcontext {
5375 abi_long sc_onstack;
5376 abi_long sc_mask;
5377 abi_long sc_pc;
5378 abi_long sc_ps;
5379 abi_long sc_regs[32];
5380 abi_long sc_ownedfp;
5381 abi_long sc_fpregs[32];
5382 abi_ulong sc_fpcr;
5383 abi_ulong sc_fp_control;
5384 abi_ulong sc_reserved1;
5385 abi_ulong sc_reserved2;
5386 abi_ulong sc_ssize;
5387 abi_ulong sc_sbase;
5388 abi_ulong sc_traparg_a0;
5389 abi_ulong sc_traparg_a1;
5390 abi_ulong sc_traparg_a2;
5391 abi_ulong sc_fp_trap_pc;
5392 abi_ulong sc_fp_trigger_sum;
5393 abi_ulong sc_fp_trigger_inst;
5394};
5395
5396struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02005397 abi_ulong tuc_flags;
5398 abi_ulong tuc_link;
5399 abi_ulong tuc_osf_sigmask;
5400 target_stack_t tuc_stack;
5401 struct target_sigcontext tuc_mcontext;
5402 target_sigset_t tuc_sigmask;
Richard Henderson6049f4f2009-12-27 18:30:03 -08005403};
5404
5405struct target_sigframe {
5406 struct target_sigcontext sc;
5407 unsigned int retcode[3];
5408};
5409
5410struct target_rt_sigframe {
5411 target_siginfo_t info;
5412 struct target_ucontext uc;
5413 unsigned int retcode[3];
5414};
5415
5416#define INSN_MOV_R30_R16 0x47fe0410
5417#define INSN_LDI_R0 0x201f0000
5418#define INSN_CALLSYS 0x00000083
5419
Riku Voipio41ecc722014-04-23 11:01:00 +03005420static void setup_sigcontext(struct target_sigcontext *sc, CPUAlphaState *env,
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01005421 abi_ulong frame_addr, target_sigset_t *set)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005422{
Riku Voipio41ecc722014-04-23 11:01:00 +03005423 int i;
Richard Henderson6049f4f2009-12-27 18:30:03 -08005424
Riku Voipio1d8b5122014-04-23 10:26:05 +03005425 __put_user(on_sig_stack(frame_addr), &sc->sc_onstack);
5426 __put_user(set->sig[0], &sc->sc_mask);
5427 __put_user(env->pc, &sc->sc_pc);
5428 __put_user(8, &sc->sc_ps);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005429
5430 for (i = 0; i < 31; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03005431 __put_user(env->ir[i], &sc->sc_regs[i]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005432 }
Riku Voipio1d8b5122014-04-23 10:26:05 +03005433 __put_user(0, &sc->sc_regs[31]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005434
5435 for (i = 0; i < 31; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03005436 __put_user(env->fir[i], &sc->sc_fpregs[i]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005437 }
Riku Voipio1d8b5122014-04-23 10:26:05 +03005438 __put_user(0, &sc->sc_fpregs[31]);
5439 __put_user(cpu_alpha_load_fpcr(env), &sc->sc_fpcr);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005440
Riku Voipio1d8b5122014-04-23 10:26:05 +03005441 __put_user(0, &sc->sc_traparg_a0); /* FIXME */
5442 __put_user(0, &sc->sc_traparg_a1); /* FIXME */
5443 __put_user(0, &sc->sc_traparg_a2); /* FIXME */
Richard Henderson6049f4f2009-12-27 18:30:03 -08005444}
5445
Riku Voipio016d2e12014-04-23 11:19:48 +03005446static void restore_sigcontext(CPUAlphaState *env,
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01005447 struct target_sigcontext *sc)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005448{
5449 uint64_t fpcr;
Riku Voipio016d2e12014-04-23 11:19:48 +03005450 int i;
Richard Henderson6049f4f2009-12-27 18:30:03 -08005451
Riku Voipio1d8b5122014-04-23 10:26:05 +03005452 __get_user(env->pc, &sc->sc_pc);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005453
5454 for (i = 0; i < 31; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03005455 __get_user(env->ir[i], &sc->sc_regs[i]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005456 }
5457 for (i = 0; i < 31; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03005458 __get_user(env->fir[i], &sc->sc_fpregs[i]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005459 }
5460
Riku Voipio1d8b5122014-04-23 10:26:05 +03005461 __get_user(fpcr, &sc->sc_fpcr);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005462 cpu_alpha_store_fpcr(env, fpcr);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005463}
5464
5465static inline abi_ulong get_sigframe(struct target_sigaction *sa,
Andreas Färber05390242012-02-25 03:37:53 +01005466 CPUAlphaState *env,
5467 unsigned long framesize)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005468{
5469 abi_ulong sp = env->ir[IR_SP];
5470
5471 /* This is the X/Open sanctioned signal stack switching. */
5472 if ((sa->sa_flags & TARGET_SA_ONSTACK) != 0 && !sas_ss_flags(sp)) {
5473 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
5474 }
5475 return (sp - framesize) & -32;
5476}
5477
5478static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01005479 target_sigset_t *set, CPUAlphaState *env)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005480{
5481 abi_ulong frame_addr, r26;
5482 struct target_sigframe *frame;
5483 int err = 0;
5484
5485 frame_addr = get_sigframe(ka, env, sizeof(*frame));
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01005486 trace_user_setup_frame(env, frame_addr);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005487 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
5488 goto give_sigsegv;
5489 }
5490
Riku Voipio41ecc722014-04-23 11:01:00 +03005491 setup_sigcontext(&frame->sc, env, frame_addr, set);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005492
5493 if (ka->sa_restorer) {
5494 r26 = ka->sa_restorer;
5495 } else {
Riku Voipio1d8b5122014-04-23 10:26:05 +03005496 __put_user(INSN_MOV_R30_R16, &frame->retcode[0]);
5497 __put_user(INSN_LDI_R0 + TARGET_NR_sigreturn,
5498 &frame->retcode[1]);
5499 __put_user(INSN_CALLSYS, &frame->retcode[2]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005500 /* imb() */
5501 r26 = frame_addr;
5502 }
5503
5504 unlock_user_struct(frame, frame_addr, 1);
5505
5506 if (err) {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01005507give_sigsegv:
Richard Henderson6049f4f2009-12-27 18:30:03 -08005508 if (sig == TARGET_SIGSEGV) {
5509 ka->_sa_handler = TARGET_SIG_DFL;
5510 }
5511 force_sig(TARGET_SIGSEGV);
5512 }
5513
5514 env->ir[IR_RA] = r26;
5515 env->ir[IR_PV] = env->pc = ka->_sa_handler;
5516 env->ir[IR_A0] = sig;
5517 env->ir[IR_A1] = 0;
5518 env->ir[IR_A2] = frame_addr + offsetof(struct target_sigframe, sc);
5519 env->ir[IR_SP] = frame_addr;
5520}
5521
5522static void setup_rt_frame(int sig, struct target_sigaction *ka,
5523 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01005524 target_sigset_t *set, CPUAlphaState *env)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005525{
5526 abi_ulong frame_addr, r26;
5527 struct target_rt_sigframe *frame;
5528 int i, err = 0;
5529
5530 frame_addr = get_sigframe(ka, env, sizeof(*frame));
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01005531 trace_user_setup_rt_frame(env, frame_addr);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005532 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
5533 goto give_sigsegv;
5534 }
5535
Peter Maydellf6c7a052015-01-08 12:19:48 +00005536 tswap_siginfo(&frame->info, info);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005537
Riku Voipio1d8b5122014-04-23 10:26:05 +03005538 __put_user(0, &frame->uc.tuc_flags);
5539 __put_user(0, &frame->uc.tuc_link);
5540 __put_user(set->sig[0], &frame->uc.tuc_osf_sigmask);
5541 __put_user(target_sigaltstack_used.ss_sp,
5542 &frame->uc.tuc_stack.ss_sp);
5543 __put_user(sas_ss_flags(env->ir[IR_SP]),
5544 &frame->uc.tuc_stack.ss_flags);
5545 __put_user(target_sigaltstack_used.ss_size,
5546 &frame->uc.tuc_stack.ss_size);
Riku Voipio41ecc722014-04-23 11:01:00 +03005547 setup_sigcontext(&frame->uc.tuc_mcontext, env, frame_addr, set);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005548 for (i = 0; i < TARGET_NSIG_WORDS; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03005549 __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005550 }
5551
5552 if (ka->sa_restorer) {
5553 r26 = ka->sa_restorer;
5554 } else {
Riku Voipio1d8b5122014-04-23 10:26:05 +03005555 __put_user(INSN_MOV_R30_R16, &frame->retcode[0]);
5556 __put_user(INSN_LDI_R0 + TARGET_NR_rt_sigreturn,
5557 &frame->retcode[1]);
5558 __put_user(INSN_CALLSYS, &frame->retcode[2]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005559 /* imb(); */
5560 r26 = frame_addr;
5561 }
5562
5563 if (err) {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01005564give_sigsegv:
5565 if (sig == TARGET_SIGSEGV) {
Richard Henderson6049f4f2009-12-27 18:30:03 -08005566 ka->_sa_handler = TARGET_SIG_DFL;
5567 }
5568 force_sig(TARGET_SIGSEGV);
5569 }
5570
5571 env->ir[IR_RA] = r26;
5572 env->ir[IR_PV] = env->pc = ka->_sa_handler;
5573 env->ir[IR_A0] = sig;
5574 env->ir[IR_A1] = frame_addr + offsetof(struct target_rt_sigframe, info);
5575 env->ir[IR_A2] = frame_addr + offsetof(struct target_rt_sigframe, uc);
5576 env->ir[IR_SP] = frame_addr;
5577}
5578
Andreas Färber05390242012-02-25 03:37:53 +01005579long do_sigreturn(CPUAlphaState *env)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005580{
5581 struct target_sigcontext *sc;
5582 abi_ulong sc_addr = env->ir[IR_A0];
5583 target_sigset_t target_set;
5584 sigset_t set;
5585
5586 if (!lock_user_struct(VERIFY_READ, sc, sc_addr, 1)) {
5587 goto badframe;
5588 }
5589
5590 target_sigemptyset(&target_set);
Riku Voipiof5f601a2014-04-23 13:00:17 +03005591 __get_user(target_set.sig[0], &sc->sc_mask);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005592
5593 target_to_host_sigset_internal(&set, &target_set);
Peter Maydell9eede5b2016-05-27 15:51:46 +01005594 set_sigmask(&set);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005595
Riku Voipio016d2e12014-04-23 11:19:48 +03005596 restore_sigcontext(env, sc);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005597 unlock_user_struct(sc, sc_addr, 0);
Timothy E Baldwin338c8582016-05-12 18:47:36 +01005598 return -TARGET_QEMU_ESIGRETURN;
Richard Henderson6049f4f2009-12-27 18:30:03 -08005599
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01005600badframe:
Richard Henderson6049f4f2009-12-27 18:30:03 -08005601 force_sig(TARGET_SIGSEGV);
5602}
5603
Andreas Färber05390242012-02-25 03:37:53 +01005604long do_rt_sigreturn(CPUAlphaState *env)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005605{
5606 abi_ulong frame_addr = env->ir[IR_A0];
5607 struct target_rt_sigframe *frame;
5608 sigset_t set;
5609
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01005610 trace_user_do_rt_sigreturn(env, frame_addr);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005611 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
5612 goto badframe;
5613 }
Aurelien Jarno60e99242010-03-29 02:12:51 +02005614 target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
Peter Maydell9eede5b2016-05-27 15:51:46 +01005615 set_sigmask(&set);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005616
Riku Voipio016d2e12014-04-23 11:19:48 +03005617 restore_sigcontext(env, &frame->uc.tuc_mcontext);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005618 if (do_sigaltstack(frame_addr + offsetof(struct target_rt_sigframe,
Aurelien Jarno60e99242010-03-29 02:12:51 +02005619 uc.tuc_stack),
Richard Henderson6049f4f2009-12-27 18:30:03 -08005620 0, env->ir[IR_SP]) == -EFAULT) {
5621 goto badframe;
5622 }
5623
5624 unlock_user_struct(frame, frame_addr, 0);
Timothy E Baldwin338c8582016-05-12 18:47:36 +01005625 return -TARGET_QEMU_ESIGRETURN;
Richard Henderson6049f4f2009-12-27 18:30:03 -08005626
5627
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01005628badframe:
Richard Henderson6049f4f2009-12-27 18:30:03 -08005629 unlock_user_struct(frame, frame_addr, 0);
5630 force_sig(TARGET_SIGSEGV);
5631}
5632
Chen Gangbf0f60a2015-09-27 08:10:18 +08005633#elif defined(TARGET_TILEGX)
5634
5635struct target_sigcontext {
5636 union {
5637 /* General-purpose registers. */
5638 abi_ulong gregs[56];
5639 struct {
5640 abi_ulong __gregs[53];
5641 abi_ulong tp; /* Aliases gregs[TREG_TP]. */
5642 abi_ulong sp; /* Aliases gregs[TREG_SP]. */
5643 abi_ulong lr; /* Aliases gregs[TREG_LR]. */
5644 };
5645 };
5646 abi_ulong pc; /* Program counter. */
5647 abi_ulong ics; /* In Interrupt Critical Section? */
5648 abi_ulong faultnum; /* Fault number. */
5649 abi_ulong pad[5];
5650};
5651
5652struct target_ucontext {
5653 abi_ulong tuc_flags;
5654 abi_ulong tuc_link;
5655 target_stack_t tuc_stack;
5656 struct target_sigcontext tuc_mcontext;
5657 target_sigset_t tuc_sigmask; /* mask last for extensibility */
5658};
5659
5660struct target_rt_sigframe {
5661 unsigned char save_area[16]; /* caller save area */
5662 struct target_siginfo info;
5663 struct target_ucontext uc;
Chen Gangf1d9d102016-03-29 21:53:49 +08005664 abi_ulong retcode[2];
Chen Gangbf0f60a2015-09-27 08:10:18 +08005665};
5666
Chen Gangf1d9d102016-03-29 21:53:49 +08005667#define INSN_MOVELI_R10_139 0x00045fe551483000ULL /* { moveli r10, 139 } */
5668#define INSN_SWINT1 0x286b180051485000ULL /* { swint1 } */
5669
5670
Chen Gangbf0f60a2015-09-27 08:10:18 +08005671static void setup_sigcontext(struct target_sigcontext *sc,
5672 CPUArchState *env, int signo)
5673{
5674 int i;
5675
5676 for (i = 0; i < TILEGX_R_COUNT; ++i) {
5677 __put_user(env->regs[i], &sc->gregs[i]);
5678 }
5679
5680 __put_user(env->pc, &sc->pc);
5681 __put_user(0, &sc->ics);
5682 __put_user(signo, &sc->faultnum);
5683}
5684
5685static void restore_sigcontext(CPUTLGState *env, struct target_sigcontext *sc)
5686{
5687 int i;
5688
5689 for (i = 0; i < TILEGX_R_COUNT; ++i) {
5690 __get_user(env->regs[i], &sc->gregs[i]);
5691 }
5692
5693 __get_user(env->pc, &sc->pc);
5694}
5695
5696static abi_ulong get_sigframe(struct target_sigaction *ka, CPUArchState *env,
5697 size_t frame_size)
5698{
5699 unsigned long sp = env->regs[TILEGX_R_SP];
5700
5701 if (on_sig_stack(sp) && !likely(on_sig_stack(sp - frame_size))) {
5702 return -1UL;
5703 }
5704
5705 if ((ka->sa_flags & SA_ONSTACK) && !sas_ss_flags(sp)) {
5706 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
5707 }
5708
5709 sp -= frame_size;
5710 sp &= -16UL;
5711 return sp;
5712}
5713
5714static void setup_rt_frame(int sig, struct target_sigaction *ka,
5715 target_siginfo_t *info,
5716 target_sigset_t *set, CPUArchState *env)
5717{
5718 abi_ulong frame_addr;
5719 struct target_rt_sigframe *frame;
5720 unsigned long restorer;
5721
5722 frame_addr = get_sigframe(ka, env, sizeof(*frame));
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01005723 trace_user_setup_rt_frame(env, frame_addr);
Chen Gangbf0f60a2015-09-27 08:10:18 +08005724 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
5725 goto give_sigsegv;
5726 }
5727
5728 /* Always write at least the signal number for the stack backtracer. */
5729 if (ka->sa_flags & TARGET_SA_SIGINFO) {
5730 /* At sigreturn time, restore the callee-save registers too. */
5731 tswap_siginfo(&frame->info, info);
5732 /* regs->flags |= PT_FLAGS_RESTORE_REGS; FIXME: we can skip it? */
5733 } else {
5734 __put_user(info->si_signo, &frame->info.si_signo);
5735 }
5736
5737 /* Create the ucontext. */
5738 __put_user(0, &frame->uc.tuc_flags);
5739 __put_user(0, &frame->uc.tuc_link);
5740 __put_user(target_sigaltstack_used.ss_sp, &frame->uc.tuc_stack.ss_sp);
5741 __put_user(sas_ss_flags(env->regs[TILEGX_R_SP]),
5742 &frame->uc.tuc_stack.ss_flags);
5743 __put_user(target_sigaltstack_used.ss_size, &frame->uc.tuc_stack.ss_size);
5744 setup_sigcontext(&frame->uc.tuc_mcontext, env, info->si_signo);
5745
Chen Gangbf0f60a2015-09-27 08:10:18 +08005746 if (ka->sa_flags & TARGET_SA_RESTORER) {
Chen Gangf1d9d102016-03-29 21:53:49 +08005747 restorer = (unsigned long) ka->sa_restorer;
5748 } else {
5749 __put_user(INSN_MOVELI_R10_139, &frame->retcode[0]);
5750 __put_user(INSN_SWINT1, &frame->retcode[1]);
5751 restorer = frame_addr + offsetof(struct target_rt_sigframe, retcode);
Chen Gangbf0f60a2015-09-27 08:10:18 +08005752 }
5753 env->pc = (unsigned long) ka->_sa_handler;
5754 env->regs[TILEGX_R_SP] = (unsigned long) frame;
5755 env->regs[TILEGX_R_LR] = restorer;
5756 env->regs[0] = (unsigned long) sig;
5757 env->regs[1] = (unsigned long) &frame->info;
5758 env->regs[2] = (unsigned long) &frame->uc;
5759 /* regs->flags |= PT_FLAGS_CALLER_SAVES; FIXME: we can skip it? */
5760
5761 unlock_user_struct(frame, frame_addr, 1);
5762 return;
5763
5764give_sigsegv:
5765 if (sig == TARGET_SIGSEGV) {
5766 ka->_sa_handler = TARGET_SIG_DFL;
5767 }
5768 force_sig(TARGET_SIGSEGV /* , current */);
5769}
5770
5771long do_rt_sigreturn(CPUTLGState *env)
5772{
5773 abi_ulong frame_addr = env->regs[TILEGX_R_SP];
5774 struct target_rt_sigframe *frame;
5775 sigset_t set;
5776
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01005777 trace_user_do_rt_sigreturn(env, frame_addr);
Chen Gangbf0f60a2015-09-27 08:10:18 +08005778 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
5779 goto badframe;
5780 }
5781 target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
Peter Maydell9eede5b2016-05-27 15:51:46 +01005782 set_sigmask(&set);
Chen Gangbf0f60a2015-09-27 08:10:18 +08005783
5784 restore_sigcontext(env, &frame->uc.tuc_mcontext);
5785 if (do_sigaltstack(frame_addr + offsetof(struct target_rt_sigframe,
5786 uc.tuc_stack),
5787 0, env->regs[TILEGX_R_SP]) == -EFAULT) {
5788 goto badframe;
5789 }
5790
5791 unlock_user_struct(frame, frame_addr, 0);
Peter Maydella9175162016-05-12 18:47:42 +01005792 return -TARGET_QEMU_ESIGRETURN;
Chen Gangbf0f60a2015-09-27 08:10:18 +08005793
5794
5795 badframe:
5796 unlock_user_struct(frame, frame_addr, 0);
5797 force_sig(TARGET_SIGSEGV);
5798}
5799
bellardb346ff42003-06-15 20:05:50 +00005800#else
5801
pbrook624f7972008-05-31 16:11:38 +00005802static void setup_frame(int sig, struct target_sigaction *ka,
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01005803 target_sigset_t *set, CPUArchState *env)
bellardb346ff42003-06-15 20:05:50 +00005804{
5805 fprintf(stderr, "setup_frame: not implemented\n");
5806}
5807
pbrook624f7972008-05-31 16:11:38 +00005808static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05005809 target_siginfo_t *info,
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01005810 target_sigset_t *set, CPUArchState *env)
bellardb346ff42003-06-15 20:05:50 +00005811{
5812 fprintf(stderr, "setup_rt_frame: not implemented\n");
5813}
5814
Andreas Färber9349b4f2012-03-14 01:38:32 +01005815long do_sigreturn(CPUArchState *env)
bellardb346ff42003-06-15 20:05:50 +00005816{
5817 fprintf(stderr, "do_sigreturn: not implemented\n");
bellardf8b0aa22007-11-11 23:03:42 +00005818 return -TARGET_ENOSYS;
bellardb346ff42003-06-15 20:05:50 +00005819}
5820
Andreas Färber9349b4f2012-03-14 01:38:32 +01005821long do_rt_sigreturn(CPUArchState *env)
bellardb346ff42003-06-15 20:05:50 +00005822{
5823 fprintf(stderr, "do_rt_sigreturn: not implemented\n");
bellardf8b0aa22007-11-11 23:03:42 +00005824 return -TARGET_ENOSYS;
bellardb346ff42003-06-15 20:05:50 +00005825}
5826
bellard66fb9762003-03-23 01:06:05 +00005827#endif
5828
Peter Maydelleb552502016-05-27 15:51:43 +01005829static void handle_pending_signal(CPUArchState *cpu_env, int sig)
5830{
5831 CPUState *cpu = ENV_GET_CPU(cpu_env);
5832 abi_ulong handler;
Peter Maydell3d3efba2016-05-27 15:51:49 +01005833 sigset_t set;
Peter Maydelleb552502016-05-27 15:51:43 +01005834 target_sigset_t target_old_set;
5835 struct target_sigaction *sa;
Peter Maydelleb552502016-05-27 15:51:43 +01005836 TaskState *ts = cpu->opaque;
5837 struct emulated_sigtable *k = &ts->sigtab[sig - 1];
5838
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01005839 trace_user_handle_signal(cpu_env, sig);
bellard66fb9762003-03-23 01:06:05 +00005840 /* dequeue signal */
Timothy E Baldwin907f5fd2016-05-27 15:51:52 +01005841 k->pending = 0;
ths3b46e622007-09-17 08:09:54 +00005842
Andreas Färberdb6b81d2013-06-27 19:49:31 +02005843 sig = gdb_handlesig(cpu, sig);
bellard1fddef42005-04-17 19:16:13 +00005844 if (!sig) {
aurel32ca587a82008-12-18 22:44:13 +00005845 sa = NULL;
5846 handler = TARGET_SIG_IGN;
5847 } else {
5848 sa = &sigact_table[sig - 1];
5849 handler = sa->_sa_handler;
bellard1fddef42005-04-17 19:16:13 +00005850 }
bellard66fb9762003-03-23 01:06:05 +00005851
bellard66fb9762003-03-23 01:06:05 +00005852 if (handler == TARGET_SIG_DFL) {
aurel32ca587a82008-12-18 22:44:13 +00005853 /* default handler : ignore some signal. The other are job control or fatal */
5854 if (sig == TARGET_SIGTSTP || sig == TARGET_SIGTTIN || sig == TARGET_SIGTTOU) {
5855 kill(getpid(),SIGSTOP);
5856 } else if (sig != TARGET_SIGCHLD &&
5857 sig != TARGET_SIGURG &&
5858 sig != TARGET_SIGWINCH &&
5859 sig != TARGET_SIGCONT) {
bellard66fb9762003-03-23 01:06:05 +00005860 force_sig(sig);
5861 }
5862 } else if (handler == TARGET_SIG_IGN) {
5863 /* ignore sig */
5864 } else if (handler == TARGET_SIG_ERR) {
5865 force_sig(sig);
5866 } else {
bellard9de5e442003-03-23 16:49:39 +00005867 /* compute the blocked signals during the handler execution */
Peter Maydell3d3efba2016-05-27 15:51:49 +01005868 sigset_t *blocked_set;
5869
pbrook624f7972008-05-31 16:11:38 +00005870 target_to_host_sigset(&set, &sa->sa_mask);
bellard9de5e442003-03-23 16:49:39 +00005871 /* SA_NODEFER indicates that the current signal should not be
5872 blocked during the handler */
pbrook624f7972008-05-31 16:11:38 +00005873 if (!(sa->sa_flags & TARGET_SA_NODEFER))
bellard9de5e442003-03-23 16:49:39 +00005874 sigaddset(&set, target_to_host_signal(sig));
ths3b46e622007-09-17 08:09:54 +00005875
bellard9de5e442003-03-23 16:49:39 +00005876 /* save the previous blocked signal state to restore it at the
5877 end of the signal execution (see do_sigreturn) */
Peter Maydell3d3efba2016-05-27 15:51:49 +01005878 host_to_target_sigset_internal(&target_old_set, &ts->signal_mask);
5879
5880 /* block signals in the handler */
5881 blocked_set = ts->in_sigsuspend ?
5882 &ts->sigsuspend_mask : &ts->signal_mask;
5883 sigorset(&ts->signal_mask, blocked_set, &set);
5884 ts->in_sigsuspend = 0;
bellard9de5e442003-03-23 16:49:39 +00005885
bellardbc8a22c2003-03-30 21:02:40 +00005886 /* if the CPU is in VM86 mode, we restore the 32 bit values */
j_mayer84409dd2007-04-06 08:56:50 +00005887#if defined(TARGET_I386) && !defined(TARGET_X86_64)
bellardbc8a22c2003-03-30 21:02:40 +00005888 {
5889 CPUX86State *env = cpu_env;
5890 if (env->eflags & VM_MASK)
5891 save_v86_state(env);
5892 }
5893#endif
bellard9de5e442003-03-23 16:49:39 +00005894 /* prepare the stack frame of the virtual CPU */
Chen Gangd0924a22015-09-12 23:32:30 +08005895#if defined(TARGET_ABI_MIPSN32) || defined(TARGET_ABI_MIPSN64) \
Chen Gangbf0f60a2015-09-27 08:10:18 +08005896 || defined(TARGET_OPENRISC) || defined(TARGET_TILEGX)
Richard Hendersonff970902013-02-10 10:30:42 -08005897 /* These targets do not have traditional signals. */
Timothy E Baldwin907f5fd2016-05-27 15:51:52 +01005898 setup_rt_frame(sig, sa, &k->info, &target_old_set, cpu_env);
Richard Hendersonff970902013-02-10 10:30:42 -08005899#else
pbrook624f7972008-05-31 16:11:38 +00005900 if (sa->sa_flags & TARGET_SA_SIGINFO)
Timothy E Baldwin907f5fd2016-05-27 15:51:52 +01005901 setup_rt_frame(sig, sa, &k->info, &target_old_set, cpu_env);
bellard66fb9762003-03-23 01:06:05 +00005902 else
pbrook624f7972008-05-31 16:11:38 +00005903 setup_frame(sig, sa, &target_old_set, cpu_env);
Richard Hendersonff970902013-02-10 10:30:42 -08005904#endif
Peter Maydell7ec87e02016-05-27 15:51:45 +01005905 if (sa->sa_flags & TARGET_SA_RESETHAND) {
pbrook624f7972008-05-31 16:11:38 +00005906 sa->_sa_handler = TARGET_SIG_DFL;
Peter Maydell7ec87e02016-05-27 15:51:45 +01005907 }
bellard31e31b82003-02-18 22:55:36 +00005908 }
bellard31e31b82003-02-18 22:55:36 +00005909}
Peter Maydelle902d582016-05-27 15:51:44 +01005910
5911void process_pending_signals(CPUArchState *cpu_env)
5912{
5913 CPUState *cpu = ENV_GET_CPU(cpu_env);
5914 int sig;
5915 TaskState *ts = cpu->opaque;
Peter Maydell3d3efba2016-05-27 15:51:49 +01005916 sigset_t set;
5917 sigset_t *blocked_set;
Peter Maydelle902d582016-05-27 15:51:44 +01005918
Peter Maydell3d3efba2016-05-27 15:51:49 +01005919 while (atomic_read(&ts->signal_pending)) {
5920 /* FIXME: This is not threadsafe. */
5921 sigfillset(&set);
5922 sigprocmask(SIG_SETMASK, &set, 0);
Peter Maydelle902d582016-05-27 15:51:44 +01005923
Timothy E Baldwin655ed672016-05-27 15:51:53 +01005924 sig = ts->sync_signal.pending;
5925 if (sig) {
5926 /* Synchronous signals are forced,
5927 * see force_sig_info() and callers in Linux
5928 * Note that not all of our queue_signal() calls in QEMU correspond
5929 * to force_sig_info() calls in Linux (some are send_sig_info()).
5930 * However it seems like a kernel bug to me to allow the process
5931 * to block a synchronous signal since it could then just end up
5932 * looping round and round indefinitely.
5933 */
5934 if (sigismember(&ts->signal_mask, target_to_host_signal_table[sig])
5935 || sigact_table[sig - 1]._sa_handler == TARGET_SIG_IGN) {
5936 sigdelset(&ts->signal_mask, target_to_host_signal_table[sig]);
5937 sigact_table[sig - 1]._sa_handler = TARGET_SIG_DFL;
5938 }
5939
5940 handle_pending_signal(cpu_env, sig);
5941 }
5942
Peter Maydell3d3efba2016-05-27 15:51:49 +01005943 for (sig = 1; sig <= TARGET_NSIG; sig++) {
5944 blocked_set = ts->in_sigsuspend ?
5945 &ts->sigsuspend_mask : &ts->signal_mask;
5946
5947 if (ts->sigtab[sig - 1].pending &&
5948 (!sigismember(blocked_set,
Timothy E Baldwin655ed672016-05-27 15:51:53 +01005949 target_to_host_signal_table[sig]))) {
Peter Maydell3d3efba2016-05-27 15:51:49 +01005950 handle_pending_signal(cpu_env, sig);
5951 /* Restart scan from the beginning */
5952 sig = 1;
5953 }
Peter Maydelle902d582016-05-27 15:51:44 +01005954 }
Peter Maydell3d3efba2016-05-27 15:51:49 +01005955
5956 /* if no signal is pending, unblock signals and recheck (the act
5957 * of unblocking might cause us to take another host signal which
5958 * will set signal_pending again).
5959 */
5960 atomic_set(&ts->signal_pending, 0);
5961 ts->in_sigsuspend = 0;
5962 set = ts->signal_mask;
5963 sigdelset(&set, SIGSEGV);
5964 sigdelset(&set, SIGBUS);
5965 sigprocmask(SIG_SETMASK, &set, 0);
Peter Maydelle902d582016-05-27 15:51:44 +01005966 }
Peter Maydell3d3efba2016-05-27 15:51:49 +01005967 ts->in_sigsuspend = 0;
Peter Maydelle902d582016-05-27 15:51:44 +01005968}