blob: 93a929364153a4f37ff8828f2fc2d91e72eb5a17 [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 */
Peter Maydell9d2803f2016-07-28 16:44:46 +0100572int queue_signal(CPUArchState *env, int sig, int si_type,
573 target_siginfo_t *info)
bellard31e31b82003-02-18 22:55:36 +0000574{
Andreas Färber0429a972013-08-26 18:14:44 +0200575 CPUState *cpu = ENV_GET_CPU(env);
576 TaskState *ts = cpu->opaque;
bellard66fb9762003-03-23 01:06:05 +0000577
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +0100578 trace_user_queue_signal(env, sig);
Peter Maydella7ec0f92014-03-14 14:36:56 +0000579
Peter Maydell9d2803f2016-07-28 16:44:46 +0100580 info->si_code = deposit32(info->si_code, 16, 16, si_type);
Peter Maydella70dadc2016-05-27 15:51:59 +0100581
Timothy E Baldwin655ed672016-05-27 15:51:53 +0100582 ts->sync_signal.info = *info;
583 ts->sync_signal.pending = sig;
Timothy E Baldwin907f5fd2016-05-27 15:51:52 +0100584 /* signal that a new signal is pending */
585 atomic_set(&ts->signal_pending, 1);
586 return 1; /* indicates that the signal was queued */
bellard9de5e442003-03-23 16:49:39 +0000587}
588
Timothy E Baldwin4d330ce2016-05-12 18:47:46 +0100589#ifndef HAVE_SAFE_SYSCALL
590static inline void rewind_if_in_safe_syscall(void *puc)
591{
592 /* Default version: never rewind */
593}
594#endif
595
ths5fafdf22007-09-16 21:08:06 +0000596static void host_signal_handler(int host_signum, siginfo_t *info,
bellard9de5e442003-03-23 16:49:39 +0000597 void *puc)
598{
Andreas Färbera2247f82013-06-09 19:47:04 +0200599 CPUArchState *env = thread_cpu->env_ptr;
Timothy E Baldwin655ed672016-05-27 15:51:53 +0100600 CPUState *cpu = ENV_GET_CPU(env);
601 TaskState *ts = cpu->opaque;
602
bellard9de5e442003-03-23 16:49:39 +0000603 int sig;
Anthony Liguoric227f092009-10-01 16:12:16 -0500604 target_siginfo_t tinfo;
Peter Maydell3d3efba2016-05-27 15:51:49 +0100605 ucontext_t *uc = puc;
Timothy E Baldwin655ed672016-05-27 15:51:53 +0100606 struct emulated_sigtable *k;
bellard9de5e442003-03-23 16:49:39 +0000607
608 /* the CPU emulator uses some host signals to detect exceptions,
aurel32eaa449b2009-01-03 13:14:52 +0000609 we forward to it some signals */
aurel32ca587a82008-12-18 22:44:13 +0000610 if ((host_signum == SIGSEGV || host_signum == SIGBUS)
aurel32eaa449b2009-01-03 13:14:52 +0000611 && info->si_code > 0) {
bellardb346ff42003-06-15 20:05:50 +0000612 if (cpu_signal_handler(host_signum, info, puc))
bellard9de5e442003-03-23 16:49:39 +0000613 return;
614 }
615
616 /* get target signal number */
617 sig = host_to_target_signal(host_signum);
618 if (sig < 1 || sig > TARGET_NSIG)
619 return;
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +0100620 trace_user_host_signal(env, host_signum, sig);
Timothy E Baldwin4d330ce2016-05-12 18:47:46 +0100621
622 rewind_if_in_safe_syscall(puc);
623
bellard9de5e442003-03-23 16:49:39 +0000624 host_to_target_siginfo_noswap(&tinfo, info);
Timothy E Baldwin655ed672016-05-27 15:51:53 +0100625 k = &ts->sigtab[sig - 1];
626 k->info = tinfo;
627 k->pending = sig;
628 ts->signal_pending = 1;
Peter Maydell3d3efba2016-05-27 15:51:49 +0100629
Timothy E Baldwin655ed672016-05-27 15:51:53 +0100630 /* Block host signals until target signal handler entered. We
631 * can't block SIGSEGV or SIGBUS while we're executing guest
632 * code in case the guest code provokes one in the window between
633 * now and it getting out to the main loop. Signals will be
634 * unblocked again in process_pending_signals().
Peter Maydell1d48fdd2016-06-14 12:49:18 +0100635 *
636 * WARNING: we cannot use sigfillset() here because the uc_sigmask
637 * field is a kernel sigset_t, which is much smaller than the
638 * libc sigset_t which sigfillset() operates on. Using sigfillset()
639 * would write 0xff bytes off the end of the structure and trash
640 * data on the struct.
641 * We can't use sizeof(uc->uc_sigmask) either, because the libc
642 * headers define the struct field with the wrong (too large) type.
Timothy E Baldwin655ed672016-05-27 15:51:53 +0100643 */
Peter Maydell1d48fdd2016-06-14 12:49:18 +0100644 memset(&uc->uc_sigmask, 0xff, SIGSET_T_SIZE);
Timothy E Baldwin655ed672016-05-27 15:51:53 +0100645 sigdelset(&uc->uc_sigmask, SIGSEGV);
646 sigdelset(&uc->uc_sigmask, SIGBUS);
647
648 /* interrupt the virtual CPU as soon as possible */
649 cpu_exit(thread_cpu);
bellard31e31b82003-02-18 22:55:36 +0000650}
651
ths0da46a62007-10-20 20:23:07 +0000652/* do_sigaltstack() returns target values and errnos. */
bellard579a97f2007-11-11 14:26:47 +0000653/* compare linux/kernel/signal.c:do_sigaltstack() */
654abi_long do_sigaltstack(abi_ulong uss_addr, abi_ulong uoss_addr, abi_ulong sp)
thsa04e1342007-09-27 13:57:58 +0000655{
656 int ret;
657 struct target_sigaltstack oss;
658
659 /* XXX: test errors */
bellard579a97f2007-11-11 14:26:47 +0000660 if(uoss_addr)
thsa04e1342007-09-27 13:57:58 +0000661 {
662 __put_user(target_sigaltstack_used.ss_sp, &oss.ss_sp);
663 __put_user(target_sigaltstack_used.ss_size, &oss.ss_size);
664 __put_user(sas_ss_flags(sp), &oss.ss_flags);
665 }
666
bellard579a97f2007-11-11 14:26:47 +0000667 if(uss_addr)
thsa04e1342007-09-27 13:57:58 +0000668 {
bellard579a97f2007-11-11 14:26:47 +0000669 struct target_sigaltstack *uss;
670 struct target_sigaltstack ss;
Tom Musta0903c8b2014-08-12 13:53:40 -0500671 size_t minstacksize = TARGET_MINSIGSTKSZ;
672
673#if defined(TARGET_PPC64)
674 /* ELF V2 for PPC64 has a 4K minimum stack size for signal handlers */
675 struct image_info *image = ((TaskState *)thread_cpu->opaque)->info;
676 if (get_ppc64_abi(image) > 1) {
677 minstacksize = 4096;
678 }
679#endif
thsa04e1342007-09-27 13:57:58 +0000680
ths0da46a62007-10-20 20:23:07 +0000681 ret = -TARGET_EFAULT;
Riku Voipio9eeb8302014-04-23 11:26:34 +0300682 if (!lock_user_struct(VERIFY_READ, uss, uss_addr, 1)) {
thsa04e1342007-09-27 13:57:58 +0000683 goto out;
Riku Voipio9eeb8302014-04-23 11:26:34 +0300684 }
685 __get_user(ss.ss_sp, &uss->ss_sp);
686 __get_user(ss.ss_size, &uss->ss_size);
687 __get_user(ss.ss_flags, &uss->ss_flags);
bellard579a97f2007-11-11 14:26:47 +0000688 unlock_user_struct(uss, uss_addr, 0);
thsa04e1342007-09-27 13:57:58 +0000689
ths0da46a62007-10-20 20:23:07 +0000690 ret = -TARGET_EPERM;
thsa04e1342007-09-27 13:57:58 +0000691 if (on_sig_stack(sp))
692 goto out;
693
ths0da46a62007-10-20 20:23:07 +0000694 ret = -TARGET_EINVAL;
thsa04e1342007-09-27 13:57:58 +0000695 if (ss.ss_flags != TARGET_SS_DISABLE
696 && ss.ss_flags != TARGET_SS_ONSTACK
697 && ss.ss_flags != 0)
698 goto out;
699
700 if (ss.ss_flags == TARGET_SS_DISABLE) {
701 ss.ss_size = 0;
702 ss.ss_sp = 0;
703 } else {
ths0da46a62007-10-20 20:23:07 +0000704 ret = -TARGET_ENOMEM;
Tom Musta0903c8b2014-08-12 13:53:40 -0500705 if (ss.ss_size < minstacksize) {
thsa04e1342007-09-27 13:57:58 +0000706 goto out;
Tom Musta0903c8b2014-08-12 13:53:40 -0500707 }
thsa04e1342007-09-27 13:57:58 +0000708 }
709
710 target_sigaltstack_used.ss_sp = ss.ss_sp;
711 target_sigaltstack_used.ss_size = ss.ss_size;
712 }
713
bellard579a97f2007-11-11 14:26:47 +0000714 if (uoss_addr) {
ths0da46a62007-10-20 20:23:07 +0000715 ret = -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +0000716 if (copy_to_user(uoss_addr, &oss, sizeof(oss)))
thsa04e1342007-09-27 13:57:58 +0000717 goto out;
thsa04e1342007-09-27 13:57:58 +0000718 }
719
720 ret = 0;
721out:
722 return ret;
723}
724
Timothy E Baldwinef6a7782016-05-27 15:51:54 +0100725/* do_sigaction() return target values and host errnos */
bellard66fb9762003-03-23 01:06:05 +0000726int do_sigaction(int sig, const struct target_sigaction *act,
727 struct target_sigaction *oact)
bellard31e31b82003-02-18 22:55:36 +0000728{
pbrook624f7972008-05-31 16:11:38 +0000729 struct target_sigaction *k;
bellard773b93e2004-01-04 17:15:59 +0000730 struct sigaction act1;
731 int host_sig;
ths0da46a62007-10-20 20:23:07 +0000732 int ret = 0;
bellard31e31b82003-02-18 22:55:36 +0000733
Timothy E Baldwinef6a7782016-05-27 15:51:54 +0100734 if (sig < 1 || sig > TARGET_NSIG || sig == TARGET_SIGKILL || sig == TARGET_SIGSTOP) {
735 return -TARGET_EINVAL;
736 }
737
738 if (block_signals()) {
739 return -TARGET_ERESTARTSYS;
740 }
741
bellard66fb9762003-03-23 01:06:05 +0000742 k = &sigact_table[sig - 1];
bellard66fb9762003-03-23 01:06:05 +0000743 if (oact) {
Richard Hendersond2565872013-01-04 16:39:32 -0800744 __put_user(k->_sa_handler, &oact->_sa_handler);
745 __put_user(k->sa_flags, &oact->sa_flags);
ths388bb212007-05-13 13:58:00 +0000746#if !defined(TARGET_MIPS)
Richard Hendersond2565872013-01-04 16:39:32 -0800747 __put_user(k->sa_restorer, &oact->sa_restorer);
ths388bb212007-05-13 13:58:00 +0000748#endif
Richard Hendersond2565872013-01-04 16:39:32 -0800749 /* Not swapped. */
pbrook624f7972008-05-31 16:11:38 +0000750 oact->sa_mask = k->sa_mask;
bellard66fb9762003-03-23 01:06:05 +0000751 }
752 if (act) {
pbrook624f7972008-05-31 16:11:38 +0000753 /* FIXME: This is not threadsafe. */
Richard Hendersond2565872013-01-04 16:39:32 -0800754 __get_user(k->_sa_handler, &act->_sa_handler);
755 __get_user(k->sa_flags, &act->sa_flags);
ths388bb212007-05-13 13:58:00 +0000756#if !defined(TARGET_MIPS)
Richard Hendersond2565872013-01-04 16:39:32 -0800757 __get_user(k->sa_restorer, &act->sa_restorer);
ths388bb212007-05-13 13:58:00 +0000758#endif
Richard Hendersond2565872013-01-04 16:39:32 -0800759 /* To be swapped in target_to_host_sigset. */
pbrook624f7972008-05-31 16:11:38 +0000760 k->sa_mask = act->sa_mask;
bellard773b93e2004-01-04 17:15:59 +0000761
762 /* we update the host linux signal state */
763 host_sig = target_to_host_signal(sig);
764 if (host_sig != SIGSEGV && host_sig != SIGBUS) {
765 sigfillset(&act1.sa_mask);
766 act1.sa_flags = SA_SIGINFO;
pbrook624f7972008-05-31 16:11:38 +0000767 if (k->sa_flags & TARGET_SA_RESTART)
bellard773b93e2004-01-04 17:15:59 +0000768 act1.sa_flags |= SA_RESTART;
769 /* NOTE: it is important to update the host kernel signal
770 ignore state to avoid getting unexpected interrupted
771 syscalls */
pbrook624f7972008-05-31 16:11:38 +0000772 if (k->_sa_handler == TARGET_SIG_IGN) {
bellard773b93e2004-01-04 17:15:59 +0000773 act1.sa_sigaction = (void *)SIG_IGN;
pbrook624f7972008-05-31 16:11:38 +0000774 } else if (k->_sa_handler == TARGET_SIG_DFL) {
aurel32ca587a82008-12-18 22:44:13 +0000775 if (fatal_signal (sig))
776 act1.sa_sigaction = host_signal_handler;
777 else
778 act1.sa_sigaction = (void *)SIG_DFL;
bellard773b93e2004-01-04 17:15:59 +0000779 } else {
780 act1.sa_sigaction = host_signal_handler;
781 }
ths0da46a62007-10-20 20:23:07 +0000782 ret = sigaction(host_sig, &act1, NULL);
bellard773b93e2004-01-04 17:15:59 +0000783 }
bellard66fb9762003-03-23 01:06:05 +0000784 }
ths0da46a62007-10-20 20:23:07 +0000785 return ret;
bellard66fb9762003-03-23 01:06:05 +0000786}
bellard31e31b82003-02-18 22:55:36 +0000787
bellard459a4012007-11-11 19:45:10 +0000788#if defined(TARGET_I386) && TARGET_ABI_BITS == 32
bellard66fb9762003-03-23 01:06:05 +0000789
790/* from the Linux kernel */
791
792struct target_fpreg {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100793 uint16_t significand[4];
794 uint16_t exponent;
bellard66fb9762003-03-23 01:06:05 +0000795};
796
797struct target_fpxreg {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100798 uint16_t significand[4];
799 uint16_t exponent;
800 uint16_t padding[3];
bellard66fb9762003-03-23 01:06:05 +0000801};
802
803struct target_xmmreg {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100804 abi_ulong element[4];
bellard66fb9762003-03-23 01:06:05 +0000805};
806
807struct target_fpstate {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100808 /* Regular FPU environment */
809 abi_ulong cw;
810 abi_ulong sw;
811 abi_ulong tag;
812 abi_ulong ipoff;
813 abi_ulong cssel;
814 abi_ulong dataoff;
815 abi_ulong datasel;
816 struct target_fpreg _st[8];
817 uint16_t status;
818 uint16_t magic; /* 0xffff = regular FPU data only */
bellard66fb9762003-03-23 01:06:05 +0000819
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100820 /* FXSR FPU environment */
821 abi_ulong _fxsr_env[6]; /* FXSR FPU env is ignored */
822 abi_ulong mxcsr;
823 abi_ulong reserved;
824 struct target_fpxreg _fxsr_st[8]; /* FXSR FPU reg data is ignored */
825 struct target_xmmreg _xmm[8];
826 abi_ulong padding[56];
bellard66fb9762003-03-23 01:06:05 +0000827};
828
829#define X86_FXSR_MAGIC 0x0000
830
831struct target_sigcontext {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100832 uint16_t gs, __gsh;
833 uint16_t fs, __fsh;
834 uint16_t es, __esh;
835 uint16_t ds, __dsh;
836 abi_ulong edi;
837 abi_ulong esi;
838 abi_ulong ebp;
839 abi_ulong esp;
840 abi_ulong ebx;
841 abi_ulong edx;
842 abi_ulong ecx;
843 abi_ulong eax;
844 abi_ulong trapno;
845 abi_ulong err;
846 abi_ulong eip;
847 uint16_t cs, __csh;
848 abi_ulong eflags;
849 abi_ulong esp_at_signal;
850 uint16_t ss, __ssh;
851 abi_ulong fpstate; /* pointer */
852 abi_ulong oldmask;
853 abi_ulong cr2;
bellard66fb9762003-03-23 01:06:05 +0000854};
855
bellard66fb9762003-03-23 01:06:05 +0000856struct target_ucontext {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100857 abi_ulong tuc_flags;
858 abi_ulong tuc_link;
859 target_stack_t tuc_stack;
860 struct target_sigcontext tuc_mcontext;
861 target_sigset_t tuc_sigmask; /* mask last for extensibility */
bellard66fb9762003-03-23 01:06:05 +0000862};
863
864struct sigframe
865{
blueswir1992f48a2007-10-14 16:27:31 +0000866 abi_ulong pretcode;
bellard66fb9762003-03-23 01:06:05 +0000867 int sig;
868 struct target_sigcontext sc;
869 struct target_fpstate fpstate;
blueswir1992f48a2007-10-14 16:27:31 +0000870 abi_ulong extramask[TARGET_NSIG_WORDS-1];
bellard66fb9762003-03-23 01:06:05 +0000871 char retcode[8];
872};
873
874struct rt_sigframe
875{
blueswir1992f48a2007-10-14 16:27:31 +0000876 abi_ulong pretcode;
bellard66fb9762003-03-23 01:06:05 +0000877 int sig;
blueswir1992f48a2007-10-14 16:27:31 +0000878 abi_ulong pinfo;
879 abi_ulong puc;
bellard66fb9762003-03-23 01:06:05 +0000880 struct target_siginfo info;
881 struct target_ucontext uc;
882 struct target_fpstate fpstate;
883 char retcode[8];
884};
885
886/*
887 * Set up a signal frame.
888 */
889
bellard66fb9762003-03-23 01:06:05 +0000890/* XXX: save x87 state */
Riku Voipio41ecc722014-04-23 11:01:00 +0300891static void setup_sigcontext(struct target_sigcontext *sc,
892 struct target_fpstate *fpstate, CPUX86State *env, abi_ulong mask,
893 abi_ulong fpstate_addr)
bellard66fb9762003-03-23 01:06:05 +0000894{
Andreas Färber27103422013-08-26 08:31:06 +0200895 CPUState *cs = CPU(x86_env_get_cpu(env));
Andreas Färber27103422013-08-26 08:31:06 +0200896 uint16_t magic;
bellard66fb9762003-03-23 01:06:05 +0000897
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100898 /* already locked in setup_frame() */
Riku Voipio1d8b5122014-04-23 10:26:05 +0300899 __put_user(env->segs[R_GS].selector, (unsigned int *)&sc->gs);
900 __put_user(env->segs[R_FS].selector, (unsigned int *)&sc->fs);
901 __put_user(env->segs[R_ES].selector, (unsigned int *)&sc->es);
902 __put_user(env->segs[R_DS].selector, (unsigned int *)&sc->ds);
903 __put_user(env->regs[R_EDI], &sc->edi);
904 __put_user(env->regs[R_ESI], &sc->esi);
905 __put_user(env->regs[R_EBP], &sc->ebp);
906 __put_user(env->regs[R_ESP], &sc->esp);
907 __put_user(env->regs[R_EBX], &sc->ebx);
908 __put_user(env->regs[R_EDX], &sc->edx);
909 __put_user(env->regs[R_ECX], &sc->ecx);
910 __put_user(env->regs[R_EAX], &sc->eax);
911 __put_user(cs->exception_index, &sc->trapno);
912 __put_user(env->error_code, &sc->err);
913 __put_user(env->eip, &sc->eip);
914 __put_user(env->segs[R_CS].selector, (unsigned int *)&sc->cs);
915 __put_user(env->eflags, &sc->eflags);
916 __put_user(env->regs[R_ESP], &sc->esp_at_signal);
917 __put_user(env->segs[R_SS].selector, (unsigned int *)&sc->ss);
bellarded2dcdf2003-05-29 20:06:27 +0000918
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100919 cpu_x86_fsave(env, fpstate_addr, 1);
920 fpstate->status = fpstate->sw;
921 magic = 0xffff;
Riku Voipio1d8b5122014-04-23 10:26:05 +0300922 __put_user(magic, &fpstate->magic);
923 __put_user(fpstate_addr, &sc->fpstate);
bellarded2dcdf2003-05-29 20:06:27 +0000924
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100925 /* non-iBCS2 extensions.. */
Riku Voipio1d8b5122014-04-23 10:26:05 +0300926 __put_user(mask, &sc->oldmask);
927 __put_user(env->cr[2], &sc->cr2);
bellard66fb9762003-03-23 01:06:05 +0000928}
929
930/*
931 * Determine which stack to use..
932 */
933
bellard579a97f2007-11-11 14:26:47 +0000934static inline abi_ulong
pbrook624f7972008-05-31 16:11:38 +0000935get_sigframe(struct target_sigaction *ka, CPUX86State *env, size_t frame_size)
bellard66fb9762003-03-23 01:06:05 +0000936{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100937 unsigned long esp;
bellard66fb9762003-03-23 01:06:05 +0000938
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100939 /* Default to using normal stack */
940 esp = env->regs[R_ESP];
941 /* This is the X/Open sanctioned signal stack switching. */
942 if (ka->sa_flags & TARGET_SA_ONSTACK) {
943 if (sas_ss_flags(esp) == 0) {
944 esp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
thsa04e1342007-09-27 13:57:58 +0000945 }
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100946 } else {
bellard66fb9762003-03-23 01:06:05 +0000947
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100948 /* This is the legacy signal stack switching. */
bellarda52c7572003-06-21 13:14:12 +0000949 if ((env->segs[R_SS].selector & 0xffff) != __USER_DS &&
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100950 !(ka->sa_flags & TARGET_SA_RESTORER) &&
951 ka->sa_restorer) {
pbrook624f7972008-05-31 16:11:38 +0000952 esp = (unsigned long) ka->sa_restorer;
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100953 }
954 }
955 return (esp - frame_size) & -8ul;
bellard66fb9762003-03-23 01:06:05 +0000956}
957
bellard579a97f2007-11-11 14:26:47 +0000958/* compare linux/arch/i386/kernel/signal.c:setup_frame() */
pbrook624f7972008-05-31 16:11:38 +0000959static void setup_frame(int sig, struct target_sigaction *ka,
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100960 target_sigset_t *set, CPUX86State *env)
bellard66fb9762003-03-23 01:06:05 +0000961{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100962 abi_ulong frame_addr;
963 struct sigframe *frame;
964 int i;
bellard66fb9762003-03-23 01:06:05 +0000965
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100966 frame_addr = get_sigframe(ka, env, sizeof(*frame));
967 trace_user_setup_frame(env, frame_addr);
bellard66fb9762003-03-23 01:06:05 +0000968
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100969 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
970 goto give_sigsegv;
bellard579a97f2007-11-11 14:26:47 +0000971
Peter Maydellb6e2c932015-01-08 12:19:43 +0000972 __put_user(sig, &frame->sig);
bellard66fb9762003-03-23 01:06:05 +0000973
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100974 setup_sigcontext(&frame->sc, &frame->fpstate, env, set->sig[0],
975 frame_addr + offsetof(struct sigframe, fpstate));
bellard66fb9762003-03-23 01:06:05 +0000976
Riku Voipio7df2fa32014-04-23 10:34:53 +0300977 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
978 __put_user(set->sig[i], &frame->extramask[i - 1]);
979 }
bellard66fb9762003-03-23 01:06:05 +0000980
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100981 /* Set up to return from userspace. If provided, use a stub
982 already in userspace. */
983 if (ka->sa_flags & TARGET_SA_RESTORER) {
Riku Voipio1d8b5122014-04-23 10:26:05 +0300984 __put_user(ka->sa_restorer, &frame->pretcode);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100985 } else {
986 uint16_t val16;
987 abi_ulong retcode_addr;
988 retcode_addr = frame_addr + offsetof(struct sigframe, retcode);
Riku Voipio1d8b5122014-04-23 10:26:05 +0300989 __put_user(retcode_addr, &frame->pretcode);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100990 /* This is popl %eax ; movl $,%eax ; int $0x80 */
991 val16 = 0xb858;
Riku Voipio1d8b5122014-04-23 10:26:05 +0300992 __put_user(val16, (uint16_t *)(frame->retcode+0));
993 __put_user(TARGET_NR_sigreturn, (int *)(frame->retcode+2));
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100994 val16 = 0x80cd;
Riku Voipio1d8b5122014-04-23 10:26:05 +0300995 __put_user(val16, (uint16_t *)(frame->retcode+6));
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100996 }
bellard66fb9762003-03-23 01:06:05 +0000997
bellard66fb9762003-03-23 01:06:05 +0000998
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100999 /* Set up registers for signal handler */
1000 env->regs[R_ESP] = frame_addr;
1001 env->eip = ka->_sa_handler;
bellard66fb9762003-03-23 01:06:05 +00001002
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001003 cpu_x86_load_seg(env, R_DS, __USER_DS);
1004 cpu_x86_load_seg(env, R_ES, __USER_DS);
1005 cpu_x86_load_seg(env, R_SS, __USER_DS);
1006 cpu_x86_load_seg(env, R_CS, __USER_CS);
1007 env->eflags &= ~TF_MASK;
bellard66fb9762003-03-23 01:06:05 +00001008
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001009 unlock_user_struct(frame, frame_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00001010
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001011 return;
bellard66fb9762003-03-23 01:06:05 +00001012
1013give_sigsegv:
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001014 if (sig == TARGET_SIGSEGV) {
1015 ka->_sa_handler = TARGET_SIG_DFL;
1016 }
1017 force_sig(TARGET_SIGSEGV /* , current */);
bellard66fb9762003-03-23 01:06:05 +00001018}
1019
bellard579a97f2007-11-11 14:26:47 +00001020/* compare linux/arch/i386/kernel/signal.c:setup_rt_frame() */
pbrook624f7972008-05-31 16:11:38 +00001021static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05001022 target_siginfo_t *info,
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001023 target_sigset_t *set, CPUX86State *env)
bellard66fb9762003-03-23 01:06:05 +00001024{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001025 abi_ulong frame_addr, addr;
1026 struct rt_sigframe *frame;
1027 int i;
bellard66fb9762003-03-23 01:06:05 +00001028
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001029 frame_addr = get_sigframe(ka, env, sizeof(*frame));
1030 trace_user_setup_rt_frame(env, frame_addr);
bellard66fb9762003-03-23 01:06:05 +00001031
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001032 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
1033 goto give_sigsegv;
bellard66fb9762003-03-23 01:06:05 +00001034
Peter Maydellb6e2c932015-01-08 12:19:43 +00001035 __put_user(sig, &frame->sig);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001036 addr = frame_addr + offsetof(struct rt_sigframe, info);
Riku Voipio1d8b5122014-04-23 10:26:05 +03001037 __put_user(addr, &frame->pinfo);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001038 addr = frame_addr + offsetof(struct rt_sigframe, uc);
Riku Voipio1d8b5122014-04-23 10:26:05 +03001039 __put_user(addr, &frame->puc);
Peter Maydellf6c7a052015-01-08 12:19:48 +00001040 tswap_siginfo(&frame->info, info);
bellard66fb9762003-03-23 01:06:05 +00001041
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001042 /* Create the ucontext. */
Riku Voipio1d8b5122014-04-23 10:26:05 +03001043 __put_user(0, &frame->uc.tuc_flags);
1044 __put_user(0, &frame->uc.tuc_link);
1045 __put_user(target_sigaltstack_used.ss_sp, &frame->uc.tuc_stack.ss_sp);
1046 __put_user(sas_ss_flags(get_sp_from_cpustate(env)),
1047 &frame->uc.tuc_stack.ss_flags);
1048 __put_user(target_sigaltstack_used.ss_size,
1049 &frame->uc.tuc_stack.ss_size);
Riku Voipio41ecc722014-04-23 11:01:00 +03001050 setup_sigcontext(&frame->uc.tuc_mcontext, &frame->fpstate, env,
1051 set->sig[0], frame_addr + offsetof(struct rt_sigframe, fpstate));
1052
Riku Voipio0188fad2014-04-23 13:34:15 +03001053 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
1054 __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
1055 }
bellard66fb9762003-03-23 01:06:05 +00001056
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001057 /* Set up to return from userspace. If provided, use a stub
1058 already in userspace. */
1059 if (ka->sa_flags & TARGET_SA_RESTORER) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03001060 __put_user(ka->sa_restorer, &frame->pretcode);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001061 } else {
1062 uint16_t val16;
1063 addr = frame_addr + offsetof(struct rt_sigframe, retcode);
Riku Voipio1d8b5122014-04-23 10:26:05 +03001064 __put_user(addr, &frame->pretcode);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001065 /* This is movl $,%eax ; int $0x80 */
Riku Voipio1d8b5122014-04-23 10:26:05 +03001066 __put_user(0xb8, (char *)(frame->retcode+0));
1067 __put_user(TARGET_NR_rt_sigreturn, (int *)(frame->retcode+1));
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001068 val16 = 0x80cd;
Riku Voipio1d8b5122014-04-23 10:26:05 +03001069 __put_user(val16, (uint16_t *)(frame->retcode+5));
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001070 }
bellard66fb9762003-03-23 01:06:05 +00001071
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001072 /* Set up registers for signal handler */
1073 env->regs[R_ESP] = frame_addr;
1074 env->eip = ka->_sa_handler;
bellard66fb9762003-03-23 01:06:05 +00001075
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001076 cpu_x86_load_seg(env, R_DS, __USER_DS);
1077 cpu_x86_load_seg(env, R_ES, __USER_DS);
1078 cpu_x86_load_seg(env, R_SS, __USER_DS);
1079 cpu_x86_load_seg(env, R_CS, __USER_CS);
1080 env->eflags &= ~TF_MASK;
bellard66fb9762003-03-23 01:06:05 +00001081
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001082 unlock_user_struct(frame, frame_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00001083
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001084 return;
bellard66fb9762003-03-23 01:06:05 +00001085
1086give_sigsegv:
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001087 if (sig == TARGET_SIGSEGV) {
1088 ka->_sa_handler = TARGET_SIG_DFL;
1089 }
1090 force_sig(TARGET_SIGSEGV /* , current */);
bellard66fb9762003-03-23 01:06:05 +00001091}
1092
1093static int
Timothy E Baldwin0284b032016-05-12 18:47:30 +01001094restore_sigcontext(CPUX86State *env, struct target_sigcontext *sc)
bellard66fb9762003-03-23 01:06:05 +00001095{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001096 unsigned int err = 0;
1097 abi_ulong fpstate_addr;
1098 unsigned int tmpflags;
bellard66fb9762003-03-23 01:06:05 +00001099
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001100 cpu_x86_load_seg(env, R_GS, tswap16(sc->gs));
1101 cpu_x86_load_seg(env, R_FS, tswap16(sc->fs));
1102 cpu_x86_load_seg(env, R_ES, tswap16(sc->es));
1103 cpu_x86_load_seg(env, R_DS, tswap16(sc->ds));
bellard66fb9762003-03-23 01:06:05 +00001104
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001105 env->regs[R_EDI] = tswapl(sc->edi);
1106 env->regs[R_ESI] = tswapl(sc->esi);
1107 env->regs[R_EBP] = tswapl(sc->ebp);
1108 env->regs[R_ESP] = tswapl(sc->esp);
1109 env->regs[R_EBX] = tswapl(sc->ebx);
1110 env->regs[R_EDX] = tswapl(sc->edx);
1111 env->regs[R_ECX] = tswapl(sc->ecx);
Timothy E Baldwin0284b032016-05-12 18:47:30 +01001112 env->regs[R_EAX] = tswapl(sc->eax);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001113 env->eip = tswapl(sc->eip);
bellard66fb9762003-03-23 01:06:05 +00001114
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001115 cpu_x86_load_seg(env, R_CS, lduw_p(&sc->cs) | 3);
1116 cpu_x86_load_seg(env, R_SS, lduw_p(&sc->ss) | 3);
ths5fafdf22007-09-16 21:08:06 +00001117
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001118 tmpflags = tswapl(sc->eflags);
1119 env->eflags = (env->eflags & ~0x40DD5) | (tmpflags & 0x40DD5);
1120 // regs->orig_eax = -1; /* disable syscall checks */
bellard28be6232007-11-11 22:23:38 +00001121
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001122 fpstate_addr = tswapl(sc->fpstate);
1123 if (fpstate_addr != 0) {
1124 if (!access_ok(VERIFY_READ, fpstate_addr,
1125 sizeof(struct target_fpstate)))
1126 goto badframe;
1127 cpu_x86_frstor(env, fpstate_addr, 1);
1128 }
bellard66fb9762003-03-23 01:06:05 +00001129
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001130 return err;
bellard66fb9762003-03-23 01:06:05 +00001131badframe:
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001132 return 1;
bellard66fb9762003-03-23 01:06:05 +00001133}
1134
1135long do_sigreturn(CPUX86State *env)
1136{
bellard579a97f2007-11-11 14:26:47 +00001137 struct sigframe *frame;
1138 abi_ulong frame_addr = env->regs[R_ESP] - 8;
Anthony Liguoric227f092009-10-01 16:12:16 -05001139 target_sigset_t target_set;
bellard66fb9762003-03-23 01:06:05 +00001140 sigset_t set;
Timothy E Baldwin0284b032016-05-12 18:47:30 +01001141 int i;
bellard66fb9762003-03-23 01:06:05 +00001142
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01001143 trace_user_do_sigreturn(env, frame_addr);
bellard579a97f2007-11-11 14:26:47 +00001144 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
1145 goto badframe;
bellard66fb9762003-03-23 01:06:05 +00001146 /* set blocked signals */
Riku Voipiof5f601a2014-04-23 13:00:17 +03001147 __get_user(target_set.sig[0], &frame->sc.oldmask);
bellard92319442004-06-19 16:58:13 +00001148 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
Riku Voipiof5f601a2014-04-23 13:00:17 +03001149 __get_user(target_set.sig[i], &frame->extramask[i - 1]);
bellard92319442004-06-19 16:58:13 +00001150 }
bellard66fb9762003-03-23 01:06:05 +00001151
bellard92319442004-06-19 16:58:13 +00001152 target_to_host_sigset_internal(&set, &target_set);
Peter Maydell9eede5b2016-05-27 15:51:46 +01001153 set_sigmask(&set);
ths3b46e622007-09-17 08:09:54 +00001154
bellard66fb9762003-03-23 01:06:05 +00001155 /* restore registers */
Timothy E Baldwin0284b032016-05-12 18:47:30 +01001156 if (restore_sigcontext(env, &frame->sc))
bellard66fb9762003-03-23 01:06:05 +00001157 goto badframe;
bellard579a97f2007-11-11 14:26:47 +00001158 unlock_user_struct(frame, frame_addr, 0);
Timothy E Baldwin0284b032016-05-12 18:47:30 +01001159 return -TARGET_QEMU_ESIGRETURN;
bellard66fb9762003-03-23 01:06:05 +00001160
1161badframe:
bellard579a97f2007-11-11 14:26:47 +00001162 unlock_user_struct(frame, frame_addr, 0);
bellard66fb9762003-03-23 01:06:05 +00001163 force_sig(TARGET_SIGSEGV);
1164 return 0;
1165}
1166
1167long do_rt_sigreturn(CPUX86State *env)
1168{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001169 abi_ulong frame_addr;
1170 struct rt_sigframe *frame;
1171 sigset_t set;
bellard66fb9762003-03-23 01:06:05 +00001172
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001173 frame_addr = env->regs[R_ESP] - 4;
1174 trace_user_do_rt_sigreturn(env, frame_addr);
1175 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
1176 goto badframe;
1177 target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
Peter Maydell9eede5b2016-05-27 15:51:46 +01001178 set_sigmask(&set);
ths5fafdf22007-09-16 21:08:06 +00001179
Timothy E Baldwin0284b032016-05-12 18:47:30 +01001180 if (restore_sigcontext(env, &frame->uc.tuc_mcontext)) {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001181 goto badframe;
1182 }
bellard66fb9762003-03-23 01:06:05 +00001183
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001184 if (do_sigaltstack(frame_addr + offsetof(struct rt_sigframe, uc.tuc_stack), 0,
1185 get_sp_from_cpustate(env)) == -EFAULT) {
1186 goto badframe;
1187 }
thsa04e1342007-09-27 13:57:58 +00001188
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001189 unlock_user_struct(frame, frame_addr, 0);
Timothy E Baldwin0284b032016-05-12 18:47:30 +01001190 return -TARGET_QEMU_ESIGRETURN;
bellard66fb9762003-03-23 01:06:05 +00001191
1192badframe:
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001193 unlock_user_struct(frame, frame_addr, 0);
1194 force_sig(TARGET_SIGSEGV);
1195 return 0;
bellard66fb9762003-03-23 01:06:05 +00001196}
1197
Andreas Schwab1744aea2013-09-03 20:12:16 +01001198#elif defined(TARGET_AARCH64)
1199
1200struct target_sigcontext {
1201 uint64_t fault_address;
1202 /* AArch64 registers */
1203 uint64_t regs[31];
1204 uint64_t sp;
1205 uint64_t pc;
1206 uint64_t pstate;
1207 /* 4K reserved for FP/SIMD state and future expansion */
1208 char __reserved[4096] __attribute__((__aligned__(16)));
1209};
1210
1211struct target_ucontext {
1212 abi_ulong tuc_flags;
1213 abi_ulong tuc_link;
1214 target_stack_t tuc_stack;
1215 target_sigset_t tuc_sigmask;
1216 /* glibc uses a 1024-bit sigset_t */
1217 char __unused[1024 / 8 - sizeof(target_sigset_t)];
1218 /* last for future expansion */
1219 struct target_sigcontext tuc_mcontext;
1220};
1221
1222/*
1223 * Header to be used at the beginning of structures extending the user
1224 * context. Such structures must be placed after the rt_sigframe on the stack
1225 * and be 16-byte aligned. The last structure must be a dummy one with the
1226 * magic and size set to 0.
1227 */
1228struct target_aarch64_ctx {
1229 uint32_t magic;
1230 uint32_t size;
1231};
1232
1233#define TARGET_FPSIMD_MAGIC 0x46508001
1234
1235struct target_fpsimd_context {
1236 struct target_aarch64_ctx head;
1237 uint32_t fpsr;
1238 uint32_t fpcr;
1239 uint64_t vregs[32 * 2]; /* really uint128_t vregs[32] */
1240};
1241
1242/*
1243 * Auxiliary context saved in the sigcontext.__reserved array. Not exported to
1244 * user space as it will change with the addition of new context. User space
1245 * should check the magic/size information.
1246 */
1247struct target_aux_context {
1248 struct target_fpsimd_context fpsimd;
1249 /* additional context to be added before "end" */
1250 struct target_aarch64_ctx end;
1251};
1252
1253struct target_rt_sigframe {
1254 struct target_siginfo info;
1255 struct target_ucontext uc;
1256 uint64_t fp;
1257 uint64_t lr;
1258 uint32_t tramp[2];
1259};
1260
1261static int target_setup_sigframe(struct target_rt_sigframe *sf,
1262 CPUARMState *env, target_sigset_t *set)
1263{
1264 int i;
1265 struct target_aux_context *aux =
1266 (struct target_aux_context *)sf->uc.tuc_mcontext.__reserved;
1267
1268 /* set up the stack frame for unwinding */
1269 __put_user(env->xregs[29], &sf->fp);
1270 __put_user(env->xregs[30], &sf->lr);
1271
1272 for (i = 0; i < 31; i++) {
1273 __put_user(env->xregs[i], &sf->uc.tuc_mcontext.regs[i]);
1274 }
1275 __put_user(env->xregs[31], &sf->uc.tuc_mcontext.sp);
1276 __put_user(env->pc, &sf->uc.tuc_mcontext.pc);
Peter Maydelld3563122013-12-17 19:42:30 +00001277 __put_user(pstate_read(env), &sf->uc.tuc_mcontext.pstate);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001278
Peter Maydell7af03922014-05-01 18:36:17 +01001279 __put_user(env->exception.vaddress, &sf->uc.tuc_mcontext.fault_address);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001280
1281 for (i = 0; i < TARGET_NSIG_WORDS; i++) {
1282 __put_user(set->sig[i], &sf->uc.tuc_sigmask.sig[i]);
1283 }
1284
1285 for (i = 0; i < 32; i++) {
1286#ifdef TARGET_WORDS_BIGENDIAN
1287 __put_user(env->vfp.regs[i * 2], &aux->fpsimd.vregs[i * 2 + 1]);
1288 __put_user(env->vfp.regs[i * 2 + 1], &aux->fpsimd.vregs[i * 2]);
1289#else
1290 __put_user(env->vfp.regs[i * 2], &aux->fpsimd.vregs[i * 2]);
1291 __put_user(env->vfp.regs[i * 2 + 1], &aux->fpsimd.vregs[i * 2 + 1]);
1292#endif
1293 }
Will Newtone0ee1382014-01-04 22:15:48 +00001294 __put_user(vfp_get_fpsr(env), &aux->fpsimd.fpsr);
1295 __put_user(vfp_get_fpcr(env), &aux->fpsimd.fpcr);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001296 __put_user(TARGET_FPSIMD_MAGIC, &aux->fpsimd.head.magic);
1297 __put_user(sizeof(struct target_fpsimd_context),
1298 &aux->fpsimd.head.size);
1299
1300 /* set the "end" magic */
1301 __put_user(0, &aux->end.magic);
1302 __put_user(0, &aux->end.size);
1303
1304 return 0;
1305}
1306
1307static int target_restore_sigframe(CPUARMState *env,
1308 struct target_rt_sigframe *sf)
1309{
1310 sigset_t set;
1311 int i;
1312 struct target_aux_context *aux =
1313 (struct target_aux_context *)sf->uc.tuc_mcontext.__reserved;
Will Newtone0ee1382014-01-04 22:15:48 +00001314 uint32_t magic, size, fpsr, fpcr;
Peter Maydelld3563122013-12-17 19:42:30 +00001315 uint64_t pstate;
Andreas Schwab1744aea2013-09-03 20:12:16 +01001316
1317 target_to_host_sigset(&set, &sf->uc.tuc_sigmask);
Peter Maydell9eede5b2016-05-27 15:51:46 +01001318 set_sigmask(&set);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001319
1320 for (i = 0; i < 31; i++) {
1321 __get_user(env->xregs[i], &sf->uc.tuc_mcontext.regs[i]);
1322 }
1323
1324 __get_user(env->xregs[31], &sf->uc.tuc_mcontext.sp);
1325 __get_user(env->pc, &sf->uc.tuc_mcontext.pc);
Peter Maydelld3563122013-12-17 19:42:30 +00001326 __get_user(pstate, &sf->uc.tuc_mcontext.pstate);
1327 pstate_write(env, pstate);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001328
1329 __get_user(magic, &aux->fpsimd.head.magic);
1330 __get_user(size, &aux->fpsimd.head.size);
1331
1332 if (magic != TARGET_FPSIMD_MAGIC
1333 || size != sizeof(struct target_fpsimd_context)) {
1334 return 1;
1335 }
1336
Peter Maydell4cf23482014-03-02 19:36:38 +00001337 for (i = 0; i < 32; i++) {
1338#ifdef TARGET_WORDS_BIGENDIAN
1339 __get_user(env->vfp.regs[i * 2], &aux->fpsimd.vregs[i * 2 + 1]);
1340 __get_user(env->vfp.regs[i * 2 + 1], &aux->fpsimd.vregs[i * 2]);
1341#else
1342 __get_user(env->vfp.regs[i * 2], &aux->fpsimd.vregs[i * 2]);
1343 __get_user(env->vfp.regs[i * 2 + 1], &aux->fpsimd.vregs[i * 2 + 1]);
1344#endif
Andreas Schwab1744aea2013-09-03 20:12:16 +01001345 }
Will Newtone0ee1382014-01-04 22:15:48 +00001346 __get_user(fpsr, &aux->fpsimd.fpsr);
1347 vfp_set_fpsr(env, fpsr);
1348 __get_user(fpcr, &aux->fpsimd.fpcr);
1349 vfp_set_fpcr(env, fpcr);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001350
1351 return 0;
1352}
1353
1354static abi_ulong get_sigframe(struct target_sigaction *ka, CPUARMState *env)
1355{
1356 abi_ulong sp;
1357
1358 sp = env->xregs[31];
1359
1360 /*
1361 * This is the X/Open sanctioned signal stack switching.
1362 */
Riku Voipiob545f632014-07-15 17:01:55 +03001363 if ((ka->sa_flags & TARGET_SA_ONSTACK) && !sas_ss_flags(sp)) {
Andreas Schwab1744aea2013-09-03 20:12:16 +01001364 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
1365 }
1366
1367 sp = (sp - sizeof(struct target_rt_sigframe)) & ~15;
1368
1369 return sp;
1370}
1371
1372static void target_setup_frame(int usig, struct target_sigaction *ka,
1373 target_siginfo_t *info, target_sigset_t *set,
1374 CPUARMState *env)
1375{
1376 struct target_rt_sigframe *frame;
Michael Matz8a3ae912014-03-02 19:36:39 +00001377 abi_ulong frame_addr, return_addr;
Andreas Schwab1744aea2013-09-03 20:12:16 +01001378
1379 frame_addr = get_sigframe(ka, env);
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01001380 trace_user_setup_frame(env, frame_addr);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001381 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
1382 goto give_sigsegv;
1383 }
1384
1385 __put_user(0, &frame->uc.tuc_flags);
1386 __put_user(0, &frame->uc.tuc_link);
1387
1388 __put_user(target_sigaltstack_used.ss_sp,
1389 &frame->uc.tuc_stack.ss_sp);
1390 __put_user(sas_ss_flags(env->xregs[31]),
1391 &frame->uc.tuc_stack.ss_flags);
1392 __put_user(target_sigaltstack_used.ss_size,
1393 &frame->uc.tuc_stack.ss_size);
1394 target_setup_sigframe(frame, env, set);
Michael Matz8a3ae912014-03-02 19:36:39 +00001395 if (ka->sa_flags & TARGET_SA_RESTORER) {
1396 return_addr = ka->sa_restorer;
1397 } else {
1398 /* mov x8,#__NR_rt_sigreturn; svc #0 */
1399 __put_user(0xd2801168, &frame->tramp[0]);
1400 __put_user(0xd4000001, &frame->tramp[1]);
1401 return_addr = frame_addr + offsetof(struct target_rt_sigframe, tramp);
1402 }
Andreas Schwab1744aea2013-09-03 20:12:16 +01001403 env->xregs[0] = usig;
1404 env->xregs[31] = frame_addr;
1405 env->xregs[29] = env->xregs[31] + offsetof(struct target_rt_sigframe, fp);
1406 env->pc = ka->_sa_handler;
Michael Matz8a3ae912014-03-02 19:36:39 +00001407 env->xregs[30] = return_addr;
Andreas Schwab1744aea2013-09-03 20:12:16 +01001408 if (info) {
Peter Maydellf6c7a052015-01-08 12:19:48 +00001409 tswap_siginfo(&frame->info, info);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001410 env->xregs[1] = frame_addr + offsetof(struct target_rt_sigframe, info);
1411 env->xregs[2] = frame_addr + offsetof(struct target_rt_sigframe, uc);
1412 }
1413
1414 unlock_user_struct(frame, frame_addr, 1);
1415 return;
1416
1417 give_sigsegv:
1418 unlock_user_struct(frame, frame_addr, 1);
1419 force_sig(TARGET_SIGSEGV);
1420}
1421
1422static void setup_rt_frame(int sig, struct target_sigaction *ka,
1423 target_siginfo_t *info, target_sigset_t *set,
1424 CPUARMState *env)
1425{
1426 target_setup_frame(sig, ka, info, set, env);
1427}
1428
1429static void setup_frame(int sig, struct target_sigaction *ka,
1430 target_sigset_t *set, CPUARMState *env)
1431{
1432 target_setup_frame(sig, ka, 0, set, env);
1433}
1434
1435long do_rt_sigreturn(CPUARMState *env)
1436{
Peter Maydell7f72cd22014-03-12 13:06:00 +00001437 struct target_rt_sigframe *frame = NULL;
Andreas Schwab1744aea2013-09-03 20:12:16 +01001438 abi_ulong frame_addr = env->xregs[31];
1439
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01001440 trace_user_do_rt_sigreturn(env, frame_addr);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001441 if (frame_addr & 15) {
1442 goto badframe;
1443 }
1444
1445 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
1446 goto badframe;
1447 }
1448
1449 if (target_restore_sigframe(env, frame)) {
1450 goto badframe;
1451 }
1452
1453 if (do_sigaltstack(frame_addr +
1454 offsetof(struct target_rt_sigframe, uc.tuc_stack),
1455 0, get_sp_from_cpustate(env)) == -EFAULT) {
1456 goto badframe;
1457 }
1458
1459 unlock_user_struct(frame, frame_addr, 0);
Timothy E Baldwinf0267ef2016-05-12 18:47:31 +01001460 return -TARGET_QEMU_ESIGRETURN;
Andreas Schwab1744aea2013-09-03 20:12:16 +01001461
1462 badframe:
1463 unlock_user_struct(frame, frame_addr, 0);
1464 force_sig(TARGET_SIGSEGV);
1465 return 0;
1466}
1467
1468long do_sigreturn(CPUARMState *env)
1469{
1470 return do_rt_sigreturn(env);
1471}
1472
bellard43fff232003-07-09 19:31:39 +00001473#elif defined(TARGET_ARM)
1474
1475struct target_sigcontext {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001476 abi_ulong trap_no;
1477 abi_ulong error_code;
1478 abi_ulong oldmask;
1479 abi_ulong arm_r0;
1480 abi_ulong arm_r1;
1481 abi_ulong arm_r2;
1482 abi_ulong arm_r3;
1483 abi_ulong arm_r4;
1484 abi_ulong arm_r5;
1485 abi_ulong arm_r6;
1486 abi_ulong arm_r7;
1487 abi_ulong arm_r8;
1488 abi_ulong arm_r9;
1489 abi_ulong arm_r10;
1490 abi_ulong arm_fp;
1491 abi_ulong arm_ip;
1492 abi_ulong arm_sp;
1493 abi_ulong arm_lr;
1494 abi_ulong arm_pc;
1495 abi_ulong arm_cpsr;
1496 abi_ulong fault_address;
bellard43fff232003-07-09 19:31:39 +00001497};
1498
pbrooka745ec62008-05-06 15:36:17 +00001499struct target_ucontext_v1 {
blueswir1992f48a2007-10-14 16:27:31 +00001500 abi_ulong tuc_flags;
1501 abi_ulong tuc_link;
Anthony Liguoric227f092009-10-01 16:12:16 -05001502 target_stack_t tuc_stack;
bellardb8076a72005-04-07 22:20:31 +00001503 struct target_sigcontext tuc_mcontext;
Anthony Liguoric227f092009-10-01 16:12:16 -05001504 target_sigset_t tuc_sigmask; /* mask last for extensibility */
bellard43fff232003-07-09 19:31:39 +00001505};
1506
pbrooka745ec62008-05-06 15:36:17 +00001507struct target_ucontext_v2 {
1508 abi_ulong tuc_flags;
1509 abi_ulong tuc_link;
Anthony Liguoric227f092009-10-01 16:12:16 -05001510 target_stack_t tuc_stack;
pbrooka745ec62008-05-06 15:36:17 +00001511 struct target_sigcontext tuc_mcontext;
Anthony Liguoric227f092009-10-01 16:12:16 -05001512 target_sigset_t tuc_sigmask; /* mask last for extensibility */
Peter Maydell5f0b7c82010-11-24 15:20:03 +00001513 char __unused[128 - sizeof(target_sigset_t)];
pbrooka745ec62008-05-06 15:36:17 +00001514 abi_ulong tuc_regspace[128] __attribute__((__aligned__(8)));
1515};
1516
Peter Maydell0d871bd2010-11-24 15:20:05 +00001517struct target_user_vfp {
1518 uint64_t fpregs[32];
1519 abi_ulong fpscr;
1520};
1521
1522struct target_user_vfp_exc {
1523 abi_ulong fpexc;
1524 abi_ulong fpinst;
1525 abi_ulong fpinst2;
1526};
1527
1528struct target_vfp_sigframe {
1529 abi_ulong magic;
1530 abi_ulong size;
1531 struct target_user_vfp ufp;
1532 struct target_user_vfp_exc ufp_exc;
1533} __attribute__((__aligned__(8)));
1534
Peter Maydell08e11252010-11-24 15:20:07 +00001535struct target_iwmmxt_sigframe {
1536 abi_ulong magic;
1537 abi_ulong size;
1538 uint64_t regs[16];
1539 /* Note that not all the coprocessor control registers are stored here */
1540 uint32_t wcssf;
1541 uint32_t wcasf;
1542 uint32_t wcgr0;
1543 uint32_t wcgr1;
1544 uint32_t wcgr2;
1545 uint32_t wcgr3;
1546} __attribute__((__aligned__(8)));
1547
Peter Maydell0d871bd2010-11-24 15:20:05 +00001548#define TARGET_VFP_MAGIC 0x56465001
Peter Maydell08e11252010-11-24 15:20:07 +00001549#define TARGET_IWMMXT_MAGIC 0x12ef842a
Peter Maydell0d871bd2010-11-24 15:20:05 +00001550
pbrooka8c33202008-05-07 23:22:46 +00001551struct sigframe_v1
bellard43fff232003-07-09 19:31:39 +00001552{
1553 struct target_sigcontext sc;
blueswir1992f48a2007-10-14 16:27:31 +00001554 abi_ulong extramask[TARGET_NSIG_WORDS-1];
1555 abi_ulong retcode;
bellard43fff232003-07-09 19:31:39 +00001556};
1557
pbrooka8c33202008-05-07 23:22:46 +00001558struct sigframe_v2
1559{
1560 struct target_ucontext_v2 uc;
1561 abi_ulong retcode;
1562};
1563
pbrooka745ec62008-05-06 15:36:17 +00001564struct rt_sigframe_v1
bellard43fff232003-07-09 19:31:39 +00001565{
bellardf8b0aa22007-11-11 23:03:42 +00001566 abi_ulong pinfo;
1567 abi_ulong puc;
bellard43fff232003-07-09 19:31:39 +00001568 struct target_siginfo info;
pbrooka745ec62008-05-06 15:36:17 +00001569 struct target_ucontext_v1 uc;
1570 abi_ulong retcode;
1571};
1572
1573struct rt_sigframe_v2
1574{
1575 struct target_siginfo info;
1576 struct target_ucontext_v2 uc;
blueswir1992f48a2007-10-14 16:27:31 +00001577 abi_ulong retcode;
bellard43fff232003-07-09 19:31:39 +00001578};
1579
1580#define TARGET_CONFIG_CPU_32 1
1581
1582/*
1583 * For ARM syscalls, we encode the syscall number into the instruction.
1584 */
1585#define SWI_SYS_SIGRETURN (0xef000000|(TARGET_NR_sigreturn + ARM_SYSCALL_BASE))
1586#define SWI_SYS_RT_SIGRETURN (0xef000000|(TARGET_NR_rt_sigreturn + ARM_SYSCALL_BASE))
1587
1588/*
1589 * For Thumb syscalls, we pass the syscall number via r7. We therefore
1590 * need two 16-bit instructions.
1591 */
1592#define SWI_THUMB_SIGRETURN (0xdf00 << 16 | 0x2700 | (TARGET_NR_sigreturn))
1593#define SWI_THUMB_RT_SIGRETURN (0xdf00 << 16 | 0x2700 | (TARGET_NR_rt_sigreturn))
1594
blueswir1992f48a2007-10-14 16:27:31 +00001595static const abi_ulong retcodes[4] = {
bellard43fff232003-07-09 19:31:39 +00001596 SWI_SYS_SIGRETURN, SWI_THUMB_SIGRETURN,
1597 SWI_SYS_RT_SIGRETURN, SWI_THUMB_RT_SIGRETURN
1598};
1599
1600
Andreas Färber05390242012-02-25 03:37:53 +01001601static inline int valid_user_regs(CPUARMState *regs)
bellard43fff232003-07-09 19:31:39 +00001602{
1603 return 1;
1604}
1605
pbrooka8c33202008-05-07 23:22:46 +00001606static void
bellard43fff232003-07-09 19:31:39 +00001607setup_sigcontext(struct target_sigcontext *sc, /*struct _fpstate *fpstate,*/
Andreas Färber05390242012-02-25 03:37:53 +01001608 CPUARMState *env, abi_ulong mask)
bellard43fff232003-07-09 19:31:39 +00001609{
Paolo Bonzinia0e1e6d2016-03-04 11:30:18 +00001610 __put_user(env->regs[0], &sc->arm_r0);
1611 __put_user(env->regs[1], &sc->arm_r1);
1612 __put_user(env->regs[2], &sc->arm_r2);
1613 __put_user(env->regs[3], &sc->arm_r3);
1614 __put_user(env->regs[4], &sc->arm_r4);
1615 __put_user(env->regs[5], &sc->arm_r5);
1616 __put_user(env->regs[6], &sc->arm_r6);
1617 __put_user(env->regs[7], &sc->arm_r7);
1618 __put_user(env->regs[8], &sc->arm_r8);
1619 __put_user(env->regs[9], &sc->arm_r9);
1620 __put_user(env->regs[10], &sc->arm_r10);
1621 __put_user(env->regs[11], &sc->arm_fp);
1622 __put_user(env->regs[12], &sc->arm_ip);
1623 __put_user(env->regs[13], &sc->arm_sp);
1624 __put_user(env->regs[14], &sc->arm_lr);
1625 __put_user(env->regs[15], &sc->arm_pc);
bellard43fff232003-07-09 19:31:39 +00001626#ifdef TARGET_CONFIG_CPU_32
Paolo Bonzinia0e1e6d2016-03-04 11:30:18 +00001627 __put_user(cpsr_read(env), &sc->arm_cpsr);
bellard43fff232003-07-09 19:31:39 +00001628#endif
1629
Paolo Bonzinia0e1e6d2016-03-04 11:30:18 +00001630 __put_user(/* current->thread.trap_no */ 0, &sc->trap_no);
1631 __put_user(/* current->thread.error_code */ 0, &sc->error_code);
1632 __put_user(/* current->thread.address */ 0, &sc->fault_address);
1633 __put_user(mask, &sc->oldmask);
bellard43fff232003-07-09 19:31:39 +00001634}
1635
bellard579a97f2007-11-11 14:26:47 +00001636static inline abi_ulong
Andreas Färber05390242012-02-25 03:37:53 +01001637get_sigframe(struct target_sigaction *ka, CPUARMState *regs, int framesize)
bellard43fff232003-07-09 19:31:39 +00001638{
Paolo Bonzinia0e1e6d2016-03-04 11:30:18 +00001639 unsigned long sp = regs->regs[13];
bellard43fff232003-07-09 19:31:39 +00001640
Paolo Bonzinia0e1e6d2016-03-04 11:30:18 +00001641 /*
1642 * This is the X/Open sanctioned signal stack switching.
1643 */
1644 if ((ka->sa_flags & TARGET_SA_ONSTACK) && !sas_ss_flags(sp)) {
1645 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
1646 }
1647 /*
1648 * ATPCS B01 mandates 8-byte alignment
1649 */
1650 return (sp - framesize) & ~7;
bellard43fff232003-07-09 19:31:39 +00001651}
1652
Riku Voipio0188fad2014-04-23 13:34:15 +03001653static void
Andreas Färber05390242012-02-25 03:37:53 +01001654setup_return(CPUARMState *env, struct target_sigaction *ka,
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001655 abi_ulong *rc, abi_ulong frame_addr, int usig, abi_ulong rc_addr)
bellard43fff232003-07-09 19:31:39 +00001656{
Paolo Bonzinia0e1e6d2016-03-04 11:30:18 +00001657 abi_ulong handler = ka->_sa_handler;
1658 abi_ulong retcode;
1659 int thumb = handler & 1;
1660 uint32_t cpsr = cpsr_read(env);
Peter Maydell964413d2011-01-14 20:39:19 +01001661
Paolo Bonzinia0e1e6d2016-03-04 11:30:18 +00001662 cpsr &= ~CPSR_IT;
1663 if (thumb) {
1664 cpsr |= CPSR_T;
1665 } else {
1666 cpsr &= ~CPSR_T;
1667 }
bellard43fff232003-07-09 19:31:39 +00001668
Paolo Bonzinia0e1e6d2016-03-04 11:30:18 +00001669 if (ka->sa_flags & TARGET_SA_RESTORER) {
1670 retcode = ka->sa_restorer;
1671 } else {
1672 unsigned int idx = thumb;
bellard43fff232003-07-09 19:31:39 +00001673
Paolo Bonzinia0e1e6d2016-03-04 11:30:18 +00001674 if (ka->sa_flags & TARGET_SA_SIGINFO) {
1675 idx += 2;
1676 }
bellard43fff232003-07-09 19:31:39 +00001677
Riku Voipio0188fad2014-04-23 13:34:15 +03001678 __put_user(retcodes[idx], rc);
Stefan Weilca8a2772011-10-03 22:43:19 +02001679
Paolo Bonzinia0e1e6d2016-03-04 11:30:18 +00001680 retcode = rc_addr + thumb;
1681 }
bellard43fff232003-07-09 19:31:39 +00001682
Paolo Bonzinia0e1e6d2016-03-04 11:30:18 +00001683 env->regs[0] = usig;
1684 env->regs[13] = frame_addr;
1685 env->regs[14] = retcode;
1686 env->regs[15] = handler & (thumb ? ~1 : ~3);
1687 cpsr_write(env, cpsr, CPSR_IT | CPSR_T, CPSRWriteByInstr);
bellard43fff232003-07-09 19:31:39 +00001688}
1689
Andreas Färber05390242012-02-25 03:37:53 +01001690static abi_ulong *setup_sigframe_v2_vfp(abi_ulong *regspace, CPUARMState *env)
Peter Maydell0d871bd2010-11-24 15:20:05 +00001691{
1692 int i;
1693 struct target_vfp_sigframe *vfpframe;
1694 vfpframe = (struct target_vfp_sigframe *)regspace;
1695 __put_user(TARGET_VFP_MAGIC, &vfpframe->magic);
1696 __put_user(sizeof(*vfpframe), &vfpframe->size);
1697 for (i = 0; i < 32; i++) {
Peter Maydell005e1a02011-02-10 13:59:35 +00001698 __put_user(float64_val(env->vfp.regs[i]), &vfpframe->ufp.fpregs[i]);
Peter Maydell0d871bd2010-11-24 15:20:05 +00001699 }
1700 __put_user(vfp_get_fpscr(env), &vfpframe->ufp.fpscr);
1701 __put_user(env->vfp.xregs[ARM_VFP_FPEXC], &vfpframe->ufp_exc.fpexc);
1702 __put_user(env->vfp.xregs[ARM_VFP_FPINST], &vfpframe->ufp_exc.fpinst);
1703 __put_user(env->vfp.xregs[ARM_VFP_FPINST2], &vfpframe->ufp_exc.fpinst2);
1704 return (abi_ulong*)(vfpframe+1);
1705}
1706
Andreas Färber05390242012-02-25 03:37:53 +01001707static abi_ulong *setup_sigframe_v2_iwmmxt(abi_ulong *regspace,
1708 CPUARMState *env)
Peter Maydell08e11252010-11-24 15:20:07 +00001709{
1710 int i;
1711 struct target_iwmmxt_sigframe *iwmmxtframe;
1712 iwmmxtframe = (struct target_iwmmxt_sigframe *)regspace;
1713 __put_user(TARGET_IWMMXT_MAGIC, &iwmmxtframe->magic);
1714 __put_user(sizeof(*iwmmxtframe), &iwmmxtframe->size);
1715 for (i = 0; i < 16; i++) {
1716 __put_user(env->iwmmxt.regs[i], &iwmmxtframe->regs[i]);
1717 }
1718 __put_user(env->vfp.xregs[ARM_IWMMXT_wCSSF], &iwmmxtframe->wcssf);
1719 __put_user(env->vfp.xregs[ARM_IWMMXT_wCASF], &iwmmxtframe->wcssf);
1720 __put_user(env->vfp.xregs[ARM_IWMMXT_wCGR0], &iwmmxtframe->wcgr0);
1721 __put_user(env->vfp.xregs[ARM_IWMMXT_wCGR1], &iwmmxtframe->wcgr1);
1722 __put_user(env->vfp.xregs[ARM_IWMMXT_wCGR2], &iwmmxtframe->wcgr2);
1723 __put_user(env->vfp.xregs[ARM_IWMMXT_wCGR3], &iwmmxtframe->wcgr3);
1724 return (abi_ulong*)(iwmmxtframe+1);
1725}
1726
pbrooka8c33202008-05-07 23:22:46 +00001727static void setup_sigframe_v2(struct target_ucontext_v2 *uc,
Andreas Färber05390242012-02-25 03:37:53 +01001728 target_sigset_t *set, CPUARMState *env)
bellard43fff232003-07-09 19:31:39 +00001729{
pbrooka8c33202008-05-07 23:22:46 +00001730 struct target_sigaltstack stack;
1731 int i;
Peter Maydell0d871bd2010-11-24 15:20:05 +00001732 abi_ulong *regspace;
pbrooka8c33202008-05-07 23:22:46 +00001733
1734 /* Clear all the bits of the ucontext we don't use. */
1735 memset(uc, 0, offsetof(struct target_ucontext_v2, tuc_mcontext));
1736
1737 memset(&stack, 0, sizeof(stack));
1738 __put_user(target_sigaltstack_used.ss_sp, &stack.ss_sp);
1739 __put_user(target_sigaltstack_used.ss_size, &stack.ss_size);
1740 __put_user(sas_ss_flags(get_sp_from_cpustate(env)), &stack.ss_flags);
1741 memcpy(&uc->tuc_stack, &stack, sizeof(stack));
1742
1743 setup_sigcontext(&uc->tuc_mcontext, env, set->sig[0]);
Peter Maydell0d871bd2010-11-24 15:20:05 +00001744 /* Save coprocessor signal frame. */
1745 regspace = uc->tuc_regspace;
1746 if (arm_feature(env, ARM_FEATURE_VFP)) {
1747 regspace = setup_sigframe_v2_vfp(regspace, env);
1748 }
Peter Maydell08e11252010-11-24 15:20:07 +00001749 if (arm_feature(env, ARM_FEATURE_IWMMXT)) {
1750 regspace = setup_sigframe_v2_iwmmxt(regspace, env);
1751 }
1752
Peter Maydell0d871bd2010-11-24 15:20:05 +00001753 /* Write terminating magic word */
1754 __put_user(0, regspace);
1755
pbrooka8c33202008-05-07 23:22:46 +00001756 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
1757 __put_user(set->sig[i], &uc->tuc_sigmask.sig[i]);
1758 }
1759}
1760
1761/* compare linux/arch/arm/kernel/signal.c:setup_frame() */
pbrook624f7972008-05-31 16:11:38 +00001762static void setup_frame_v1(int usig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01001763 target_sigset_t *set, CPUARMState *regs)
pbrooka8c33202008-05-07 23:22:46 +00001764{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001765 struct sigframe_v1 *frame;
1766 abi_ulong frame_addr = get_sigframe(ka, regs, sizeof(*frame));
1767 int i;
bellard43fff232003-07-09 19:31:39 +00001768
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001769 trace_user_setup_frame(regs, frame_addr);
1770 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
1771 return;
1772 }
bellard579a97f2007-11-11 14:26:47 +00001773
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001774 setup_sigcontext(&frame->sc, regs, set->sig[0]);
bellard43fff232003-07-09 19:31:39 +00001775
Riku Voipio0188fad2014-04-23 13:34:15 +03001776 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
1777 __put_user(set->sig[i], &frame->extramask[i - 1]);
1778 }
bellard43fff232003-07-09 19:31:39 +00001779
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001780 setup_return(regs, ka, &frame->retcode, frame_addr, usig,
1781 frame_addr + offsetof(struct sigframe_v1, retcode));
bellard579a97f2007-11-11 14:26:47 +00001782
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001783 unlock_user_struct(frame, frame_addr, 1);
pbrooka8c33202008-05-07 23:22:46 +00001784}
1785
pbrook624f7972008-05-31 16:11:38 +00001786static void setup_frame_v2(int usig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01001787 target_sigset_t *set, CPUARMState *regs)
pbrooka8c33202008-05-07 23:22:46 +00001788{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001789 struct sigframe_v2 *frame;
1790 abi_ulong frame_addr = get_sigframe(ka, regs, sizeof(*frame));
pbrooka8c33202008-05-07 23:22:46 +00001791
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001792 trace_user_setup_frame(regs, frame_addr);
1793 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
1794 return;
1795 }
pbrooka8c33202008-05-07 23:22:46 +00001796
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001797 setup_sigframe_v2(&frame->uc, set, regs);
pbrooka8c33202008-05-07 23:22:46 +00001798
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001799 setup_return(regs, ka, &frame->retcode, frame_addr, usig,
1800 frame_addr + offsetof(struct sigframe_v2, retcode));
pbrooka8c33202008-05-07 23:22:46 +00001801
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001802 unlock_user_struct(frame, frame_addr, 1);
pbrooka8c33202008-05-07 23:22:46 +00001803}
1804
pbrook624f7972008-05-31 16:11:38 +00001805static void setup_frame(int usig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01001806 target_sigset_t *set, CPUARMState *regs)
pbrooka8c33202008-05-07 23:22:46 +00001807{
1808 if (get_osversion() >= 0x020612) {
1809 setup_frame_v2(usig, ka, set, regs);
1810 } else {
1811 setup_frame_v1(usig, ka, set, regs);
1812 }
bellard43fff232003-07-09 19:31:39 +00001813}
1814
bellard579a97f2007-11-11 14:26:47 +00001815/* compare linux/arch/arm/kernel/signal.c:setup_rt_frame() */
pbrook624f7972008-05-31 16:11:38 +00001816static void setup_rt_frame_v1(int usig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05001817 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01001818 target_sigset_t *set, CPUARMState *env)
bellard43fff232003-07-09 19:31:39 +00001819{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001820 struct rt_sigframe_v1 *frame;
1821 abi_ulong frame_addr = get_sigframe(ka, env, sizeof(*frame));
1822 struct target_sigaltstack stack;
1823 int i;
1824 abi_ulong info_addr, uc_addr;
bellard43fff232003-07-09 19:31:39 +00001825
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001826 trace_user_setup_rt_frame(env, frame_addr);
1827 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
1828 return /* 1 */;
1829 }
bellardedf779f2004-02-22 13:40:13 +00001830
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001831 info_addr = frame_addr + offsetof(struct rt_sigframe_v1, info);
1832 __put_user(info_addr, &frame->pinfo);
1833 uc_addr = frame_addr + offsetof(struct rt_sigframe_v1, uc);
1834 __put_user(uc_addr, &frame->puc);
1835 tswap_siginfo(&frame->info, info);
bellard43fff232003-07-09 19:31:39 +00001836
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001837 /* Clear all the bits of the ucontext we don't use. */
1838 memset(&frame->uc, 0, offsetof(struct target_ucontext_v1, tuc_mcontext));
bellard43fff232003-07-09 19:31:39 +00001839
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001840 memset(&stack, 0, sizeof(stack));
1841 __put_user(target_sigaltstack_used.ss_sp, &stack.ss_sp);
1842 __put_user(target_sigaltstack_used.ss_size, &stack.ss_size);
1843 __put_user(sas_ss_flags(get_sp_from_cpustate(env)), &stack.ss_flags);
1844 memcpy(&frame->uc.tuc_stack, &stack, sizeof(stack));
thsa04e1342007-09-27 13:57:58 +00001845
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001846 setup_sigcontext(&frame->uc.tuc_mcontext, env, set->sig[0]);
1847 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
1848 __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
1849 }
bellard43fff232003-07-09 19:31:39 +00001850
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001851 setup_return(env, ka, &frame->retcode, frame_addr, usig,
1852 frame_addr + offsetof(struct rt_sigframe_v1, retcode));
pbrooka745ec62008-05-06 15:36:17 +00001853
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001854 env->regs[1] = info_addr;
1855 env->regs[2] = uc_addr;
pbrooka745ec62008-05-06 15:36:17 +00001856
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001857 unlock_user_struct(frame, frame_addr, 1);
pbrooka745ec62008-05-06 15:36:17 +00001858}
1859
pbrook624f7972008-05-31 16:11:38 +00001860static void setup_rt_frame_v2(int usig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05001861 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01001862 target_sigset_t *set, CPUARMState *env)
pbrooka745ec62008-05-06 15:36:17 +00001863{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001864 struct rt_sigframe_v2 *frame;
1865 abi_ulong frame_addr = get_sigframe(ka, env, sizeof(*frame));
1866 abi_ulong info_addr, uc_addr;
pbrooka745ec62008-05-06 15:36:17 +00001867
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001868 trace_user_setup_rt_frame(env, frame_addr);
1869 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
1870 return /* 1 */;
1871 }
pbrooka745ec62008-05-06 15:36:17 +00001872
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001873 info_addr = frame_addr + offsetof(struct rt_sigframe_v2, info);
1874 uc_addr = frame_addr + offsetof(struct rt_sigframe_v2, uc);
1875 tswap_siginfo(&frame->info, info);
pbrooka745ec62008-05-06 15:36:17 +00001876
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001877 setup_sigframe_v2(&frame->uc, set, env);
pbrooka745ec62008-05-06 15:36:17 +00001878
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001879 setup_return(env, ka, &frame->retcode, frame_addr, usig,
1880 frame_addr + offsetof(struct rt_sigframe_v2, retcode));
pbrooka745ec62008-05-06 15:36:17 +00001881
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001882 env->regs[1] = info_addr;
1883 env->regs[2] = uc_addr;
pbrooka745ec62008-05-06 15:36:17 +00001884
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001885 unlock_user_struct(frame, frame_addr, 1);
bellard43fff232003-07-09 19:31:39 +00001886}
1887
pbrook624f7972008-05-31 16:11:38 +00001888static void setup_rt_frame(int usig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05001889 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01001890 target_sigset_t *set, CPUARMState *env)
pbrooka745ec62008-05-06 15:36:17 +00001891{
1892 if (get_osversion() >= 0x020612) {
1893 setup_rt_frame_v2(usig, ka, info, set, env);
1894 } else {
1895 setup_rt_frame_v1(usig, ka, info, set, env);
1896 }
1897}
1898
bellard43fff232003-07-09 19:31:39 +00001899static int
Andreas Färber05390242012-02-25 03:37:53 +01001900restore_sigcontext(CPUARMState *env, struct target_sigcontext *sc)
bellard43fff232003-07-09 19:31:39 +00001901{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001902 int err = 0;
1903 uint32_t cpsr;
bellard43fff232003-07-09 19:31:39 +00001904
Riku Voipio1d8b5122014-04-23 10:26:05 +03001905 __get_user(env->regs[0], &sc->arm_r0);
1906 __get_user(env->regs[1], &sc->arm_r1);
1907 __get_user(env->regs[2], &sc->arm_r2);
1908 __get_user(env->regs[3], &sc->arm_r3);
1909 __get_user(env->regs[4], &sc->arm_r4);
1910 __get_user(env->regs[5], &sc->arm_r5);
1911 __get_user(env->regs[6], &sc->arm_r6);
1912 __get_user(env->regs[7], &sc->arm_r7);
1913 __get_user(env->regs[8], &sc->arm_r8);
1914 __get_user(env->regs[9], &sc->arm_r9);
1915 __get_user(env->regs[10], &sc->arm_r10);
1916 __get_user(env->regs[11], &sc->arm_fp);
1917 __get_user(env->regs[12], &sc->arm_ip);
1918 __get_user(env->regs[13], &sc->arm_sp);
1919 __get_user(env->regs[14], &sc->arm_lr);
1920 __get_user(env->regs[15], &sc->arm_pc);
bellard43fff232003-07-09 19:31:39 +00001921#ifdef TARGET_CONFIG_CPU_32
Riku Voipio1d8b5122014-04-23 10:26:05 +03001922 __get_user(cpsr, &sc->arm_cpsr);
Peter Maydell50866ba2016-02-23 15:36:43 +00001923 cpsr_write(env, cpsr, CPSR_USER | CPSR_EXEC, CPSRWriteByInstr);
bellard43fff232003-07-09 19:31:39 +00001924#endif
1925
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001926 err |= !valid_user_regs(env);
bellard43fff232003-07-09 19:31:39 +00001927
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001928 return err;
bellard43fff232003-07-09 19:31:39 +00001929}
1930
Andreas Färber05390242012-02-25 03:37:53 +01001931static long do_sigreturn_v1(CPUARMState *env)
bellard43fff232003-07-09 19:31:39 +00001932{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001933 abi_ulong frame_addr;
1934 struct sigframe_v1 *frame = NULL;
1935 target_sigset_t set;
1936 sigset_t host_set;
1937 int i;
bellard43fff232003-07-09 19:31:39 +00001938
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001939 /*
1940 * Since we stacked the signal on a 64-bit boundary,
1941 * then 'sp' should be word aligned here. If it's
1942 * not, then the user is trying to mess with us.
1943 */
1944 frame_addr = env->regs[13];
1945 trace_user_do_sigreturn(env, frame_addr);
1946 if (frame_addr & 7) {
1947 goto badframe;
1948 }
Peter Maydell978fae92013-07-29 12:00:32 +01001949
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001950 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
1951 goto badframe;
1952 }
bellard43fff232003-07-09 19:31:39 +00001953
Riku Voipiof5f601a2014-04-23 13:00:17 +03001954 __get_user(set.sig[0], &frame->sc.oldmask);
1955 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
1956 __get_user(set.sig[i], &frame->extramask[i - 1]);
1957 }
bellard43fff232003-07-09 19:31:39 +00001958
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001959 target_to_host_sigset_internal(&host_set, &set);
Peter Maydell9eede5b2016-05-27 15:51:46 +01001960 set_sigmask(&host_set);
bellard43fff232003-07-09 19:31:39 +00001961
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001962 if (restore_sigcontext(env, &frame->sc)) {
1963 goto badframe;
1964 }
bellard43fff232003-07-09 19:31:39 +00001965
1966#if 0
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001967 /* Send SIGTRAP if we're single-stepping */
1968 if (ptrace_cancel_bpt(current))
1969 send_sig(SIGTRAP, current, 1);
bellard43fff232003-07-09 19:31:39 +00001970#endif
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001971 unlock_user_struct(frame, frame_addr, 0);
Timothy E Baldwinf0267ef2016-05-12 18:47:31 +01001972 return -TARGET_QEMU_ESIGRETURN;
bellard43fff232003-07-09 19:31:39 +00001973
1974badframe:
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001975 force_sig(TARGET_SIGSEGV /* , current */);
1976 return 0;
bellard43fff232003-07-09 19:31:39 +00001977}
1978
Andreas Färber05390242012-02-25 03:37:53 +01001979static abi_ulong *restore_sigframe_v2_vfp(CPUARMState *env, abi_ulong *regspace)
Peter Maydell5f9099d2010-11-24 15:20:06 +00001980{
1981 int i;
1982 abi_ulong magic, sz;
1983 uint32_t fpscr, fpexc;
1984 struct target_vfp_sigframe *vfpframe;
1985 vfpframe = (struct target_vfp_sigframe *)regspace;
1986
1987 __get_user(magic, &vfpframe->magic);
1988 __get_user(sz, &vfpframe->size);
1989 if (magic != TARGET_VFP_MAGIC || sz != sizeof(*vfpframe)) {
1990 return 0;
1991 }
1992 for (i = 0; i < 32; i++) {
Peter Maydell005e1a02011-02-10 13:59:35 +00001993 __get_user(float64_val(env->vfp.regs[i]), &vfpframe->ufp.fpregs[i]);
Peter Maydell5f9099d2010-11-24 15:20:06 +00001994 }
1995 __get_user(fpscr, &vfpframe->ufp.fpscr);
1996 vfp_set_fpscr(env, fpscr);
1997 __get_user(fpexc, &vfpframe->ufp_exc.fpexc);
1998 /* Sanitise FPEXC: ensure VFP is enabled, FPINST2 is invalid
1999 * and the exception flag is cleared
2000 */
2001 fpexc |= (1 << 30);
2002 fpexc &= ~((1 << 31) | (1 << 28));
2003 env->vfp.xregs[ARM_VFP_FPEXC] = fpexc;
2004 __get_user(env->vfp.xregs[ARM_VFP_FPINST], &vfpframe->ufp_exc.fpinst);
2005 __get_user(env->vfp.xregs[ARM_VFP_FPINST2], &vfpframe->ufp_exc.fpinst2);
2006 return (abi_ulong*)(vfpframe + 1);
2007}
2008
Andreas Färber05390242012-02-25 03:37:53 +01002009static abi_ulong *restore_sigframe_v2_iwmmxt(CPUARMState *env,
2010 abi_ulong *regspace)
Peter Maydella59d69d2010-11-24 15:20:08 +00002011{
2012 int i;
2013 abi_ulong magic, sz;
2014 struct target_iwmmxt_sigframe *iwmmxtframe;
2015 iwmmxtframe = (struct target_iwmmxt_sigframe *)regspace;
2016
2017 __get_user(magic, &iwmmxtframe->magic);
2018 __get_user(sz, &iwmmxtframe->size);
2019 if (magic != TARGET_IWMMXT_MAGIC || sz != sizeof(*iwmmxtframe)) {
2020 return 0;
2021 }
2022 for (i = 0; i < 16; i++) {
2023 __get_user(env->iwmmxt.regs[i], &iwmmxtframe->regs[i]);
2024 }
2025 __get_user(env->vfp.xregs[ARM_IWMMXT_wCSSF], &iwmmxtframe->wcssf);
2026 __get_user(env->vfp.xregs[ARM_IWMMXT_wCASF], &iwmmxtframe->wcssf);
2027 __get_user(env->vfp.xregs[ARM_IWMMXT_wCGR0], &iwmmxtframe->wcgr0);
2028 __get_user(env->vfp.xregs[ARM_IWMMXT_wCGR1], &iwmmxtframe->wcgr1);
2029 __get_user(env->vfp.xregs[ARM_IWMMXT_wCGR2], &iwmmxtframe->wcgr2);
2030 __get_user(env->vfp.xregs[ARM_IWMMXT_wCGR3], &iwmmxtframe->wcgr3);
2031 return (abi_ulong*)(iwmmxtframe + 1);
2032}
2033
Andreas Färber05390242012-02-25 03:37:53 +01002034static int do_sigframe_return_v2(CPUARMState *env, target_ulong frame_addr,
pbrooka8c33202008-05-07 23:22:46 +00002035 struct target_ucontext_v2 *uc)
2036{
2037 sigset_t host_set;
Peter Maydell5f9099d2010-11-24 15:20:06 +00002038 abi_ulong *regspace;
pbrooka8c33202008-05-07 23:22:46 +00002039
2040 target_to_host_sigset(&host_set, &uc->tuc_sigmask);
Peter Maydell9eede5b2016-05-27 15:51:46 +01002041 set_sigmask(&host_set);
pbrooka8c33202008-05-07 23:22:46 +00002042
2043 if (restore_sigcontext(env, &uc->tuc_mcontext))
2044 return 1;
2045
Peter Maydell5f9099d2010-11-24 15:20:06 +00002046 /* Restore coprocessor signal frame */
2047 regspace = uc->tuc_regspace;
2048 if (arm_feature(env, ARM_FEATURE_VFP)) {
2049 regspace = restore_sigframe_v2_vfp(env, regspace);
2050 if (!regspace) {
2051 return 1;
2052 }
2053 }
Peter Maydella59d69d2010-11-24 15:20:08 +00002054 if (arm_feature(env, ARM_FEATURE_IWMMXT)) {
2055 regspace = restore_sigframe_v2_iwmmxt(env, regspace);
2056 if (!regspace) {
2057 return 1;
2058 }
2059 }
Peter Maydell5f9099d2010-11-24 15:20:06 +00002060
pbrooka8c33202008-05-07 23:22:46 +00002061 if (do_sigaltstack(frame_addr + offsetof(struct target_ucontext_v2, tuc_stack), 0, get_sp_from_cpustate(env)) == -EFAULT)
2062 return 1;
2063
2064#if 0
2065 /* Send SIGTRAP if we're single-stepping */
2066 if (ptrace_cancel_bpt(current))
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002067 send_sig(SIGTRAP, current, 1);
pbrooka8c33202008-05-07 23:22:46 +00002068#endif
2069
2070 return 0;
2071}
2072
Andreas Färber05390242012-02-25 03:37:53 +01002073static long do_sigreturn_v2(CPUARMState *env)
pbrooka8c33202008-05-07 23:22:46 +00002074{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002075 abi_ulong frame_addr;
2076 struct sigframe_v2 *frame = NULL;
pbrooka8c33202008-05-07 23:22:46 +00002077
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002078 /*
2079 * Since we stacked the signal on a 64-bit boundary,
2080 * then 'sp' should be word aligned here. If it's
2081 * not, then the user is trying to mess with us.
2082 */
2083 frame_addr = env->regs[13];
2084 trace_user_do_sigreturn(env, frame_addr);
2085 if (frame_addr & 7) {
2086 goto badframe;
2087 }
Peter Maydell978fae92013-07-29 12:00:32 +01002088
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002089 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
2090 goto badframe;
2091 }
pbrooka8c33202008-05-07 23:22:46 +00002092
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002093 if (do_sigframe_return_v2(env, frame_addr, &frame->uc)) {
2094 goto badframe;
2095 }
pbrooka8c33202008-05-07 23:22:46 +00002096
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002097 unlock_user_struct(frame, frame_addr, 0);
Timothy E Baldwinf0267ef2016-05-12 18:47:31 +01002098 return -TARGET_QEMU_ESIGRETURN;
pbrooka8c33202008-05-07 23:22:46 +00002099
2100badframe:
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002101 unlock_user_struct(frame, frame_addr, 0);
2102 force_sig(TARGET_SIGSEGV /* , current */);
2103 return 0;
pbrooka8c33202008-05-07 23:22:46 +00002104}
2105
Andreas Färber05390242012-02-25 03:37:53 +01002106long do_sigreturn(CPUARMState *env)
pbrooka8c33202008-05-07 23:22:46 +00002107{
2108 if (get_osversion() >= 0x020612) {
2109 return do_sigreturn_v2(env);
2110 } else {
2111 return do_sigreturn_v1(env);
2112 }
2113}
2114
Andreas Färber05390242012-02-25 03:37:53 +01002115static long do_rt_sigreturn_v1(CPUARMState *env)
bellard43fff232003-07-09 19:31:39 +00002116{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002117 abi_ulong frame_addr;
2118 struct rt_sigframe_v1 *frame = NULL;
2119 sigset_t host_set;
bellard43fff232003-07-09 19:31:39 +00002120
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002121 /*
2122 * Since we stacked the signal on a 64-bit boundary,
2123 * then 'sp' should be word aligned here. If it's
2124 * not, then the user is trying to mess with us.
2125 */
2126 frame_addr = env->regs[13];
2127 trace_user_do_rt_sigreturn(env, frame_addr);
2128 if (frame_addr & 7) {
2129 goto badframe;
2130 }
Peter Maydell978fae92013-07-29 12:00:32 +01002131
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002132 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
2133 goto badframe;
2134 }
bellard43fff232003-07-09 19:31:39 +00002135
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002136 target_to_host_sigset(&host_set, &frame->uc.tuc_sigmask);
Peter Maydell9eede5b2016-05-27 15:51:46 +01002137 set_sigmask(&host_set);
bellard43fff232003-07-09 19:31:39 +00002138
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002139 if (restore_sigcontext(env, &frame->uc.tuc_mcontext)) {
2140 goto badframe;
2141 }
bellard43fff232003-07-09 19:31:39 +00002142
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002143 if (do_sigaltstack(frame_addr + offsetof(struct rt_sigframe_v1, uc.tuc_stack), 0, get_sp_from_cpustate(env)) == -EFAULT)
2144 goto badframe;
thsa04e1342007-09-27 13:57:58 +00002145
bellard43fff232003-07-09 19:31:39 +00002146#if 0
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002147 /* Send SIGTRAP if we're single-stepping */
2148 if (ptrace_cancel_bpt(current))
2149 send_sig(SIGTRAP, current, 1);
bellard43fff232003-07-09 19:31:39 +00002150#endif
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002151 unlock_user_struct(frame, frame_addr, 0);
Timothy E Baldwinf0267ef2016-05-12 18:47:31 +01002152 return -TARGET_QEMU_ESIGRETURN;
bellard43fff232003-07-09 19:31:39 +00002153
2154badframe:
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002155 unlock_user_struct(frame, frame_addr, 0);
2156 force_sig(TARGET_SIGSEGV /* , current */);
2157 return 0;
bellard43fff232003-07-09 19:31:39 +00002158}
2159
Andreas Färber05390242012-02-25 03:37:53 +01002160static long do_rt_sigreturn_v2(CPUARMState *env)
pbrooka745ec62008-05-06 15:36:17 +00002161{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002162 abi_ulong frame_addr;
2163 struct rt_sigframe_v2 *frame = NULL;
pbrooka745ec62008-05-06 15:36:17 +00002164
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002165 /*
2166 * Since we stacked the signal on a 64-bit boundary,
2167 * then 'sp' should be word aligned here. If it's
2168 * not, then the user is trying to mess with us.
2169 */
2170 frame_addr = env->regs[13];
2171 trace_user_do_rt_sigreturn(env, frame_addr);
2172 if (frame_addr & 7) {
2173 goto badframe;
2174 }
Peter Maydell978fae92013-07-29 12:00:32 +01002175
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002176 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
2177 goto badframe;
2178 }
pbrooka745ec62008-05-06 15:36:17 +00002179
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002180 if (do_sigframe_return_v2(env, frame_addr, &frame->uc)) {
2181 goto badframe;
2182 }
pbrooka745ec62008-05-06 15:36:17 +00002183
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002184 unlock_user_struct(frame, frame_addr, 0);
Timothy E Baldwinf0267ef2016-05-12 18:47:31 +01002185 return -TARGET_QEMU_ESIGRETURN;
pbrooka745ec62008-05-06 15:36:17 +00002186
2187badframe:
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002188 unlock_user_struct(frame, frame_addr, 0);
2189 force_sig(TARGET_SIGSEGV /* , current */);
2190 return 0;
pbrooka745ec62008-05-06 15:36:17 +00002191}
2192
Andreas Färber05390242012-02-25 03:37:53 +01002193long do_rt_sigreturn(CPUARMState *env)
pbrooka745ec62008-05-06 15:36:17 +00002194{
2195 if (get_osversion() >= 0x020612) {
2196 return do_rt_sigreturn_v2(env);
2197 } else {
2198 return do_rt_sigreturn_v1(env);
2199 }
2200}
2201
bellard6d5e2162004-09-30 22:04:13 +00002202#elif defined(TARGET_SPARC)
bellard80a9d032005-01-03 23:31:27 +00002203
bellard6d5e2162004-09-30 22:04:13 +00002204#define __SUNOS_MAXWIN 31
2205
2206/* This is what SunOS does, so shall I. */
2207struct target_sigcontext {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002208 abi_ulong sigc_onstack; /* state to restore */
bellard6d5e2162004-09-30 22:04:13 +00002209
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002210 abi_ulong sigc_mask; /* sigmask to restore */
2211 abi_ulong sigc_sp; /* stack pointer */
2212 abi_ulong sigc_pc; /* program counter */
2213 abi_ulong sigc_npc; /* next program counter */
2214 abi_ulong sigc_psr; /* for condition codes etc */
2215 abi_ulong sigc_g1; /* User uses these two registers */
2216 abi_ulong sigc_o0; /* within the trampoline code. */
bellard6d5e2162004-09-30 22:04:13 +00002217
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002218 /* Now comes information regarding the users window set
bellard6d5e2162004-09-30 22:04:13 +00002219 * at the time of the signal.
2220 */
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002221 abi_ulong sigc_oswins; /* outstanding windows */
bellard6d5e2162004-09-30 22:04:13 +00002222
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002223 /* stack ptrs for each regwin buf */
2224 char *sigc_spbuf[__SUNOS_MAXWIN];
bellard6d5e2162004-09-30 22:04:13 +00002225
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002226 /* Windows to restore after signal */
2227 struct {
2228 abi_ulong locals[8];
2229 abi_ulong ins[8];
2230 } sigc_wbuf[__SUNOS_MAXWIN];
bellard6d5e2162004-09-30 22:04:13 +00002231};
2232/* A Sparc stack frame */
2233struct sparc_stackf {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002234 abi_ulong locals[8];
2235 abi_ulong ins[8];
2236 /* It's simpler to treat fp and callers_pc as elements of ins[]
Peter Maydelle321c342011-02-01 15:54:52 +00002237 * since we never need to access them ourselves.
2238 */
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002239 char *structptr;
2240 abi_ulong xargs[6];
2241 abi_ulong xxargs[1];
bellard6d5e2162004-09-30 22:04:13 +00002242};
2243
2244typedef struct {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002245 struct {
2246 abi_ulong psr;
2247 abi_ulong pc;
2248 abi_ulong npc;
2249 abi_ulong y;
2250 abi_ulong u_regs[16]; /* globals and ins */
2251 } si_regs;
2252 int si_mask;
bellard6d5e2162004-09-30 22:04:13 +00002253} __siginfo_t;
2254
2255typedef struct {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002256 abi_ulong si_float_regs[32];
2257 unsigned long si_fsr;
2258 unsigned long si_fpqdepth;
2259 struct {
2260 unsigned long *insn_addr;
2261 unsigned long insn;
2262 } si_fpqueue [16];
Anthony Liguoric227f092009-10-01 16:12:16 -05002263} qemu_siginfo_fpu_t;
bellard6d5e2162004-09-30 22:04:13 +00002264
2265
2266struct target_signal_frame {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002267 struct sparc_stackf ss;
2268 __siginfo_t info;
2269 abi_ulong fpu_save;
2270 abi_ulong insns[2] __attribute__ ((aligned (8)));
2271 abi_ulong extramask[TARGET_NSIG_WORDS - 1];
2272 abi_ulong extra_size; /* Should be 0 */
2273 qemu_siginfo_fpu_t fpu_state;
bellard6d5e2162004-09-30 22:04:13 +00002274};
2275struct target_rt_signal_frame {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002276 struct sparc_stackf ss;
2277 siginfo_t info;
2278 abi_ulong regs[20];
2279 sigset_t mask;
2280 abi_ulong fpu_save;
2281 unsigned int insns[2];
2282 stack_t stack;
2283 unsigned int extra_size; /* Should be 0 */
2284 qemu_siginfo_fpu_t fpu_state;
bellard6d5e2162004-09-30 22:04:13 +00002285};
2286
bellarde80cfcf2004-12-19 23:18:01 +00002287#define UREG_O0 16
2288#define UREG_O6 22
2289#define UREG_I0 0
2290#define UREG_I1 1
2291#define UREG_I2 2
blueswir15bfb56b2007-10-05 17:01:51 +00002292#define UREG_I3 3
2293#define UREG_I4 4
2294#define UREG_I5 5
bellarde80cfcf2004-12-19 23:18:01 +00002295#define UREG_I6 6
2296#define UREG_I7 7
2297#define UREG_L0 8
bellard6d5e2162004-09-30 22:04:13 +00002298#define UREG_FP UREG_I6
2299#define UREG_SP UREG_O6
2300
pbrook624f7972008-05-31 16:11:38 +00002301static inline abi_ulong get_sigframe(struct target_sigaction *sa,
Andreas Färber05390242012-02-25 03:37:53 +01002302 CPUSPARCState *env,
2303 unsigned long framesize)
bellard6d5e2162004-09-30 22:04:13 +00002304{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002305 abi_ulong sp;
bellard6d5e2162004-09-30 22:04:13 +00002306
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002307 sp = env->regwptr[UREG_FP];
bellard6d5e2162004-09-30 22:04:13 +00002308
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002309 /* This is the X/Open sanctioned signal stack switching. */
2310 if (sa->sa_flags & TARGET_SA_ONSTACK) {
2311 if (!on_sig_stack(sp)
2312 && !((target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size) & 7)) {
2313 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
2314 }
2315 }
2316 return sp - framesize;
bellard6d5e2162004-09-30 22:04:13 +00002317}
2318
2319static int
Andreas Färber05390242012-02-25 03:37:53 +01002320setup___siginfo(__siginfo_t *si, CPUSPARCState *env, abi_ulong mask)
bellard6d5e2162004-09-30 22:04:13 +00002321{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002322 int err = 0, i;
bellard6d5e2162004-09-30 22:04:13 +00002323
Riku Voipio1d8b5122014-04-23 10:26:05 +03002324 __put_user(env->psr, &si->si_regs.psr);
2325 __put_user(env->pc, &si->si_regs.pc);
2326 __put_user(env->npc, &si->si_regs.npc);
2327 __put_user(env->y, &si->si_regs.y);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002328 for (i=0; i < 8; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002329 __put_user(env->gregs[i], &si->si_regs.u_regs[i]);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002330 }
2331 for (i=0; i < 8; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002332 __put_user(env->regwptr[UREG_I0 + i], &si->si_regs.u_regs[i+8]);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002333 }
Riku Voipio1d8b5122014-04-23 10:26:05 +03002334 __put_user(mask, &si->si_mask);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002335 return err;
bellard6d5e2162004-09-30 22:04:13 +00002336}
bellarde80cfcf2004-12-19 23:18:01 +00002337
bellard80a9d032005-01-03 23:31:27 +00002338#if 0
bellard6d5e2162004-09-30 22:04:13 +00002339static int
2340setup_sigcontext(struct target_sigcontext *sc, /*struct _fpstate *fpstate,*/
Andreas Färber05390242012-02-25 03:37:53 +01002341 CPUSPARCState *env, unsigned long mask)
bellard6d5e2162004-09-30 22:04:13 +00002342{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002343 int err = 0;
bellard6d5e2162004-09-30 22:04:13 +00002344
Riku Voipio1d8b5122014-04-23 10:26:05 +03002345 __put_user(mask, &sc->sigc_mask);
2346 __put_user(env->regwptr[UREG_SP], &sc->sigc_sp);
2347 __put_user(env->pc, &sc->sigc_pc);
2348 __put_user(env->npc, &sc->sigc_npc);
2349 __put_user(env->psr, &sc->sigc_psr);
2350 __put_user(env->gregs[1], &sc->sigc_g1);
2351 __put_user(env->regwptr[UREG_O0], &sc->sigc_o0);
bellard6d5e2162004-09-30 22:04:13 +00002352
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002353 return err;
bellard6d5e2162004-09-30 22:04:13 +00002354}
bellard80a9d032005-01-03 23:31:27 +00002355#endif
bellard6d5e2162004-09-30 22:04:13 +00002356#define NF_ALIGNEDSZ (((sizeof(struct target_signal_frame) + 7) & (~7)))
2357
pbrook624f7972008-05-31 16:11:38 +00002358static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01002359 target_sigset_t *set, CPUSPARCState *env)
bellard6d5e2162004-09-30 22:04:13 +00002360{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002361 abi_ulong sf_addr;
2362 struct target_signal_frame *sf;
2363 int sigframe_size, err, i;
bellard6d5e2162004-09-30 22:04:13 +00002364
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002365 /* 1. Make sure everything is clean */
2366 //synchronize_user_stack();
bellard6d5e2162004-09-30 22:04:13 +00002367
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002368 sigframe_size = NF_ALIGNEDSZ;
2369 sf_addr = get_sigframe(ka, env, sigframe_size);
2370 trace_user_setup_frame(env, sf_addr);
bellard6d5e2162004-09-30 22:04:13 +00002371
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002372 sf = lock_user(VERIFY_WRITE, sf_addr,
2373 sizeof(struct target_signal_frame), 0);
2374 if (!sf) {
2375 goto sigsegv;
2376 }
bellard6d5e2162004-09-30 22:04:13 +00002377#if 0
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002378 if (invalid_frame_pointer(sf, sigframe_size))
2379 goto sigill_and_return;
bellard6d5e2162004-09-30 22:04:13 +00002380#endif
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002381 /* 2. Save the current process state */
2382 err = setup___siginfo(&sf->info, env, set->sig[0]);
Riku Voipio1d8b5122014-04-23 10:26:05 +03002383 __put_user(0, &sf->extra_size);
bellard6d5e2162004-09-30 22:04:13 +00002384
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002385 //save_fpu_state(regs, &sf->fpu_state);
2386 //__put_user(&sf->fpu_state, &sf->fpu_save);
bellard6d5e2162004-09-30 22:04:13 +00002387
Riku Voipio1d8b5122014-04-23 10:26:05 +03002388 __put_user(set->sig[0], &sf->info.si_mask);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002389 for (i = 0; i < TARGET_NSIG_WORDS - 1; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002390 __put_user(set->sig[i + 1], &sf->extramask[i]);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002391 }
bellard6d5e2162004-09-30 22:04:13 +00002392
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002393 for (i = 0; i < 8; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002394 __put_user(env->regwptr[i + UREG_L0], &sf->ss.locals[i]);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002395 }
2396 for (i = 0; i < 8; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002397 __put_user(env->regwptr[i + UREG_I0], &sf->ss.ins[i]);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002398 }
2399 if (err)
2400 goto sigsegv;
bellard6d5e2162004-09-30 22:04:13 +00002401
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002402 /* 3. signal handler back-trampoline and parameters */
2403 env->regwptr[UREG_FP] = sf_addr;
2404 env->regwptr[UREG_I0] = sig;
2405 env->regwptr[UREG_I1] = sf_addr +
2406 offsetof(struct target_signal_frame, info);
2407 env->regwptr[UREG_I2] = sf_addr +
2408 offsetof(struct target_signal_frame, info);
bellard6d5e2162004-09-30 22:04:13 +00002409
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002410 /* 4. signal handler */
2411 env->pc = ka->_sa_handler;
2412 env->npc = (env->pc + 4);
2413 /* 5. return to kernel instructions */
2414 if (ka->sa_restorer) {
2415 env->regwptr[UREG_I7] = ka->sa_restorer;
2416 } else {
2417 uint32_t val32;
bellard459a4012007-11-11 19:45:10 +00002418
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002419 env->regwptr[UREG_I7] = sf_addr +
2420 offsetof(struct target_signal_frame, insns) - 2 * 4;
bellard6d5e2162004-09-30 22:04:13 +00002421
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002422 /* mov __NR_sigreturn, %g1 */
2423 val32 = 0x821020d8;
Riku Voipio1d8b5122014-04-23 10:26:05 +03002424 __put_user(val32, &sf->insns[0]);
bellard6d5e2162004-09-30 22:04:13 +00002425
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002426 /* t 0x10 */
2427 val32 = 0x91d02010;
Riku Voipio1d8b5122014-04-23 10:26:05 +03002428 __put_user(val32, &sf->insns[1]);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002429 if (err)
2430 goto sigsegv;
bellard6d5e2162004-09-30 22:04:13 +00002431
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002432 /* Flush instruction space. */
2433 // flush_sig_insns(current->mm, (unsigned long) &(sf->insns[0]));
2434 // tb_flush(env);
2435 }
2436 unlock_user(sf, sf_addr, sizeof(struct target_signal_frame));
2437 return;
bellard459a4012007-11-11 19:45:10 +00002438#if 0
2439sigill_and_return:
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002440 force_sig(TARGET_SIGILL);
bellard459a4012007-11-11 19:45:10 +00002441#endif
bellard6d5e2162004-09-30 22:04:13 +00002442sigsegv:
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002443 unlock_user(sf, sf_addr, sizeof(struct target_signal_frame));
2444 force_sig(TARGET_SIGSEGV);
bellard6d5e2162004-09-30 22:04:13 +00002445}
bellard6d5e2162004-09-30 22:04:13 +00002446
pbrook624f7972008-05-31 16:11:38 +00002447static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05002448 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01002449 target_sigset_t *set, CPUSPARCState *env)
bellard6d5e2162004-09-30 22:04:13 +00002450{
2451 fprintf(stderr, "setup_rt_frame: not implemented\n");
2452}
2453
Andreas Färber05390242012-02-25 03:37:53 +01002454long do_sigreturn(CPUSPARCState *env)
bellard6d5e2162004-09-30 22:04:13 +00002455{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002456 abi_ulong sf_addr;
2457 struct target_signal_frame *sf;
2458 uint32_t up_psr, pc, npc;
2459 target_sigset_t set;
2460 sigset_t host_set;
2461 int err=0, i;
bellard6d5e2162004-09-30 22:04:13 +00002462
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002463 sf_addr = env->regwptr[UREG_FP];
2464 trace_user_do_sigreturn(env, sf_addr);
2465 if (!lock_user_struct(VERIFY_READ, sf, sf_addr, 1)) {
2466 goto segv_and_exit;
2467 }
bellard6d5e2162004-09-30 22:04:13 +00002468
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002469 /* 1. Make sure we are not getting garbage from the user */
bellard6d5e2162004-09-30 22:04:13 +00002470
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002471 if (sf_addr & 3)
2472 goto segv_and_exit;
bellard6d5e2162004-09-30 22:04:13 +00002473
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002474 __get_user(pc, &sf->info.si_regs.pc);
2475 __get_user(npc, &sf->info.si_regs.npc);
bellard6d5e2162004-09-30 22:04:13 +00002476
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002477 if ((pc | npc) & 3) {
2478 goto segv_and_exit;
2479 }
bellard6d5e2162004-09-30 22:04:13 +00002480
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002481 /* 2. Restore the state */
2482 __get_user(up_psr, &sf->info.si_regs.psr);
bellarde80cfcf2004-12-19 23:18:01 +00002483
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002484 /* User can only change condition codes and FPU enabling in %psr. */
2485 env->psr = (up_psr & (PSR_ICC /* | PSR_EF */))
2486 | (env->psr & ~(PSR_ICC /* | PSR_EF */));
bellarda315a142005-01-30 22:59:18 +00002487
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002488 env->pc = pc;
2489 env->npc = npc;
2490 __get_user(env->y, &sf->info.si_regs.y);
2491 for (i=0; i < 8; i++) {
2492 __get_user(env->gregs[i], &sf->info.si_regs.u_regs[i]);
2493 }
2494 for (i=0; i < 8; i++) {
2495 __get_user(env->regwptr[i + UREG_I0], &sf->info.si_regs.u_regs[i+8]);
2496 }
bellard6d5e2162004-09-30 22:04:13 +00002497
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002498 /* FIXME: implement FPU save/restore:
Peter Maydell2aec3a22011-06-16 17:37:14 +01002499 * __get_user(fpu_save, &sf->fpu_save);
2500 * if (fpu_save)
2501 * err |= restore_fpu_state(env, fpu_save);
2502 */
bellard6d5e2162004-09-30 22:04:13 +00002503
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002504 /* This is pretty much atomic, no amount locking would prevent
bellard6d5e2162004-09-30 22:04:13 +00002505 * the races which exist anyways.
2506 */
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002507 __get_user(set.sig[0], &sf->info.si_mask);
2508 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
2509 __get_user(set.sig[i], &sf->extramask[i - 1]);
2510 }
bellarde80cfcf2004-12-19 23:18:01 +00002511
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002512 target_to_host_sigset_internal(&host_set, &set);
Peter Maydell9eede5b2016-05-27 15:51:46 +01002513 set_sigmask(&host_set);
bellard6d5e2162004-09-30 22:04:13 +00002514
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002515 if (err) {
2516 goto segv_and_exit;
2517 }
2518 unlock_user_struct(sf, sf_addr, 0);
Timothy E Baldwinc0bea682016-05-12 18:47:34 +01002519 return -TARGET_QEMU_ESIGRETURN;
bellard6d5e2162004-09-30 22:04:13 +00002520
2521segv_and_exit:
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002522 unlock_user_struct(sf, sf_addr, 0);
2523 force_sig(TARGET_SIGSEGV);
bellard6d5e2162004-09-30 22:04:13 +00002524}
2525
Andreas Färber05390242012-02-25 03:37:53 +01002526long do_rt_sigreturn(CPUSPARCState *env)
bellard6d5e2162004-09-30 22:04:13 +00002527{
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01002528 trace_user_do_rt_sigreturn(env, 0);
bellard6d5e2162004-09-30 22:04:13 +00002529 fprintf(stderr, "do_rt_sigreturn: not implemented\n");
bellardf8b0aa22007-11-11 23:03:42 +00002530 return -TARGET_ENOSYS;
bellard6d5e2162004-09-30 22:04:13 +00002531}
2532
bellard459a4012007-11-11 19:45:10 +00002533#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
blueswir15bfb56b2007-10-05 17:01:51 +00002534#define MC_TSTATE 0
2535#define MC_PC 1
2536#define MC_NPC 2
2537#define MC_Y 3
2538#define MC_G1 4
2539#define MC_G2 5
2540#define MC_G3 6
2541#define MC_G4 7
2542#define MC_G5 8
2543#define MC_G6 9
2544#define MC_G7 10
2545#define MC_O0 11
2546#define MC_O1 12
2547#define MC_O2 13
2548#define MC_O3 14
2549#define MC_O4 15
2550#define MC_O5 16
2551#define MC_O6 17
2552#define MC_O7 18
2553#define MC_NGREG 19
2554
Anthony Liguoric227f092009-10-01 16:12:16 -05002555typedef abi_ulong target_mc_greg_t;
2556typedef target_mc_greg_t target_mc_gregset_t[MC_NGREG];
blueswir15bfb56b2007-10-05 17:01:51 +00002557
2558struct target_mc_fq {
blueswir1992f48a2007-10-14 16:27:31 +00002559 abi_ulong *mcfq_addr;
blueswir15bfb56b2007-10-05 17:01:51 +00002560 uint32_t mcfq_insn;
2561};
2562
2563struct target_mc_fpu {
2564 union {
2565 uint32_t sregs[32];
2566 uint64_t dregs[32];
2567 //uint128_t qregs[16];
2568 } mcfpu_fregs;
blueswir1992f48a2007-10-14 16:27:31 +00002569 abi_ulong mcfpu_fsr;
2570 abi_ulong mcfpu_fprs;
2571 abi_ulong mcfpu_gsr;
blueswir15bfb56b2007-10-05 17:01:51 +00002572 struct target_mc_fq *mcfpu_fq;
2573 unsigned char mcfpu_qcnt;
2574 unsigned char mcfpu_qentsz;
2575 unsigned char mcfpu_enab;
2576};
Anthony Liguoric227f092009-10-01 16:12:16 -05002577typedef struct target_mc_fpu target_mc_fpu_t;
blueswir15bfb56b2007-10-05 17:01:51 +00002578
2579typedef struct {
Anthony Liguoric227f092009-10-01 16:12:16 -05002580 target_mc_gregset_t mc_gregs;
2581 target_mc_greg_t mc_fp;
2582 target_mc_greg_t mc_i7;
2583 target_mc_fpu_t mc_fpregs;
2584} target_mcontext_t;
blueswir15bfb56b2007-10-05 17:01:51 +00002585
2586struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02002587 struct target_ucontext *tuc_link;
2588 abi_ulong tuc_flags;
2589 target_sigset_t tuc_sigmask;
2590 target_mcontext_t tuc_mcontext;
blueswir15bfb56b2007-10-05 17:01:51 +00002591};
2592
2593/* A V9 register window */
2594struct target_reg_window {
blueswir1992f48a2007-10-14 16:27:31 +00002595 abi_ulong locals[8];
2596 abi_ulong ins[8];
blueswir15bfb56b2007-10-05 17:01:51 +00002597};
2598
2599#define TARGET_STACK_BIAS 2047
2600
2601/* {set, get}context() needed for 64-bit SparcLinux userland. */
2602void sparc64_set_context(CPUSPARCState *env)
2603{
bellard459a4012007-11-11 19:45:10 +00002604 abi_ulong ucp_addr;
2605 struct target_ucontext *ucp;
Anthony Liguoric227f092009-10-01 16:12:16 -05002606 target_mc_gregset_t *grp;
blueswir1992f48a2007-10-14 16:27:31 +00002607 abi_ulong pc, npc, tstate;
bellard459a4012007-11-11 19:45:10 +00002608 abi_ulong fp, i7, w_addr;
blueswir15bfb56b2007-10-05 17:01:51 +00002609 unsigned int i;
blueswir15bfb56b2007-10-05 17:01:51 +00002610
bellard459a4012007-11-11 19:45:10 +00002611 ucp_addr = env->regwptr[UREG_I0];
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002612 if (!lock_user_struct(VERIFY_READ, ucp, ucp_addr, 1)) {
bellard459a4012007-11-11 19:45:10 +00002613 goto do_sigsegv;
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002614 }
Aurelien Jarno60e99242010-03-29 02:12:51 +02002615 grp = &ucp->tuc_mcontext.mc_gregs;
Riku Voipio1d8b5122014-04-23 10:26:05 +03002616 __get_user(pc, &((*grp)[MC_PC]));
2617 __get_user(npc, &((*grp)[MC_NPC]));
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002618 if ((pc | npc) & 3) {
blueswir15bfb56b2007-10-05 17:01:51 +00002619 goto do_sigsegv;
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002620 }
blueswir15bfb56b2007-10-05 17:01:51 +00002621 if (env->regwptr[UREG_I1]) {
Anthony Liguoric227f092009-10-01 16:12:16 -05002622 target_sigset_t target_set;
blueswir15bfb56b2007-10-05 17:01:51 +00002623 sigset_t set;
2624
2625 if (TARGET_NSIG_WORDS == 1) {
Riku Voipiobe3ef5c2014-04-23 14:02:36 +03002626 __get_user(target_set.sig[0], &ucp->tuc_sigmask.sig[0]);
blueswir15bfb56b2007-10-05 17:01:51 +00002627 } else {
bellard459a4012007-11-11 19:45:10 +00002628 abi_ulong *src, *dst;
Aurelien Jarno60e99242010-03-29 02:12:51 +02002629 src = ucp->tuc_sigmask.sig;
bellard459a4012007-11-11 19:45:10 +00002630 dst = target_set.sig;
Stefan Weil0d9e61c2013-12-07 14:48:08 +01002631 for (i = 0; i < TARGET_NSIG_WORDS; i++, dst++, src++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002632 __get_user(*dst, src);
Stefan Weil0d9e61c2013-12-07 14:48:08 +01002633 }
blueswir15bfb56b2007-10-05 17:01:51 +00002634 }
2635 target_to_host_sigset_internal(&set, &target_set);
Peter Maydell9eede5b2016-05-27 15:51:46 +01002636 set_sigmask(&set);
blueswir15bfb56b2007-10-05 17:01:51 +00002637 }
2638 env->pc = pc;
2639 env->npc = npc;
Riku Voipio1d8b5122014-04-23 10:26:05 +03002640 __get_user(env->y, &((*grp)[MC_Y]));
2641 __get_user(tstate, &((*grp)[MC_TSTATE]));
blueswir15bfb56b2007-10-05 17:01:51 +00002642 env->asi = (tstate >> 24) & 0xff;
Blue Swirl5a834bb2010-05-09 20:19:04 +00002643 cpu_put_ccr(env, tstate >> 32);
2644 cpu_put_cwp64(env, tstate & 0x1f);
Riku Voipio1d8b5122014-04-23 10:26:05 +03002645 __get_user(env->gregs[1], (&(*grp)[MC_G1]));
2646 __get_user(env->gregs[2], (&(*grp)[MC_G2]));
2647 __get_user(env->gregs[3], (&(*grp)[MC_G3]));
2648 __get_user(env->gregs[4], (&(*grp)[MC_G4]));
2649 __get_user(env->gregs[5], (&(*grp)[MC_G5]));
2650 __get_user(env->gregs[6], (&(*grp)[MC_G6]));
2651 __get_user(env->gregs[7], (&(*grp)[MC_G7]));
2652 __get_user(env->regwptr[UREG_I0], (&(*grp)[MC_O0]));
2653 __get_user(env->regwptr[UREG_I1], (&(*grp)[MC_O1]));
2654 __get_user(env->regwptr[UREG_I2], (&(*grp)[MC_O2]));
2655 __get_user(env->regwptr[UREG_I3], (&(*grp)[MC_O3]));
2656 __get_user(env->regwptr[UREG_I4], (&(*grp)[MC_O4]));
2657 __get_user(env->regwptr[UREG_I5], (&(*grp)[MC_O5]));
2658 __get_user(env->regwptr[UREG_I6], (&(*grp)[MC_O6]));
2659 __get_user(env->regwptr[UREG_I7], (&(*grp)[MC_O7]));
blueswir15bfb56b2007-10-05 17:01:51 +00002660
Riku Voipio1d8b5122014-04-23 10:26:05 +03002661 __get_user(fp, &(ucp->tuc_mcontext.mc_fp));
2662 __get_user(i7, &(ucp->tuc_mcontext.mc_i7));
blueswir15bfb56b2007-10-05 17:01:51 +00002663
bellard459a4012007-11-11 19:45:10 +00002664 w_addr = TARGET_STACK_BIAS+env->regwptr[UREG_I6];
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002665 if (put_user(fp, w_addr + offsetof(struct target_reg_window, ins[6]),
2666 abi_ulong) != 0) {
bellard459a4012007-11-11 19:45:10 +00002667 goto do_sigsegv;
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002668 }
2669 if (put_user(i7, w_addr + offsetof(struct target_reg_window, ins[7]),
2670 abi_ulong) != 0) {
bellard459a4012007-11-11 19:45:10 +00002671 goto do_sigsegv;
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002672 }
Peter Maydellc7b016b2011-06-16 17:37:15 +01002673 /* FIXME this does not match how the kernel handles the FPU in
2674 * its sparc64_set_context implementation. In particular the FPU
2675 * is only restored if fenab is non-zero in:
2676 * __get_user(fenab, &(ucp->tuc_mcontext.mc_fpregs.mcfpu_enab));
2677 */
Riku Voipiobe3ef5c2014-04-23 14:02:36 +03002678 __get_user(env->fprs, &(ucp->tuc_mcontext.mc_fpregs.mcfpu_fprs));
bellard459a4012007-11-11 19:45:10 +00002679 {
Richard Henderson30038fd2011-10-17 10:42:49 -07002680 uint32_t *src = ucp->tuc_mcontext.mc_fpregs.mcfpu_fregs.sregs;
2681 for (i = 0; i < 64; i++, src++) {
2682 if (i & 1) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002683 __get_user(env->fpr[i/2].l.lower, src);
Richard Henderson30038fd2011-10-17 10:42:49 -07002684 } else {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002685 __get_user(env->fpr[i/2].l.upper, src);
Richard Henderson30038fd2011-10-17 10:42:49 -07002686 }
2687 }
bellard459a4012007-11-11 19:45:10 +00002688 }
Riku Voipio1d8b5122014-04-23 10:26:05 +03002689 __get_user(env->fsr,
2690 &(ucp->tuc_mcontext.mc_fpregs.mcfpu_fsr));
2691 __get_user(env->gsr,
2692 &(ucp->tuc_mcontext.mc_fpregs.mcfpu_gsr));
bellard459a4012007-11-11 19:45:10 +00002693 unlock_user_struct(ucp, ucp_addr, 0);
blueswir15bfb56b2007-10-05 17:01:51 +00002694 return;
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002695do_sigsegv:
bellard459a4012007-11-11 19:45:10 +00002696 unlock_user_struct(ucp, ucp_addr, 0);
Riku Voipio66393fb2009-12-04 15:16:32 +02002697 force_sig(TARGET_SIGSEGV);
blueswir15bfb56b2007-10-05 17:01:51 +00002698}
2699
2700void sparc64_get_context(CPUSPARCState *env)
2701{
bellard459a4012007-11-11 19:45:10 +00002702 abi_ulong ucp_addr;
2703 struct target_ucontext *ucp;
Anthony Liguoric227f092009-10-01 16:12:16 -05002704 target_mc_gregset_t *grp;
2705 target_mcontext_t *mcp;
bellard459a4012007-11-11 19:45:10 +00002706 abi_ulong fp, i7, w_addr;
blueswir15bfb56b2007-10-05 17:01:51 +00002707 int err;
2708 unsigned int i;
Anthony Liguoric227f092009-10-01 16:12:16 -05002709 target_sigset_t target_set;
blueswir15bfb56b2007-10-05 17:01:51 +00002710 sigset_t set;
2711
bellard459a4012007-11-11 19:45:10 +00002712 ucp_addr = env->regwptr[UREG_I0];
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002713 if (!lock_user_struct(VERIFY_WRITE, ucp, ucp_addr, 0)) {
bellard459a4012007-11-11 19:45:10 +00002714 goto do_sigsegv;
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002715 }
bellard459a4012007-11-11 19:45:10 +00002716
Aurelien Jarno60e99242010-03-29 02:12:51 +02002717 mcp = &ucp->tuc_mcontext;
blueswir15bfb56b2007-10-05 17:01:51 +00002718 grp = &mcp->mc_gregs;
2719
2720 /* Skip over the trap instruction, first. */
2721 env->pc = env->npc;
2722 env->npc += 4;
2723
Peter Maydell3d3efba2016-05-27 15:51:49 +01002724 /* If we're only reading the signal mask then do_sigprocmask()
2725 * is guaranteed not to fail, which is important because we don't
2726 * have any way to signal a failure or restart this operation since
2727 * this is not a normal syscall.
2728 */
2729 err = do_sigprocmask(0, NULL, &set);
2730 assert(err == 0);
blueswir15bfb56b2007-10-05 17:01:51 +00002731 host_to_target_sigset_internal(&target_set, &set);
bellard459a4012007-11-11 19:45:10 +00002732 if (TARGET_NSIG_WORDS == 1) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002733 __put_user(target_set.sig[0],
2734 (abi_ulong *)&ucp->tuc_sigmask);
bellard459a4012007-11-11 19:45:10 +00002735 } else {
2736 abi_ulong *src, *dst;
2737 src = target_set.sig;
Aurelien Jarno60e99242010-03-29 02:12:51 +02002738 dst = ucp->tuc_sigmask.sig;
Stefan Weil0d9e61c2013-12-07 14:48:08 +01002739 for (i = 0; i < TARGET_NSIG_WORDS; i++, dst++, src++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002740 __put_user(*src, dst);
Stefan Weil0d9e61c2013-12-07 14:48:08 +01002741 }
blueswir15bfb56b2007-10-05 17:01:51 +00002742 if (err)
2743 goto do_sigsegv;
2744 }
2745
bellard459a4012007-11-11 19:45:10 +00002746 /* XXX: tstate must be saved properly */
Riku Voipio1d8b5122014-04-23 10:26:05 +03002747 // __put_user(env->tstate, &((*grp)[MC_TSTATE]));
2748 __put_user(env->pc, &((*grp)[MC_PC]));
2749 __put_user(env->npc, &((*grp)[MC_NPC]));
2750 __put_user(env->y, &((*grp)[MC_Y]));
2751 __put_user(env->gregs[1], &((*grp)[MC_G1]));
2752 __put_user(env->gregs[2], &((*grp)[MC_G2]));
2753 __put_user(env->gregs[3], &((*grp)[MC_G3]));
2754 __put_user(env->gregs[4], &((*grp)[MC_G4]));
2755 __put_user(env->gregs[5], &((*grp)[MC_G5]));
2756 __put_user(env->gregs[6], &((*grp)[MC_G6]));
2757 __put_user(env->gregs[7], &((*grp)[MC_G7]));
2758 __put_user(env->regwptr[UREG_I0], &((*grp)[MC_O0]));
2759 __put_user(env->regwptr[UREG_I1], &((*grp)[MC_O1]));
2760 __put_user(env->regwptr[UREG_I2], &((*grp)[MC_O2]));
2761 __put_user(env->regwptr[UREG_I3], &((*grp)[MC_O3]));
2762 __put_user(env->regwptr[UREG_I4], &((*grp)[MC_O4]));
2763 __put_user(env->regwptr[UREG_I5], &((*grp)[MC_O5]));
2764 __put_user(env->regwptr[UREG_I6], &((*grp)[MC_O6]));
2765 __put_user(env->regwptr[UREG_I7], &((*grp)[MC_O7]));
blueswir15bfb56b2007-10-05 17:01:51 +00002766
bellard459a4012007-11-11 19:45:10 +00002767 w_addr = TARGET_STACK_BIAS+env->regwptr[UREG_I6];
2768 fp = i7 = 0;
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002769 if (get_user(fp, w_addr + offsetof(struct target_reg_window, ins[6]),
2770 abi_ulong) != 0) {
bellard459a4012007-11-11 19:45:10 +00002771 goto do_sigsegv;
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002772 }
2773 if (get_user(i7, w_addr + offsetof(struct target_reg_window, ins[7]),
2774 abi_ulong) != 0) {
bellard459a4012007-11-11 19:45:10 +00002775 goto do_sigsegv;
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002776 }
Riku Voipio1d8b5122014-04-23 10:26:05 +03002777 __put_user(fp, &(mcp->mc_fp));
2778 __put_user(i7, &(mcp->mc_i7));
blueswir15bfb56b2007-10-05 17:01:51 +00002779
bellard459a4012007-11-11 19:45:10 +00002780 {
Richard Henderson30038fd2011-10-17 10:42:49 -07002781 uint32_t *dst = ucp->tuc_mcontext.mc_fpregs.mcfpu_fregs.sregs;
2782 for (i = 0; i < 64; i++, dst++) {
2783 if (i & 1) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002784 __put_user(env->fpr[i/2].l.lower, dst);
Richard Henderson30038fd2011-10-17 10:42:49 -07002785 } else {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002786 __put_user(env->fpr[i/2].l.upper, dst);
Richard Henderson30038fd2011-10-17 10:42:49 -07002787 }
2788 }
bellard459a4012007-11-11 19:45:10 +00002789 }
Riku Voipio1d8b5122014-04-23 10:26:05 +03002790 __put_user(env->fsr, &(mcp->mc_fpregs.mcfpu_fsr));
2791 __put_user(env->gsr, &(mcp->mc_fpregs.mcfpu_gsr));
2792 __put_user(env->fprs, &(mcp->mc_fpregs.mcfpu_fprs));
blueswir15bfb56b2007-10-05 17:01:51 +00002793
2794 if (err)
2795 goto do_sigsegv;
bellard459a4012007-11-11 19:45:10 +00002796 unlock_user_struct(ucp, ucp_addr, 1);
blueswir15bfb56b2007-10-05 17:01:51 +00002797 return;
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002798do_sigsegv:
bellard459a4012007-11-11 19:45:10 +00002799 unlock_user_struct(ucp, ucp_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02002800 force_sig(TARGET_SIGSEGV);
blueswir15bfb56b2007-10-05 17:01:51 +00002801}
2802#endif
Richard Hendersonff970902013-02-10 10:30:42 -08002803#elif defined(TARGET_MIPS) || defined(TARGET_MIPS64)
bellard106ec872006-06-27 21:08:10 +00002804
Richard Hendersonff970902013-02-10 10:30:42 -08002805# if defined(TARGET_ABI_MIPSO32)
bellard106ec872006-06-27 21:08:10 +00002806struct target_sigcontext {
2807 uint32_t sc_regmask; /* Unused */
2808 uint32_t sc_status;
2809 uint64_t sc_pc;
2810 uint64_t sc_regs[32];
2811 uint64_t sc_fpregs[32];
2812 uint32_t sc_ownedfp; /* Unused */
2813 uint32_t sc_fpc_csr;
2814 uint32_t sc_fpc_eir; /* Unused */
2815 uint32_t sc_used_math;
2816 uint32_t sc_dsp; /* dsp status, was sc_ssflags */
Paul Brook94c54952009-07-09 18:40:15 +01002817 uint32_t pad0;
bellard106ec872006-06-27 21:08:10 +00002818 uint64_t sc_mdhi;
2819 uint64_t sc_mdlo;
2820 target_ulong sc_hi1; /* Was sc_cause */
2821 target_ulong sc_lo1; /* Was sc_badvaddr */
2822 target_ulong sc_hi2; /* Was sc_sigset[4] */
2823 target_ulong sc_lo2;
2824 target_ulong sc_hi3;
2825 target_ulong sc_lo3;
2826};
Richard Hendersonff970902013-02-10 10:30:42 -08002827# else /* N32 || N64 */
2828struct target_sigcontext {
2829 uint64_t sc_regs[32];
2830 uint64_t sc_fpregs[32];
2831 uint64_t sc_mdhi;
2832 uint64_t sc_hi1;
2833 uint64_t sc_hi2;
2834 uint64_t sc_hi3;
2835 uint64_t sc_mdlo;
2836 uint64_t sc_lo1;
2837 uint64_t sc_lo2;
2838 uint64_t sc_lo3;
2839 uint64_t sc_pc;
2840 uint32_t sc_fpc_csr;
2841 uint32_t sc_used_math;
2842 uint32_t sc_dsp;
2843 uint32_t sc_reserved;
2844};
2845# endif /* O32 */
bellard106ec872006-06-27 21:08:10 +00002846
2847struct sigframe {
2848 uint32_t sf_ass[4]; /* argument save space for o32 */
2849 uint32_t sf_code[2]; /* signal trampoline */
2850 struct target_sigcontext sf_sc;
Anthony Liguoric227f092009-10-01 16:12:16 -05002851 target_sigset_t sf_mask;
bellard106ec872006-06-27 21:08:10 +00002852};
2853
pbrook0b1bcb02009-04-21 01:41:10 +00002854struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02002855 target_ulong tuc_flags;
2856 target_ulong tuc_link;
2857 target_stack_t tuc_stack;
Paul Brook94c54952009-07-09 18:40:15 +01002858 target_ulong pad0;
Aurelien Jarno60e99242010-03-29 02:12:51 +02002859 struct target_sigcontext tuc_mcontext;
2860 target_sigset_t tuc_sigmask;
pbrook0b1bcb02009-04-21 01:41:10 +00002861};
2862
2863struct target_rt_sigframe {
2864 uint32_t rs_ass[4]; /* argument save space for o32 */
2865 uint32_t rs_code[2]; /* signal trampoline */
2866 struct target_siginfo rs_info;
2867 struct target_ucontext rs_uc;
2868};
2869
bellard106ec872006-06-27 21:08:10 +00002870/* Install trampoline to jump back from signal handler */
2871static inline int install_sigtramp(unsigned int *tramp, unsigned int syscall)
2872{
Richard Henderson084d0492013-02-10 10:30:44 -08002873 int err = 0;
bellard106ec872006-06-27 21:08:10 +00002874
2875 /*
Richard Henderson084d0492013-02-10 10:30:44 -08002876 * Set up the return code ...
2877 *
2878 * li v0, __NR__foo_sigreturn
2879 * syscall
2880 */
bellard106ec872006-06-27 21:08:10 +00002881
Riku Voipio1d8b5122014-04-23 10:26:05 +03002882 __put_user(0x24020000 + syscall, tramp + 0);
2883 __put_user(0x0000000c , tramp + 1);
bellard106ec872006-06-27 21:08:10 +00002884 return err;
2885}
2886
Riku Voipio41ecc722014-04-23 11:01:00 +03002887static inline void setup_sigcontext(CPUMIPSState *regs,
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002888 struct target_sigcontext *sc)
bellard106ec872006-06-27 21:08:10 +00002889{
Richard Henderson084d0492013-02-10 10:30:44 -08002890 int i;
bellard106ec872006-06-27 21:08:10 +00002891
Riku Voipio1d8b5122014-04-23 10:26:05 +03002892 __put_user(exception_resume_pc(regs), &sc->sc_pc);
Kwok Cheung Yeung1239b472013-05-17 14:51:21 -07002893 regs->hflags &= ~MIPS_HFLAG_BMASK;
bellard106ec872006-06-27 21:08:10 +00002894
Richard Henderson084d0492013-02-10 10:30:44 -08002895 __put_user(0, &sc->sc_regs[0]);
2896 for (i = 1; i < 32; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002897 __put_user(regs->active_tc.gpr[i], &sc->sc_regs[i]);
Richard Henderson084d0492013-02-10 10:30:44 -08002898 }
bellard106ec872006-06-27 21:08:10 +00002899
Riku Voipio1d8b5122014-04-23 10:26:05 +03002900 __put_user(regs->active_tc.HI[0], &sc->sc_mdhi);
2901 __put_user(regs->active_tc.LO[0], &sc->sc_mdlo);
bellard106ec872006-06-27 21:08:10 +00002902
Richard Henderson084d0492013-02-10 10:30:44 -08002903 /* Rather than checking for dsp existence, always copy. The storage
2904 would just be garbage otherwise. */
Riku Voipio1d8b5122014-04-23 10:26:05 +03002905 __put_user(regs->active_tc.HI[1], &sc->sc_hi1);
2906 __put_user(regs->active_tc.HI[2], &sc->sc_hi2);
2907 __put_user(regs->active_tc.HI[3], &sc->sc_hi3);
2908 __put_user(regs->active_tc.LO[1], &sc->sc_lo1);
2909 __put_user(regs->active_tc.LO[2], &sc->sc_lo2);
2910 __put_user(regs->active_tc.LO[3], &sc->sc_lo3);
Richard Henderson084d0492013-02-10 10:30:44 -08002911 {
2912 uint32_t dsp = cpu_rddsp(0x3ff, regs);
Riku Voipio1d8b5122014-04-23 10:26:05 +03002913 __put_user(dsp, &sc->sc_dsp);
bellard106ec872006-06-27 21:08:10 +00002914 }
Richard Henderson084d0492013-02-10 10:30:44 -08002915
Riku Voipio1d8b5122014-04-23 10:26:05 +03002916 __put_user(1, &sc->sc_used_math);
Richard Henderson084d0492013-02-10 10:30:44 -08002917
2918 for (i = 0; i < 32; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002919 __put_user(regs->active_fpu.fpr[i].d, &sc->sc_fpregs[i]);
bellard106ec872006-06-27 21:08:10 +00002920 }
bellard106ec872006-06-27 21:08:10 +00002921}
2922
Riku Voipio016d2e12014-04-23 11:19:48 +03002923static inline void
Andreas Färber05390242012-02-25 03:37:53 +01002924restore_sigcontext(CPUMIPSState *regs, struct target_sigcontext *sc)
bellard106ec872006-06-27 21:08:10 +00002925{
Richard Henderson084d0492013-02-10 10:30:44 -08002926 int i;
bellard106ec872006-06-27 21:08:10 +00002927
Riku Voipio1d8b5122014-04-23 10:26:05 +03002928 __get_user(regs->CP0_EPC, &sc->sc_pc);
bellard106ec872006-06-27 21:08:10 +00002929
Riku Voipio1d8b5122014-04-23 10:26:05 +03002930 __get_user(regs->active_tc.HI[0], &sc->sc_mdhi);
2931 __get_user(regs->active_tc.LO[0], &sc->sc_mdlo);
bellard106ec872006-06-27 21:08:10 +00002932
Richard Henderson084d0492013-02-10 10:30:44 -08002933 for (i = 1; i < 32; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002934 __get_user(regs->active_tc.gpr[i], &sc->sc_regs[i]);
bellard106ec872006-06-27 21:08:10 +00002935 }
2936
Riku Voipio1d8b5122014-04-23 10:26:05 +03002937 __get_user(regs->active_tc.HI[1], &sc->sc_hi1);
2938 __get_user(regs->active_tc.HI[2], &sc->sc_hi2);
2939 __get_user(regs->active_tc.HI[3], &sc->sc_hi3);
2940 __get_user(regs->active_tc.LO[1], &sc->sc_lo1);
2941 __get_user(regs->active_tc.LO[2], &sc->sc_lo2);
2942 __get_user(regs->active_tc.LO[3], &sc->sc_lo3);
Richard Henderson084d0492013-02-10 10:30:44 -08002943 {
2944 uint32_t dsp;
Riku Voipio1d8b5122014-04-23 10:26:05 +03002945 __get_user(dsp, &sc->sc_dsp);
Richard Henderson084d0492013-02-10 10:30:44 -08002946 cpu_wrdsp(dsp, 0x3ff, regs);
2947 }
2948
2949 for (i = 0; i < 32; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002950 __get_user(regs->active_fpu.fpr[i].d, &sc->sc_fpregs[i]);
Richard Henderson084d0492013-02-10 10:30:44 -08002951 }
bellard106ec872006-06-27 21:08:10 +00002952}
Richard Hendersonff970902013-02-10 10:30:42 -08002953
bellard106ec872006-06-27 21:08:10 +00002954/*
2955 * Determine which stack to use..
2956 */
bellard579a97f2007-11-11 14:26:47 +00002957static inline abi_ulong
Andreas Färber05390242012-02-25 03:37:53 +01002958get_sigframe(struct target_sigaction *ka, CPUMIPSState *regs, size_t frame_size)
bellard106ec872006-06-27 21:08:10 +00002959{
2960 unsigned long sp;
2961
2962 /* Default to using normal stack */
thsb5dc7732008-06-27 10:02:35 +00002963 sp = regs->active_tc.gpr[29];
bellard106ec872006-06-27 21:08:10 +00002964
2965 /*
Stefan Weil93148aa2012-02-26 18:46:12 +01002966 * FPU emulator may have its own trampoline active just
bellard106ec872006-06-27 21:08:10 +00002967 * above the user stack, 16-bytes before the next lowest
2968 * 16 byte boundary. Try to avoid trashing it.
2969 */
2970 sp -= 32;
2971
bellard106ec872006-06-27 21:08:10 +00002972 /* This is the X/Open sanctioned signal stack switching. */
pbrook624f7972008-05-31 16:11:38 +00002973 if ((ka->sa_flags & TARGET_SA_ONSTACK) && (sas_ss_flags (sp) == 0)) {
thsa04e1342007-09-27 13:57:58 +00002974 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
2975 }
bellard106ec872006-06-27 21:08:10 +00002976
bellard579a97f2007-11-11 14:26:47 +00002977 return (sp - frame_size) & ~7;
bellard106ec872006-06-27 21:08:10 +00002978}
2979
Kwok Cheung Yeungea3164a2013-05-17 14:51:20 -07002980static void mips_set_hflags_isa_mode_from_pc(CPUMIPSState *env)
2981{
2982 if (env->insn_flags & (ASE_MIPS16 | ASE_MICROMIPS)) {
2983 env->hflags &= ~MIPS_HFLAG_M16;
2984 env->hflags |= (env->active_tc.PC & 1) << MIPS_HFLAG_M16_SHIFT;
2985 env->active_tc.PC &= ~(target_ulong) 1;
2986 }
2987}
2988
Richard Hendersonff970902013-02-10 10:30:42 -08002989# if defined(TARGET_ABI_MIPSO32)
bellard579a97f2007-11-11 14:26:47 +00002990/* compare linux/arch/mips/kernel/signal.c:setup_frame() */
pbrook624f7972008-05-31 16:11:38 +00002991static void setup_frame(int sig, struct target_sigaction * ka,
Andreas Färber05390242012-02-25 03:37:53 +01002992 target_sigset_t *set, CPUMIPSState *regs)
bellard106ec872006-06-27 21:08:10 +00002993{
2994 struct sigframe *frame;
bellard579a97f2007-11-11 14:26:47 +00002995 abi_ulong frame_addr;
bellard106ec872006-06-27 21:08:10 +00002996 int i;
2997
bellard579a97f2007-11-11 14:26:47 +00002998 frame_addr = get_sigframe(ka, regs, sizeof(*frame));
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01002999 trace_user_setup_frame(regs, frame_addr);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003000 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
3001 goto give_sigsegv;
3002 }
bellard106ec872006-06-27 21:08:10 +00003003
3004 install_sigtramp(frame->sf_code, TARGET_NR_sigreturn);
3005
Riku Voipio41ecc722014-04-23 11:01:00 +03003006 setup_sigcontext(regs, &frame->sf_sc);
bellard106ec872006-06-27 21:08:10 +00003007
3008 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
Riku Voipio0188fad2014-04-23 13:34:15 +03003009 __put_user(set->sig[i], &frame->sf_mask.sig[i]);
bellard106ec872006-06-27 21:08:10 +00003010 }
3011
3012 /*
3013 * Arguments to signal handler:
3014 *
3015 * a0 = signal number
3016 * a1 = 0 (should be cause)
3017 * a2 = pointer to struct sigcontext
3018 *
3019 * $25 and PC point to the signal handler, $29 points to the
3020 * struct sigframe.
3021 */
thsb5dc7732008-06-27 10:02:35 +00003022 regs->active_tc.gpr[ 4] = sig;
3023 regs->active_tc.gpr[ 5] = 0;
3024 regs->active_tc.gpr[ 6] = frame_addr + offsetof(struct sigframe, sf_sc);
3025 regs->active_tc.gpr[29] = frame_addr;
3026 regs->active_tc.gpr[31] = frame_addr + offsetof(struct sigframe, sf_code);
bellard106ec872006-06-27 21:08:10 +00003027 /* The original kernel code sets CP0_EPC to the handler
3028 * since it returns to userland using eret
3029 * we cannot do this here, and we must set PC directly */
thsb5dc7732008-06-27 10:02:35 +00003030 regs->active_tc.PC = regs->active_tc.gpr[25] = ka->_sa_handler;
Kwok Cheung Yeungea3164a2013-05-17 14:51:20 -07003031 mips_set_hflags_isa_mode_from_pc(regs);
bellard579a97f2007-11-11 14:26:47 +00003032 unlock_user_struct(frame, frame_addr, 1);
bellard106ec872006-06-27 21:08:10 +00003033 return;
3034
3035give_sigsegv:
3036 force_sig(TARGET_SIGSEGV/*, current*/);
bellard106ec872006-06-27 21:08:10 +00003037}
3038
Andreas Färber05390242012-02-25 03:37:53 +01003039long do_sigreturn(CPUMIPSState *regs)
bellard106ec872006-06-27 21:08:10 +00003040{
ths388bb212007-05-13 13:58:00 +00003041 struct sigframe *frame;
bellard579a97f2007-11-11 14:26:47 +00003042 abi_ulong frame_addr;
ths388bb212007-05-13 13:58:00 +00003043 sigset_t blocked;
Anthony Liguoric227f092009-10-01 16:12:16 -05003044 target_sigset_t target_set;
ths388bb212007-05-13 13:58:00 +00003045 int i;
bellard106ec872006-06-27 21:08:10 +00003046
thsb5dc7732008-06-27 10:02:35 +00003047 frame_addr = regs->active_tc.gpr[29];
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01003048 trace_user_do_sigreturn(regs, frame_addr);
bellard579a97f2007-11-11 14:26:47 +00003049 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003050 goto badframe;
bellard106ec872006-06-27 21:08:10 +00003051
ths388bb212007-05-13 13:58:00 +00003052 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
Riku Voipiof5f601a2014-04-23 13:00:17 +03003053 __get_user(target_set.sig[i], &frame->sf_mask.sig[i]);
ths388bb212007-05-13 13:58:00 +00003054 }
bellard106ec872006-06-27 21:08:10 +00003055
ths388bb212007-05-13 13:58:00 +00003056 target_to_host_sigset_internal(&blocked, &target_set);
Peter Maydell9eede5b2016-05-27 15:51:46 +01003057 set_sigmask(&blocked);
bellard106ec872006-06-27 21:08:10 +00003058
Riku Voipio016d2e12014-04-23 11:19:48 +03003059 restore_sigcontext(regs, &frame->sf_sc);
bellard106ec872006-06-27 21:08:10 +00003060
3061#if 0
ths388bb212007-05-13 13:58:00 +00003062 /*
3063 * Don't let your children do this ...
3064 */
3065 __asm__ __volatile__(
bellard106ec872006-06-27 21:08:10 +00003066 "move\t$29, %0\n\t"
3067 "j\tsyscall_exit"
3068 :/* no outputs */
3069 :"r" (&regs));
ths388bb212007-05-13 13:58:00 +00003070 /* Unreached */
bellard106ec872006-06-27 21:08:10 +00003071#endif
ths3b46e622007-09-17 08:09:54 +00003072
thsb5dc7732008-06-27 10:02:35 +00003073 regs->active_tc.PC = regs->CP0_EPC;
Kwok Cheung Yeungea3164a2013-05-17 14:51:20 -07003074 mips_set_hflags_isa_mode_from_pc(regs);
ths388bb212007-05-13 13:58:00 +00003075 /* I am not sure this is right, but it seems to work
bellard106ec872006-06-27 21:08:10 +00003076 * maybe a problem with nested signals ? */
3077 regs->CP0_EPC = 0;
pbrook0b1bcb02009-04-21 01:41:10 +00003078 return -TARGET_QEMU_ESIGRETURN;
bellard106ec872006-06-27 21:08:10 +00003079
3080badframe:
ths388bb212007-05-13 13:58:00 +00003081 force_sig(TARGET_SIGSEGV/*, current*/);
3082 return 0;
bellard106ec872006-06-27 21:08:10 +00003083}
Richard Hendersonff970902013-02-10 10:30:42 -08003084# endif /* O32 */
bellard106ec872006-06-27 21:08:10 +00003085
pbrook624f7972008-05-31 16:11:38 +00003086static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05003087 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01003088 target_sigset_t *set, CPUMIPSState *env)
bellard106ec872006-06-27 21:08:10 +00003089{
pbrook0b1bcb02009-04-21 01:41:10 +00003090 struct target_rt_sigframe *frame;
3091 abi_ulong frame_addr;
3092 int i;
3093
3094 frame_addr = get_sigframe(ka, env, sizeof(*frame));
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01003095 trace_user_setup_rt_frame(env, frame_addr);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003096 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
3097 goto give_sigsegv;
3098 }
pbrook0b1bcb02009-04-21 01:41:10 +00003099
3100 install_sigtramp(frame->rs_code, TARGET_NR_rt_sigreturn);
3101
Peter Maydellf6c7a052015-01-08 12:19:48 +00003102 tswap_siginfo(&frame->rs_info, info);
pbrook0b1bcb02009-04-21 01:41:10 +00003103
Aurelien Jarno60e99242010-03-29 02:12:51 +02003104 __put_user(0, &frame->rs_uc.tuc_flags);
3105 __put_user(0, &frame->rs_uc.tuc_link);
3106 __put_user(target_sigaltstack_used.ss_sp, &frame->rs_uc.tuc_stack.ss_sp);
3107 __put_user(target_sigaltstack_used.ss_size, &frame->rs_uc.tuc_stack.ss_size);
pbrook0b1bcb02009-04-21 01:41:10 +00003108 __put_user(sas_ss_flags(get_sp_from_cpustate(env)),
Aurelien Jarno60e99242010-03-29 02:12:51 +02003109 &frame->rs_uc.tuc_stack.ss_flags);
pbrook0b1bcb02009-04-21 01:41:10 +00003110
Aurelien Jarno60e99242010-03-29 02:12:51 +02003111 setup_sigcontext(env, &frame->rs_uc.tuc_mcontext);
pbrook0b1bcb02009-04-21 01:41:10 +00003112
3113 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
Aurelien Jarno60e99242010-03-29 02:12:51 +02003114 __put_user(set->sig[i], &frame->rs_uc.tuc_sigmask.sig[i]);
pbrook0b1bcb02009-04-21 01:41:10 +00003115 }
3116
3117 /*
3118 * Arguments to signal handler:
3119 *
3120 * a0 = signal number
Richard W.M. Jones02d2bd52012-07-05 03:32:44 +00003121 * a1 = pointer to siginfo_t
pbrook0b1bcb02009-04-21 01:41:10 +00003122 * a2 = pointer to struct ucontext
3123 *
3124 * $25 and PC point to the signal handler, $29 points to the
3125 * struct sigframe.
3126 */
3127 env->active_tc.gpr[ 4] = sig;
3128 env->active_tc.gpr[ 5] = frame_addr
3129 + offsetof(struct target_rt_sigframe, rs_info);
3130 env->active_tc.gpr[ 6] = frame_addr
3131 + offsetof(struct target_rt_sigframe, rs_uc);
3132 env->active_tc.gpr[29] = frame_addr;
3133 env->active_tc.gpr[31] = frame_addr
3134 + offsetof(struct target_rt_sigframe, rs_code);
3135 /* The original kernel code sets CP0_EPC to the handler
3136 * since it returns to userland using eret
3137 * we cannot do this here, and we must set PC directly */
3138 env->active_tc.PC = env->active_tc.gpr[25] = ka->_sa_handler;
Kwok Cheung Yeungea3164a2013-05-17 14:51:20 -07003139 mips_set_hflags_isa_mode_from_pc(env);
pbrook0b1bcb02009-04-21 01:41:10 +00003140 unlock_user_struct(frame, frame_addr, 1);
3141 return;
3142
3143give_sigsegv:
3144 unlock_user_struct(frame, frame_addr, 1);
3145 force_sig(TARGET_SIGSEGV/*, current*/);
bellard106ec872006-06-27 21:08:10 +00003146}
3147
Andreas Färber05390242012-02-25 03:37:53 +01003148long do_rt_sigreturn(CPUMIPSState *env)
bellard106ec872006-06-27 21:08:10 +00003149{
pbrook0b1bcb02009-04-21 01:41:10 +00003150 struct target_rt_sigframe *frame;
3151 abi_ulong frame_addr;
3152 sigset_t blocked;
3153
pbrook0b1bcb02009-04-21 01:41:10 +00003154 frame_addr = env->active_tc.gpr[29];
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01003155 trace_user_do_rt_sigreturn(env, frame_addr);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003156 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
3157 goto badframe;
3158 }
pbrook0b1bcb02009-04-21 01:41:10 +00003159
Aurelien Jarno60e99242010-03-29 02:12:51 +02003160 target_to_host_sigset(&blocked, &frame->rs_uc.tuc_sigmask);
Peter Maydell9eede5b2016-05-27 15:51:46 +01003161 set_sigmask(&blocked);
pbrook0b1bcb02009-04-21 01:41:10 +00003162
Riku Voipio016d2e12014-04-23 11:19:48 +03003163 restore_sigcontext(env, &frame->rs_uc.tuc_mcontext);
pbrook0b1bcb02009-04-21 01:41:10 +00003164
3165 if (do_sigaltstack(frame_addr +
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003166 offsetof(struct target_rt_sigframe, rs_uc.tuc_stack),
3167 0, get_sp_from_cpustate(env)) == -EFAULT)
pbrook0b1bcb02009-04-21 01:41:10 +00003168 goto badframe;
3169
3170 env->active_tc.PC = env->CP0_EPC;
Kwok Cheung Yeungea3164a2013-05-17 14:51:20 -07003171 mips_set_hflags_isa_mode_from_pc(env);
pbrook0b1bcb02009-04-21 01:41:10 +00003172 /* I am not sure this is right, but it seems to work
3173 * maybe a problem with nested signals ? */
3174 env->CP0_EPC = 0;
3175 return -TARGET_QEMU_ESIGRETURN;
3176
3177badframe:
3178 force_sig(TARGET_SIGSEGV/*, current*/);
3179 return 0;
bellard106ec872006-06-27 21:08:10 +00003180}
bellard6d5e2162004-09-30 22:04:13 +00003181
thsc3b5bc82007-12-02 06:31:25 +00003182#elif defined(TARGET_SH4)
3183
3184/*
3185 * code and data structures from linux kernel:
3186 * include/asm-sh/sigcontext.h
3187 * arch/sh/kernel/signal.c
3188 */
3189
3190struct target_sigcontext {
3191 target_ulong oldmask;
3192
3193 /* CPU registers */
3194 target_ulong sc_gregs[16];
3195 target_ulong sc_pc;
3196 target_ulong sc_pr;
3197 target_ulong sc_sr;
3198 target_ulong sc_gbr;
3199 target_ulong sc_mach;
3200 target_ulong sc_macl;
3201
3202 /* FPU registers */
3203 target_ulong sc_fpregs[16];
3204 target_ulong sc_xfpregs[16];
3205 unsigned int sc_fpscr;
3206 unsigned int sc_fpul;
3207 unsigned int sc_ownedfp;
3208};
3209
3210struct target_sigframe
3211{
3212 struct target_sigcontext sc;
3213 target_ulong extramask[TARGET_NSIG_WORDS-1];
3214 uint16_t retcode[3];
3215};
3216
3217
3218struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02003219 target_ulong tuc_flags;
3220 struct target_ucontext *tuc_link;
3221 target_stack_t tuc_stack;
3222 struct target_sigcontext tuc_mcontext;
3223 target_sigset_t tuc_sigmask; /* mask last for extensibility */
thsc3b5bc82007-12-02 06:31:25 +00003224};
3225
3226struct target_rt_sigframe
3227{
3228 struct target_siginfo info;
3229 struct target_ucontext uc;
3230 uint16_t retcode[3];
3231};
3232
3233
3234#define MOVW(n) (0x9300|((n)-2)) /* Move mem word at PC+n to R3 */
3235#define TRAP_NOARG 0xc310 /* Syscall w/no args (NR in R3) SH3/4 */
3236
pbrook624f7972008-05-31 16:11:38 +00003237static abi_ulong get_sigframe(struct target_sigaction *ka,
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003238 unsigned long sp, size_t frame_size)
thsc3b5bc82007-12-02 06:31:25 +00003239{
pbrook624f7972008-05-31 16:11:38 +00003240 if ((ka->sa_flags & TARGET_SA_ONSTACK) && (sas_ss_flags(sp) == 0)) {
thsc3b5bc82007-12-02 06:31:25 +00003241 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
3242 }
3243
3244 return (sp - frame_size) & -8ul;
3245}
3246
Riku Voipio41ecc722014-04-23 11:01:00 +03003247static void setup_sigcontext(struct target_sigcontext *sc,
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003248 CPUSH4State *regs, unsigned long mask)
thsc3b5bc82007-12-02 06:31:25 +00003249{
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003250 int i;
thsc3b5bc82007-12-02 06:31:25 +00003251
Riku Voipio1d8b5122014-04-23 10:26:05 +03003252#define COPY(x) __put_user(regs->x, &sc->sc_##x)
thsc3b5bc82007-12-02 06:31:25 +00003253 COPY(gregs[0]); COPY(gregs[1]);
3254 COPY(gregs[2]); COPY(gregs[3]);
3255 COPY(gregs[4]); COPY(gregs[5]);
3256 COPY(gregs[6]); COPY(gregs[7]);
3257 COPY(gregs[8]); COPY(gregs[9]);
3258 COPY(gregs[10]); COPY(gregs[11]);
3259 COPY(gregs[12]); COPY(gregs[13]);
3260 COPY(gregs[14]); COPY(gregs[15]);
3261 COPY(gbr); COPY(mach);
3262 COPY(macl); COPY(pr);
3263 COPY(sr); COPY(pc);
3264#undef COPY
3265
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003266 for (i=0; i<16; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03003267 __put_user(regs->fregs[i], &sc->sc_fpregs[i]);
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003268 }
Riku Voipio1d8b5122014-04-23 10:26:05 +03003269 __put_user(regs->fpscr, &sc->sc_fpscr);
3270 __put_user(regs->fpul, &sc->sc_fpul);
thsc3b5bc82007-12-02 06:31:25 +00003271
3272 /* non-iBCS2 extensions.. */
Riku Voipio1d8b5122014-04-23 10:26:05 +03003273 __put_user(mask, &sc->oldmask);
thsc3b5bc82007-12-02 06:31:25 +00003274}
3275
Timothy E Baldwinba412492016-05-12 18:47:35 +01003276static void restore_sigcontext(CPUSH4State *regs, struct target_sigcontext *sc)
thsc3b5bc82007-12-02 06:31:25 +00003277{
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003278 int i;
thsc3b5bc82007-12-02 06:31:25 +00003279
Riku Voipio1d8b5122014-04-23 10:26:05 +03003280#define COPY(x) __get_user(regs->x, &sc->sc_##x)
Timothy E Baldwinba412492016-05-12 18:47:35 +01003281 COPY(gregs[0]); COPY(gregs[1]);
thsc3b5bc82007-12-02 06:31:25 +00003282 COPY(gregs[2]); COPY(gregs[3]);
3283 COPY(gregs[4]); COPY(gregs[5]);
3284 COPY(gregs[6]); COPY(gregs[7]);
3285 COPY(gregs[8]); COPY(gregs[9]);
3286 COPY(gregs[10]); COPY(gregs[11]);
3287 COPY(gregs[12]); COPY(gregs[13]);
3288 COPY(gregs[14]); COPY(gregs[15]);
3289 COPY(gbr); COPY(mach);
3290 COPY(macl); COPY(pr);
3291 COPY(sr); COPY(pc);
3292#undef COPY
3293
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003294 for (i=0; i<16; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03003295 __get_user(regs->fregs[i], &sc->sc_fpregs[i]);
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003296 }
Riku Voipio1d8b5122014-04-23 10:26:05 +03003297 __get_user(regs->fpscr, &sc->sc_fpscr);
3298 __get_user(regs->fpul, &sc->sc_fpul);
thsc3b5bc82007-12-02 06:31:25 +00003299
3300 regs->tra = -1; /* disable syscall checks */
thsc3b5bc82007-12-02 06:31:25 +00003301}
3302
pbrook624f7972008-05-31 16:11:38 +00003303static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01003304 target_sigset_t *set, CPUSH4State *regs)
thsc3b5bc82007-12-02 06:31:25 +00003305{
3306 struct target_sigframe *frame;
3307 abi_ulong frame_addr;
3308 int i;
thsc3b5bc82007-12-02 06:31:25 +00003309
3310 frame_addr = get_sigframe(ka, regs->gregs[15], sizeof(*frame));
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01003311 trace_user_setup_frame(regs, frame_addr);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003312 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
3313 goto give_sigsegv;
3314 }
thsc3b5bc82007-12-02 06:31:25 +00003315
Riku Voipio41ecc722014-04-23 11:01:00 +03003316 setup_sigcontext(&frame->sc, regs, set->sig[0]);
thsc3b5bc82007-12-02 06:31:25 +00003317
3318 for (i = 0; i < TARGET_NSIG_WORDS - 1; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03003319 __put_user(set->sig[i + 1], &frame->extramask[i]);
thsc3b5bc82007-12-02 06:31:25 +00003320 }
3321
3322 /* Set up to return from userspace. If provided, use a stub
3323 already in userspace. */
pbrook624f7972008-05-31 16:11:38 +00003324 if (ka->sa_flags & TARGET_SA_RESTORER) {
3325 regs->pr = (unsigned long) ka->sa_restorer;
thsc3b5bc82007-12-02 06:31:25 +00003326 } else {
3327 /* Generate return code (system call to sigreturn) */
Laurent Vivier2a0fa682015-11-23 11:38:26 +01003328 abi_ulong retcode_addr = frame_addr +
3329 offsetof(struct target_sigframe, retcode);
Riku Voipio1d8b5122014-04-23 10:26:05 +03003330 __put_user(MOVW(2), &frame->retcode[0]);
3331 __put_user(TRAP_NOARG, &frame->retcode[1]);
3332 __put_user((TARGET_NR_sigreturn), &frame->retcode[2]);
Laurent Vivier2a0fa682015-11-23 11:38:26 +01003333 regs->pr = (unsigned long) retcode_addr;
thsc3b5bc82007-12-02 06:31:25 +00003334 }
3335
thsc3b5bc82007-12-02 06:31:25 +00003336 /* Set up registers for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003337 regs->gregs[15] = frame_addr;
Peter Maydellb6e2c932015-01-08 12:19:43 +00003338 regs->gregs[4] = sig; /* Arg for signal handler */
thsc3b5bc82007-12-02 06:31:25 +00003339 regs->gregs[5] = 0;
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003340 regs->gregs[6] = frame_addr += offsetof(typeof(*frame), sc);
pbrook624f7972008-05-31 16:11:38 +00003341 regs->pc = (unsigned long) ka->_sa_handler;
thsc3b5bc82007-12-02 06:31:25 +00003342
3343 unlock_user_struct(frame, frame_addr, 1);
3344 return;
3345
3346give_sigsegv:
3347 unlock_user_struct(frame, frame_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02003348 force_sig(TARGET_SIGSEGV);
thsc3b5bc82007-12-02 06:31:25 +00003349}
3350
pbrook624f7972008-05-31 16:11:38 +00003351static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05003352 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01003353 target_sigset_t *set, CPUSH4State *regs)
thsc3b5bc82007-12-02 06:31:25 +00003354{
3355 struct target_rt_sigframe *frame;
3356 abi_ulong frame_addr;
3357 int i;
thsc3b5bc82007-12-02 06:31:25 +00003358
3359 frame_addr = get_sigframe(ka, regs->gregs[15], sizeof(*frame));
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01003360 trace_user_setup_rt_frame(regs, frame_addr);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003361 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
3362 goto give_sigsegv;
3363 }
thsc3b5bc82007-12-02 06:31:25 +00003364
Peter Maydellf6c7a052015-01-08 12:19:48 +00003365 tswap_siginfo(&frame->info, info);
thsc3b5bc82007-12-02 06:31:25 +00003366
3367 /* Create the ucontext. */
Riku Voipio1d8b5122014-04-23 10:26:05 +03003368 __put_user(0, &frame->uc.tuc_flags);
3369 __put_user(0, (unsigned long *)&frame->uc.tuc_link);
3370 __put_user((unsigned long)target_sigaltstack_used.ss_sp,
3371 &frame->uc.tuc_stack.ss_sp);
3372 __put_user(sas_ss_flags(regs->gregs[15]),
3373 &frame->uc.tuc_stack.ss_flags);
3374 __put_user(target_sigaltstack_used.ss_size,
3375 &frame->uc.tuc_stack.ss_size);
3376 setup_sigcontext(&frame->uc.tuc_mcontext,
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003377 regs, set->sig[0]);
thsc3b5bc82007-12-02 06:31:25 +00003378 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03003379 __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
thsc3b5bc82007-12-02 06:31:25 +00003380 }
3381
3382 /* Set up to return from userspace. If provided, use a stub
3383 already in userspace. */
pbrook624f7972008-05-31 16:11:38 +00003384 if (ka->sa_flags & TARGET_SA_RESTORER) {
3385 regs->pr = (unsigned long) ka->sa_restorer;
thsc3b5bc82007-12-02 06:31:25 +00003386 } else {
3387 /* Generate return code (system call to sigreturn) */
Laurent Vivier2a0fa682015-11-23 11:38:26 +01003388 abi_ulong retcode_addr = frame_addr +
3389 offsetof(struct target_rt_sigframe, retcode);
Riku Voipio1d8b5122014-04-23 10:26:05 +03003390 __put_user(MOVW(2), &frame->retcode[0]);
3391 __put_user(TRAP_NOARG, &frame->retcode[1]);
3392 __put_user((TARGET_NR_rt_sigreturn), &frame->retcode[2]);
Laurent Vivier2a0fa682015-11-23 11:38:26 +01003393 regs->pr = (unsigned long) retcode_addr;
thsc3b5bc82007-12-02 06:31:25 +00003394 }
3395
thsc3b5bc82007-12-02 06:31:25 +00003396 /* Set up registers for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003397 regs->gregs[15] = frame_addr;
Peter Maydellb6e2c932015-01-08 12:19:43 +00003398 regs->gregs[4] = sig; /* Arg for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003399 regs->gregs[5] = frame_addr + offsetof(typeof(*frame), info);
3400 regs->gregs[6] = frame_addr + offsetof(typeof(*frame), uc);
pbrook624f7972008-05-31 16:11:38 +00003401 regs->pc = (unsigned long) ka->_sa_handler;
thsc3b5bc82007-12-02 06:31:25 +00003402
3403 unlock_user_struct(frame, frame_addr, 1);
3404 return;
3405
3406give_sigsegv:
3407 unlock_user_struct(frame, frame_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02003408 force_sig(TARGET_SIGSEGV);
thsc3b5bc82007-12-02 06:31:25 +00003409}
3410
Andreas Färber05390242012-02-25 03:37:53 +01003411long do_sigreturn(CPUSH4State *regs)
thsc3b5bc82007-12-02 06:31:25 +00003412{
3413 struct target_sigframe *frame;
3414 abi_ulong frame_addr;
3415 sigset_t blocked;
Anthony Liguoric227f092009-10-01 16:12:16 -05003416 target_sigset_t target_set;
thsc3b5bc82007-12-02 06:31:25 +00003417 int i;
3418 int err = 0;
3419
thsc3b5bc82007-12-02 06:31:25 +00003420 frame_addr = regs->gregs[15];
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01003421 trace_user_do_sigreturn(regs, frame_addr);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003422 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
3423 goto badframe;
3424 }
thsc3b5bc82007-12-02 06:31:25 +00003425
Riku Voipio1d8b5122014-04-23 10:26:05 +03003426 __get_user(target_set.sig[0], &frame->sc.oldmask);
thsc3b5bc82007-12-02 06:31:25 +00003427 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03003428 __get_user(target_set.sig[i], &frame->extramask[i - 1]);
thsc3b5bc82007-12-02 06:31:25 +00003429 }
3430
3431 if (err)
3432 goto badframe;
3433
3434 target_to_host_sigset_internal(&blocked, &target_set);
Peter Maydell9eede5b2016-05-27 15:51:46 +01003435 set_sigmask(&blocked);
thsc3b5bc82007-12-02 06:31:25 +00003436
Timothy E Baldwinba412492016-05-12 18:47:35 +01003437 restore_sigcontext(regs, &frame->sc);
thsc3b5bc82007-12-02 06:31:25 +00003438
3439 unlock_user_struct(frame, frame_addr, 0);
Timothy E Baldwinba412492016-05-12 18:47:35 +01003440 return -TARGET_QEMU_ESIGRETURN;
thsc3b5bc82007-12-02 06:31:25 +00003441
3442badframe:
3443 unlock_user_struct(frame, frame_addr, 0);
3444 force_sig(TARGET_SIGSEGV);
3445 return 0;
3446}
3447
Andreas Färber05390242012-02-25 03:37:53 +01003448long do_rt_sigreturn(CPUSH4State *regs)
thsc3b5bc82007-12-02 06:31:25 +00003449{
3450 struct target_rt_sigframe *frame;
3451 abi_ulong frame_addr;
3452 sigset_t blocked;
3453
thsc3b5bc82007-12-02 06:31:25 +00003454 frame_addr = regs->gregs[15];
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01003455 trace_user_do_rt_sigreturn(regs, frame_addr);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003456 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
3457 goto badframe;
3458 }
thsc3b5bc82007-12-02 06:31:25 +00003459
Aurelien Jarno60e99242010-03-29 02:12:51 +02003460 target_to_host_sigset(&blocked, &frame->uc.tuc_sigmask);
Peter Maydell9eede5b2016-05-27 15:51:46 +01003461 set_sigmask(&blocked);
thsc3b5bc82007-12-02 06:31:25 +00003462
Timothy E Baldwinba412492016-05-12 18:47:35 +01003463 restore_sigcontext(regs, &frame->uc.tuc_mcontext);
thsc3b5bc82007-12-02 06:31:25 +00003464
3465 if (do_sigaltstack(frame_addr +
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003466 offsetof(struct target_rt_sigframe, uc.tuc_stack),
3467 0, get_sp_from_cpustate(regs)) == -EFAULT) {
thsc3b5bc82007-12-02 06:31:25 +00003468 goto badframe;
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003469 }
thsc3b5bc82007-12-02 06:31:25 +00003470
3471 unlock_user_struct(frame, frame_addr, 0);
Timothy E Baldwinba412492016-05-12 18:47:35 +01003472 return -TARGET_QEMU_ESIGRETURN;
thsc3b5bc82007-12-02 06:31:25 +00003473
3474badframe:
3475 unlock_user_struct(frame, frame_addr, 0);
3476 force_sig(TARGET_SIGSEGV);
3477 return 0;
3478}
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003479#elif defined(TARGET_MICROBLAZE)
3480
3481struct target_sigcontext {
3482 struct target_pt_regs regs; /* needs to be first */
3483 uint32_t oldmask;
3484};
3485
Edgar E. Iglesiasb2178702010-07-23 09:30:37 +02003486struct target_stack_t {
3487 abi_ulong ss_sp;
3488 int ss_flags;
3489 unsigned int ss_size;
3490};
3491
3492struct target_ucontext {
Richard Hendersonf711df62010-11-22 14:57:52 -08003493 abi_ulong tuc_flags;
3494 abi_ulong tuc_link;
3495 struct target_stack_t tuc_stack;
3496 struct target_sigcontext tuc_mcontext;
3497 uint32_t tuc_extramask[TARGET_NSIG_WORDS - 1];
Edgar E. Iglesiasb2178702010-07-23 09:30:37 +02003498};
3499
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003500/* Signal frames. */
3501struct target_signal_frame {
Edgar E. Iglesiasb2178702010-07-23 09:30:37 +02003502 struct target_ucontext uc;
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003503 uint32_t extramask[TARGET_NSIG_WORDS - 1];
3504 uint32_t tramp[2];
3505};
3506
3507struct rt_signal_frame {
Richard W.M. Jones02d2bd52012-07-05 03:32:44 +00003508 siginfo_t info;
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003509 struct ucontext uc;
3510 uint32_t tramp[2];
3511};
3512
Andreas Färber05390242012-02-25 03:37:53 +01003513static void setup_sigcontext(struct target_sigcontext *sc, CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003514{
3515 __put_user(env->regs[0], &sc->regs.r0);
3516 __put_user(env->regs[1], &sc->regs.r1);
3517 __put_user(env->regs[2], &sc->regs.r2);
3518 __put_user(env->regs[3], &sc->regs.r3);
3519 __put_user(env->regs[4], &sc->regs.r4);
3520 __put_user(env->regs[5], &sc->regs.r5);
3521 __put_user(env->regs[6], &sc->regs.r6);
3522 __put_user(env->regs[7], &sc->regs.r7);
3523 __put_user(env->regs[8], &sc->regs.r8);
3524 __put_user(env->regs[9], &sc->regs.r9);
3525 __put_user(env->regs[10], &sc->regs.r10);
3526 __put_user(env->regs[11], &sc->regs.r11);
3527 __put_user(env->regs[12], &sc->regs.r12);
3528 __put_user(env->regs[13], &sc->regs.r13);
3529 __put_user(env->regs[14], &sc->regs.r14);
3530 __put_user(env->regs[15], &sc->regs.r15);
3531 __put_user(env->regs[16], &sc->regs.r16);
3532 __put_user(env->regs[17], &sc->regs.r17);
3533 __put_user(env->regs[18], &sc->regs.r18);
3534 __put_user(env->regs[19], &sc->regs.r19);
3535 __put_user(env->regs[20], &sc->regs.r20);
3536 __put_user(env->regs[21], &sc->regs.r21);
3537 __put_user(env->regs[22], &sc->regs.r22);
3538 __put_user(env->regs[23], &sc->regs.r23);
3539 __put_user(env->regs[24], &sc->regs.r24);
3540 __put_user(env->regs[25], &sc->regs.r25);
3541 __put_user(env->regs[26], &sc->regs.r26);
3542 __put_user(env->regs[27], &sc->regs.r27);
3543 __put_user(env->regs[28], &sc->regs.r28);
3544 __put_user(env->regs[29], &sc->regs.r29);
3545 __put_user(env->regs[30], &sc->regs.r30);
3546 __put_user(env->regs[31], &sc->regs.r31);
3547 __put_user(env->sregs[SR_PC], &sc->regs.pc);
3548}
3549
Andreas Färber05390242012-02-25 03:37:53 +01003550static void restore_sigcontext(struct target_sigcontext *sc, CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003551{
3552 __get_user(env->regs[0], &sc->regs.r0);
3553 __get_user(env->regs[1], &sc->regs.r1);
3554 __get_user(env->regs[2], &sc->regs.r2);
3555 __get_user(env->regs[3], &sc->regs.r3);
3556 __get_user(env->regs[4], &sc->regs.r4);
3557 __get_user(env->regs[5], &sc->regs.r5);
3558 __get_user(env->regs[6], &sc->regs.r6);
3559 __get_user(env->regs[7], &sc->regs.r7);
3560 __get_user(env->regs[8], &sc->regs.r8);
3561 __get_user(env->regs[9], &sc->regs.r9);
3562 __get_user(env->regs[10], &sc->regs.r10);
3563 __get_user(env->regs[11], &sc->regs.r11);
3564 __get_user(env->regs[12], &sc->regs.r12);
3565 __get_user(env->regs[13], &sc->regs.r13);
3566 __get_user(env->regs[14], &sc->regs.r14);
3567 __get_user(env->regs[15], &sc->regs.r15);
3568 __get_user(env->regs[16], &sc->regs.r16);
3569 __get_user(env->regs[17], &sc->regs.r17);
3570 __get_user(env->regs[18], &sc->regs.r18);
3571 __get_user(env->regs[19], &sc->regs.r19);
3572 __get_user(env->regs[20], &sc->regs.r20);
3573 __get_user(env->regs[21], &sc->regs.r21);
3574 __get_user(env->regs[22], &sc->regs.r22);
3575 __get_user(env->regs[23], &sc->regs.r23);
3576 __get_user(env->regs[24], &sc->regs.r24);
3577 __get_user(env->regs[25], &sc->regs.r25);
3578 __get_user(env->regs[26], &sc->regs.r26);
3579 __get_user(env->regs[27], &sc->regs.r27);
3580 __get_user(env->regs[28], &sc->regs.r28);
3581 __get_user(env->regs[29], &sc->regs.r29);
3582 __get_user(env->regs[30], &sc->regs.r30);
3583 __get_user(env->regs[31], &sc->regs.r31);
3584 __get_user(env->sregs[SR_PC], &sc->regs.pc);
3585}
3586
3587static abi_ulong get_sigframe(struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01003588 CPUMBState *env, int frame_size)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003589{
3590 abi_ulong sp = env->regs[1];
3591
Riku Voipiob545f632014-07-15 17:01:55 +03003592 if ((ka->sa_flags & TARGET_SA_ONSTACK) != 0 && !on_sig_stack(sp)) {
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003593 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
Riku Voipiob545f632014-07-15 17:01:55 +03003594 }
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003595
3596 return ((sp - frame_size) & -8UL);
3597}
3598
3599static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01003600 target_sigset_t *set, CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003601{
3602 struct target_signal_frame *frame;
3603 abi_ulong frame_addr;
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003604 int i;
3605
3606 frame_addr = get_sigframe(ka, env, sizeof *frame);
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01003607 trace_user_setup_frame(env, frame_addr);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003608 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
3609 goto badframe;
3610
3611 /* Save the mask. */
Riku Voipio1d8b5122014-04-23 10:26:05 +03003612 __put_user(set->sig[0], &frame->uc.tuc_mcontext.oldmask);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003613
3614 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
Riku Voipio0188fad2014-04-23 13:34:15 +03003615 __put_user(set->sig[i], &frame->extramask[i - 1]);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003616 }
3617
Richard Hendersonf711df62010-11-22 14:57:52 -08003618 setup_sigcontext(&frame->uc.tuc_mcontext, env);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003619
3620 /* Set up to return from userspace. If provided, use a stub
3621 already in userspace. */
3622 /* minus 8 is offset to cater for "rtsd r15,8" offset */
3623 if (ka->sa_flags & TARGET_SA_RESTORER) {
3624 env->regs[15] = ((unsigned long)ka->sa_restorer)-8;
3625 } else {
3626 uint32_t t;
3627 /* Note, these encodings are _big endian_! */
3628 /* addi r12, r0, __NR_sigreturn */
3629 t = 0x31800000UL | TARGET_NR_sigreturn;
Riku Voipio1d8b5122014-04-23 10:26:05 +03003630 __put_user(t, frame->tramp + 0);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003631 /* brki r14, 0x8 */
3632 t = 0xb9cc0008UL;
Riku Voipio1d8b5122014-04-23 10:26:05 +03003633 __put_user(t, frame->tramp + 1);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003634
3635 /* Return from sighandler will jump to the tramp.
3636 Negative 8 offset because return is rtsd r15, 8 */
Chen Gang166c97e2016-03-29 22:13:45 +08003637 env->regs[15] = frame_addr + offsetof(struct target_signal_frame, tramp)
3638 - 8;
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003639 }
3640
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003641 /* Set up registers for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003642 env->regs[1] = frame_addr;
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003643 /* Signal handler args: */
3644 env->regs[5] = sig; /* Arg 0: signum */
Edgar E. Iglesias187b4e02010-07-15 15:32:51 +02003645 env->regs[6] = 0;
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003646 /* arg 1: sigcontext */
3647 env->regs[7] = frame_addr += offsetof(typeof(*frame), uc);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003648
3649 /* Offset of 4 to handle microblaze rtid r14, 0 */
3650 env->sregs[SR_PC] = (unsigned long)ka->_sa_handler;
3651
3652 unlock_user_struct(frame, frame_addr, 1);
3653 return;
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003654badframe:
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003655 force_sig(TARGET_SIGSEGV);
3656}
3657
3658static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05003659 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01003660 target_sigset_t *set, CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003661{
3662 fprintf(stderr, "Microblaze setup_rt_frame: not implemented\n");
3663}
3664
Andreas Färber05390242012-02-25 03:37:53 +01003665long do_sigreturn(CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003666{
3667 struct target_signal_frame *frame;
3668 abi_ulong frame_addr;
Anthony Liguoric227f092009-10-01 16:12:16 -05003669 target_sigset_t target_set;
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003670 sigset_t set;
3671 int i;
3672
3673 frame_addr = env->regs[R_SP];
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01003674 trace_user_do_sigreturn(env, frame_addr);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003675 /* Make sure the guest isn't playing games. */
3676 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 1))
3677 goto badframe;
3678
3679 /* Restore blocked signals */
Riku Voipiof5f601a2014-04-23 13:00:17 +03003680 __get_user(target_set.sig[0], &frame->uc.tuc_mcontext.oldmask);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003681 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003682 __get_user(target_set.sig[i], &frame->extramask[i - 1]);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003683 }
3684 target_to_host_sigset_internal(&set, &target_set);
Peter Maydell9eede5b2016-05-27 15:51:46 +01003685 set_sigmask(&set);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003686
Richard Hendersonf711df62010-11-22 14:57:52 -08003687 restore_sigcontext(&frame->uc.tuc_mcontext, env);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003688 /* We got here through a sigreturn syscall, our path back is via an
3689 rtb insn so setup r14 for that. */
3690 env->regs[14] = env->sregs[SR_PC];
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003691
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003692 unlock_user_struct(frame, frame_addr, 0);
Timothy E Baldwin4134ecf2016-05-12 18:47:44 +01003693 return -TARGET_QEMU_ESIGRETURN;
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003694badframe:
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003695 force_sig(TARGET_SIGSEGV);
3696}
3697
Andreas Färber05390242012-02-25 03:37:53 +01003698long do_rt_sigreturn(CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003699{
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01003700 trace_user_do_rt_sigreturn(env, 0);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003701 fprintf(stderr, "Microblaze do_rt_sigreturn: not implemented\n");
3702 return -TARGET_ENOSYS;
3703}
3704
edgar_iglb6d3abd2008-02-28 11:29:27 +00003705#elif defined(TARGET_CRIS)
3706
3707struct target_sigcontext {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003708 struct target_pt_regs regs; /* needs to be first */
3709 uint32_t oldmask;
3710 uint32_t usp; /* usp before stacking this gunk on it */
edgar_iglb6d3abd2008-02-28 11:29:27 +00003711};
3712
3713/* Signal frames. */
3714struct target_signal_frame {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003715 struct target_sigcontext sc;
3716 uint32_t extramask[TARGET_NSIG_WORDS - 1];
3717 uint16_t retcode[4]; /* Trampoline code. */
edgar_iglb6d3abd2008-02-28 11:29:27 +00003718};
3719
3720struct rt_signal_frame {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003721 siginfo_t *pinfo;
3722 void *puc;
3723 siginfo_t info;
3724 struct ucontext uc;
3725 uint16_t retcode[4]; /* Trampoline code. */
edgar_iglb6d3abd2008-02-28 11:29:27 +00003726};
3727
Andreas Färber05390242012-02-25 03:37:53 +01003728static void setup_sigcontext(struct target_sigcontext *sc, CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003729{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003730 __put_user(env->regs[0], &sc->regs.r0);
3731 __put_user(env->regs[1], &sc->regs.r1);
3732 __put_user(env->regs[2], &sc->regs.r2);
3733 __put_user(env->regs[3], &sc->regs.r3);
3734 __put_user(env->regs[4], &sc->regs.r4);
3735 __put_user(env->regs[5], &sc->regs.r5);
3736 __put_user(env->regs[6], &sc->regs.r6);
3737 __put_user(env->regs[7], &sc->regs.r7);
3738 __put_user(env->regs[8], &sc->regs.r8);
3739 __put_user(env->regs[9], &sc->regs.r9);
3740 __put_user(env->regs[10], &sc->regs.r10);
3741 __put_user(env->regs[11], &sc->regs.r11);
3742 __put_user(env->regs[12], &sc->regs.r12);
3743 __put_user(env->regs[13], &sc->regs.r13);
3744 __put_user(env->regs[14], &sc->usp);
3745 __put_user(env->regs[15], &sc->regs.acr);
3746 __put_user(env->pregs[PR_MOF], &sc->regs.mof);
3747 __put_user(env->pregs[PR_SRP], &sc->regs.srp);
3748 __put_user(env->pc, &sc->regs.erp);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003749}
edgar_igl9664d922008-03-03 22:23:53 +00003750
Andreas Färber05390242012-02-25 03:37:53 +01003751static void restore_sigcontext(struct target_sigcontext *sc, CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003752{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003753 __get_user(env->regs[0], &sc->regs.r0);
3754 __get_user(env->regs[1], &sc->regs.r1);
3755 __get_user(env->regs[2], &sc->regs.r2);
3756 __get_user(env->regs[3], &sc->regs.r3);
3757 __get_user(env->regs[4], &sc->regs.r4);
3758 __get_user(env->regs[5], &sc->regs.r5);
3759 __get_user(env->regs[6], &sc->regs.r6);
3760 __get_user(env->regs[7], &sc->regs.r7);
3761 __get_user(env->regs[8], &sc->regs.r8);
3762 __get_user(env->regs[9], &sc->regs.r9);
3763 __get_user(env->regs[10], &sc->regs.r10);
3764 __get_user(env->regs[11], &sc->regs.r11);
3765 __get_user(env->regs[12], &sc->regs.r12);
3766 __get_user(env->regs[13], &sc->regs.r13);
3767 __get_user(env->regs[14], &sc->usp);
3768 __get_user(env->regs[15], &sc->regs.acr);
3769 __get_user(env->pregs[PR_MOF], &sc->regs.mof);
3770 __get_user(env->pregs[PR_SRP], &sc->regs.srp);
3771 __get_user(env->pc, &sc->regs.erp);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003772}
3773
Andreas Färber05390242012-02-25 03:37:53 +01003774static abi_ulong get_sigframe(CPUCRISState *env, int framesize)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003775{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003776 abi_ulong sp;
3777 /* Align the stack downwards to 4. */
3778 sp = (env->regs[R_SP] & ~3);
3779 return sp - framesize;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003780}
3781
pbrook624f7972008-05-31 16:11:38 +00003782static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01003783 target_sigset_t *set, CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003784{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003785 struct target_signal_frame *frame;
3786 abi_ulong frame_addr;
3787 int i;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003788
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003789 frame_addr = get_sigframe(env, sizeof *frame);
3790 trace_user_setup_frame(env, frame_addr);
3791 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
3792 goto badframe;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003793
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003794 /*
3795 * The CRIS signal return trampoline. A real linux/CRIS kernel doesn't
3796 * use this trampoline anymore but it sets it up for GDB.
3797 * In QEMU, using the trampoline simplifies things a bit so we use it.
3798 *
3799 * This is movu.w __NR_sigreturn, r9; break 13;
3800 */
Riku Voipio1d8b5122014-04-23 10:26:05 +03003801 __put_user(0x9c5f, frame->retcode+0);
3802 __put_user(TARGET_NR_sigreturn,
3803 frame->retcode + 1);
3804 __put_user(0xe93d, frame->retcode + 2);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003805
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003806 /* Save the mask. */
Riku Voipio1d8b5122014-04-23 10:26:05 +03003807 __put_user(set->sig[0], &frame->sc.oldmask);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003808
Riku Voipio0188fad2014-04-23 13:34:15 +03003809 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
3810 __put_user(set->sig[i], &frame->extramask[i - 1]);
3811 }
edgar_iglb6d3abd2008-02-28 11:29:27 +00003812
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003813 setup_sigcontext(&frame->sc, env);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003814
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003815 /* Move the stack and setup the arguments for the handler. */
3816 env->regs[R_SP] = frame_addr;
3817 env->regs[10] = sig;
3818 env->pc = (unsigned long) ka->_sa_handler;
3819 /* Link SRP so the guest returns through the trampoline. */
3820 env->pregs[PR_SRP] = frame_addr + offsetof(typeof(*frame), retcode);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003821
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003822 unlock_user_struct(frame, frame_addr, 1);
3823 return;
3824badframe:
3825 force_sig(TARGET_SIGSEGV);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003826}
3827
pbrook624f7972008-05-31 16:11:38 +00003828static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05003829 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01003830 target_sigset_t *set, CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003831{
3832 fprintf(stderr, "CRIS setup_rt_frame: not implemented\n");
3833}
3834
Andreas Färber05390242012-02-25 03:37:53 +01003835long do_sigreturn(CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003836{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003837 struct target_signal_frame *frame;
3838 abi_ulong frame_addr;
3839 target_sigset_t target_set;
3840 sigset_t set;
3841 int i;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003842
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003843 frame_addr = env->regs[R_SP];
3844 trace_user_do_sigreturn(env, frame_addr);
3845 /* Make sure the guest isn't playing games. */
3846 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 1)) {
3847 goto badframe;
3848 }
edgar_iglb6d3abd2008-02-28 11:29:27 +00003849
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003850 /* Restore blocked signals */
Riku Voipiof5f601a2014-04-23 13:00:17 +03003851 __get_user(target_set.sig[0], &frame->sc.oldmask);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003852 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
Riku Voipiof5f601a2014-04-23 13:00:17 +03003853 __get_user(target_set.sig[i], &frame->extramask[i - 1]);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003854 }
3855 target_to_host_sigset_internal(&set, &target_set);
Peter Maydell9eede5b2016-05-27 15:51:46 +01003856 set_sigmask(&set);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003857
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003858 restore_sigcontext(&frame->sc, env);
3859 unlock_user_struct(frame, frame_addr, 0);
Timothy E Baldwin62050862016-05-12 18:47:41 +01003860 return -TARGET_QEMU_ESIGRETURN;
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003861badframe:
3862 force_sig(TARGET_SIGSEGV);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003863}
3864
Andreas Färber05390242012-02-25 03:37:53 +01003865long do_rt_sigreturn(CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003866{
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01003867 trace_user_do_rt_sigreturn(env, 0);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003868 fprintf(stderr, "CRIS do_rt_sigreturn: not implemented\n");
3869 return -TARGET_ENOSYS;
3870}
thsc3b5bc82007-12-02 06:31:25 +00003871
Jia Liud9627832012-07-20 15:50:52 +08003872#elif defined(TARGET_OPENRISC)
3873
3874struct target_sigcontext {
3875 struct target_pt_regs regs;
3876 abi_ulong oldmask;
3877 abi_ulong usp;
3878};
3879
3880struct target_ucontext {
3881 abi_ulong tuc_flags;
3882 abi_ulong tuc_link;
3883 target_stack_t tuc_stack;
3884 struct target_sigcontext tuc_mcontext;
3885 target_sigset_t tuc_sigmask; /* mask last for extensibility */
3886};
3887
3888struct target_rt_sigframe {
3889 abi_ulong pinfo;
3890 uint64_t puc;
3891 struct target_siginfo info;
3892 struct target_sigcontext sc;
3893 struct target_ucontext uc;
3894 unsigned char retcode[16]; /* trampoline code */
3895};
3896
3897/* This is the asm-generic/ucontext.h version */
3898#if 0
3899static int restore_sigcontext(CPUOpenRISCState *regs,
3900 struct target_sigcontext *sc)
3901{
3902 unsigned int err = 0;
3903 unsigned long old_usp;
3904
3905 /* Alwys make any pending restarted system call return -EINTR */
3906 current_thread_info()->restart_block.fn = do_no_restart_syscall;
3907
3908 /* restore the regs from &sc->regs (same as sc, since regs is first)
3909 * (sc is already checked for VERIFY_READ since the sigframe was
3910 * checked in sys_sigreturn previously)
3911 */
3912
3913 if (copy_from_user(regs, &sc, sizeof(struct target_pt_regs))) {
3914 goto badframe;
3915 }
3916
3917 /* make sure the U-flag is set so user-mode cannot fool us */
3918
3919 regs->sr &= ~SR_SM;
3920
3921 /* restore the old USP as it was before we stacked the sc etc.
3922 * (we cannot just pop the sigcontext since we aligned the sp and
3923 * stuff after pushing it)
3924 */
3925
Riku Voipio1d8b5122014-04-23 10:26:05 +03003926 __get_user(old_usp, &sc->usp);
Jia Liud9627832012-07-20 15:50:52 +08003927 phx_signal("old_usp 0x%lx", old_usp);
3928
3929 __PHX__ REALLY /* ??? */
3930 wrusp(old_usp);
3931 regs->gpr[1] = old_usp;
3932
3933 /* TODO: the other ports use regs->orig_XX to disable syscall checks
3934 * after this completes, but we don't use that mechanism. maybe we can
3935 * use it now ?
3936 */
3937
3938 return err;
3939
3940badframe:
3941 return 1;
3942}
3943#endif
3944
3945/* Set up a signal frame. */
3946
Riku Voipio41ecc722014-04-23 11:01:00 +03003947static void setup_sigcontext(struct target_sigcontext *sc,
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003948 CPUOpenRISCState *regs,
3949 unsigned long mask)
Jia Liud9627832012-07-20 15:50:52 +08003950{
Jia Liud9627832012-07-20 15:50:52 +08003951 unsigned long usp = regs->gpr[1];
3952
3953 /* copy the regs. they are first in sc so we can use sc directly */
3954
Riku Voipio1d8b5122014-04-23 10:26:05 +03003955 /*copy_to_user(&sc, regs, sizeof(struct target_pt_regs));*/
Jia Liud9627832012-07-20 15:50:52 +08003956
3957 /* Set the frametype to CRIS_FRAME_NORMAL for the execution of
3958 the signal handler. The frametype will be restored to its previous
3959 value in restore_sigcontext. */
3960 /*regs->frametype = CRIS_FRAME_NORMAL;*/
3961
3962 /* then some other stuff */
Riku Voipio1d8b5122014-04-23 10:26:05 +03003963 __put_user(mask, &sc->oldmask);
Riku Voipio41ecc722014-04-23 11:01:00 +03003964 __put_user(usp, &sc->usp);
Jia Liud9627832012-07-20 15:50:52 +08003965}
3966
3967static inline unsigned long align_sigframe(unsigned long sp)
3968{
Eduardo Habkost9be38592016-06-13 18:57:58 -03003969 return sp & ~3UL;
Jia Liud9627832012-07-20 15:50:52 +08003970}
3971
3972static inline abi_ulong get_sigframe(struct target_sigaction *ka,
3973 CPUOpenRISCState *regs,
3974 size_t frame_size)
3975{
3976 unsigned long sp = regs->gpr[1];
3977 int onsigstack = on_sig_stack(sp);
3978
3979 /* redzone */
3980 /* This is the X/Open sanctioned signal stack switching. */
Riku Voipiob545f632014-07-15 17:01:55 +03003981 if ((ka->sa_flags & TARGET_SA_ONSTACK) != 0 && !onsigstack) {
Jia Liud9627832012-07-20 15:50:52 +08003982 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
3983 }
3984
3985 sp = align_sigframe(sp - frame_size);
3986
3987 /*
3988 * If we are on the alternate signal stack and would overflow it, don't.
3989 * Return an always-bogus address instead so we will die with SIGSEGV.
3990 */
3991
3992 if (onsigstack && !likely(on_sig_stack(sp))) {
3993 return -1L;
3994 }
3995
3996 return sp;
3997}
3998
Jia Liud9627832012-07-20 15:50:52 +08003999static void setup_rt_frame(int sig, struct target_sigaction *ka,
4000 target_siginfo_t *info,
4001 target_sigset_t *set, CPUOpenRISCState *env)
4002{
4003 int err = 0;
4004 abi_ulong frame_addr;
4005 unsigned long return_ip;
4006 struct target_rt_sigframe *frame;
4007 abi_ulong info_addr, uc_addr;
4008
Jia Liud9627832012-07-20 15:50:52 +08004009 frame_addr = get_sigframe(ka, env, sizeof(*frame));
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01004010 trace_user_setup_rt_frame(env, frame_addr);
Jia Liud9627832012-07-20 15:50:52 +08004011 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
4012 goto give_sigsegv;
4013 }
4014
4015 info_addr = frame_addr + offsetof(struct target_rt_sigframe, info);
Riku Voipio1d8b5122014-04-23 10:26:05 +03004016 __put_user(info_addr, &frame->pinfo);
Jia Liud9627832012-07-20 15:50:52 +08004017 uc_addr = frame_addr + offsetof(struct target_rt_sigframe, uc);
Riku Voipio1d8b5122014-04-23 10:26:05 +03004018 __put_user(uc_addr, &frame->puc);
Jia Liud9627832012-07-20 15:50:52 +08004019
4020 if (ka->sa_flags & SA_SIGINFO) {
Peter Maydellf6c7a052015-01-08 12:19:48 +00004021 tswap_siginfo(&frame->info, info);
Jia Liud9627832012-07-20 15:50:52 +08004022 }
4023
4024 /*err |= __clear_user(&frame->uc, offsetof(struct ucontext, uc_mcontext));*/
Riku Voipio1d8b5122014-04-23 10:26:05 +03004025 __put_user(0, &frame->uc.tuc_flags);
4026 __put_user(0, &frame->uc.tuc_link);
4027 __put_user(target_sigaltstack_used.ss_sp,
4028 &frame->uc.tuc_stack.ss_sp);
4029 __put_user(sas_ss_flags(env->gpr[1]), &frame->uc.tuc_stack.ss_flags);
4030 __put_user(target_sigaltstack_used.ss_size,
4031 &frame->uc.tuc_stack.ss_size);
Riku Voipio41ecc722014-04-23 11:01:00 +03004032 setup_sigcontext(&frame->sc, env, set->sig[0]);
Jia Liud9627832012-07-20 15:50:52 +08004033
4034 /*err |= copy_to_user(frame->uc.tuc_sigmask, set, sizeof(*set));*/
4035
Jia Liud9627832012-07-20 15:50:52 +08004036 /* trampoline - the desired return ip is the retcode itself */
4037 return_ip = (unsigned long)&frame->retcode;
4038 /* This is l.ori r11,r0,__NR_sigreturn, l.sys 1 */
Riku Voipio1d8b5122014-04-23 10:26:05 +03004039 __put_user(0xa960, (short *)(frame->retcode + 0));
4040 __put_user(TARGET_NR_rt_sigreturn, (short *)(frame->retcode + 2));
4041 __put_user(0x20000001, (unsigned long *)(frame->retcode + 4));
4042 __put_user(0x15000000, (unsigned long *)(frame->retcode + 8));
Jia Liud9627832012-07-20 15:50:52 +08004043
4044 if (err) {
4045 goto give_sigsegv;
4046 }
4047
4048 /* TODO what is the current->exec_domain stuff and invmap ? */
4049
4050 /* Set up registers for signal handler */
4051 env->pc = (unsigned long)ka->_sa_handler; /* what we enter NOW */
4052 env->gpr[9] = (unsigned long)return_ip; /* what we enter LATER */
4053 env->gpr[3] = (unsigned long)sig; /* arg 1: signo */
4054 env->gpr[4] = (unsigned long)&frame->info; /* arg 2: (siginfo_t*) */
4055 env->gpr[5] = (unsigned long)&frame->uc; /* arg 3: ucontext */
4056
4057 /* actually move the usp to reflect the stacked frame */
4058 env->gpr[1] = (unsigned long)frame;
4059
4060 return;
4061
4062give_sigsegv:
4063 unlock_user_struct(frame, frame_addr, 1);
4064 if (sig == TARGET_SIGSEGV) {
4065 ka->_sa_handler = TARGET_SIG_DFL;
4066 }
4067 force_sig(TARGET_SIGSEGV);
4068}
4069
4070long do_sigreturn(CPUOpenRISCState *env)
4071{
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01004072 trace_user_do_sigreturn(env, 0);
4073 fprintf(stderr, "do_sigreturn: not implemented\n");
Jia Liud9627832012-07-20 15:50:52 +08004074 return -TARGET_ENOSYS;
4075}
4076
4077long do_rt_sigreturn(CPUOpenRISCState *env)
4078{
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01004079 trace_user_do_rt_sigreturn(env, 0);
4080 fprintf(stderr, "do_rt_sigreturn: not implemented\n");
Jia Liud9627832012-07-20 15:50:52 +08004081 return -TARGET_ENOSYS;
4082}
4083/* TARGET_OPENRISC */
4084
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004085#elif defined(TARGET_S390X)
4086
4087#define __NUM_GPRS 16
4088#define __NUM_FPRS 16
4089#define __NUM_ACRS 16
4090
4091#define S390_SYSCALL_SIZE 2
4092#define __SIGNAL_FRAMESIZE 160 /* FIXME: 31-bit mode -> 96 */
4093
4094#define _SIGCONTEXT_NSIG 64
4095#define _SIGCONTEXT_NSIG_BPW 64 /* FIXME: 31-bit mode -> 32 */
4096#define _SIGCONTEXT_NSIG_WORDS (_SIGCONTEXT_NSIG / _SIGCONTEXT_NSIG_BPW)
4097#define _SIGMASK_COPY_SIZE (sizeof(unsigned long)*_SIGCONTEXT_NSIG_WORDS)
4098#define PSW_ADDR_AMODE 0x0000000000000000UL /* 0x80000000UL for 31-bit */
4099#define S390_SYSCALL_OPCODE ((uint16_t)0x0a00)
4100
4101typedef struct {
4102 target_psw_t psw;
4103 target_ulong gprs[__NUM_GPRS];
4104 unsigned int acrs[__NUM_ACRS];
4105} target_s390_regs_common;
4106
4107typedef struct {
4108 unsigned int fpc;
4109 double fprs[__NUM_FPRS];
4110} target_s390_fp_regs;
4111
4112typedef struct {
4113 target_s390_regs_common regs;
4114 target_s390_fp_regs fpregs;
4115} target_sigregs;
4116
4117struct target_sigcontext {
4118 target_ulong oldmask[_SIGCONTEXT_NSIG_WORDS];
4119 target_sigregs *sregs;
4120};
4121
4122typedef struct {
4123 uint8_t callee_used_stack[__SIGNAL_FRAMESIZE];
4124 struct target_sigcontext sc;
4125 target_sigregs sregs;
4126 int signo;
4127 uint8_t retcode[S390_SYSCALL_SIZE];
4128} sigframe;
4129
4130struct target_ucontext {
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004131 target_ulong tuc_flags;
4132 struct target_ucontext *tuc_link;
4133 target_stack_t tuc_stack;
4134 target_sigregs tuc_mcontext;
4135 target_sigset_t tuc_sigmask; /* mask last for extensibility */
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004136};
4137
4138typedef struct {
4139 uint8_t callee_used_stack[__SIGNAL_FRAMESIZE];
4140 uint8_t retcode[S390_SYSCALL_SIZE];
4141 struct target_siginfo info;
4142 struct target_ucontext uc;
4143} rt_sigframe;
4144
4145static inline abi_ulong
Andreas Färber05390242012-02-25 03:37:53 +01004146get_sigframe(struct target_sigaction *ka, CPUS390XState *env, size_t frame_size)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004147{
4148 abi_ulong sp;
4149
4150 /* Default to using normal stack */
4151 sp = env->regs[15];
4152
4153 /* This is the X/Open sanctioned signal stack switching. */
4154 if (ka->sa_flags & TARGET_SA_ONSTACK) {
4155 if (!sas_ss_flags(sp)) {
4156 sp = target_sigaltstack_used.ss_sp +
4157 target_sigaltstack_used.ss_size;
4158 }
4159 }
4160
4161 /* This is the legacy signal stack switching. */
4162 else if (/* FIXME !user_mode(regs) */ 0 &&
4163 !(ka->sa_flags & TARGET_SA_RESTORER) &&
4164 ka->sa_restorer) {
4165 sp = (abi_ulong) ka->sa_restorer;
4166 }
4167
4168 return (sp - frame_size) & -8ul;
4169}
4170
Andreas Färber05390242012-02-25 03:37:53 +01004171static void save_sigregs(CPUS390XState *env, target_sigregs *sregs)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004172{
4173 int i;
4174 //save_access_regs(current->thread.acrs); FIXME
4175
4176 /* Copy a 'clean' PSW mask to the user to avoid leaking
4177 information about whether PER is currently on. */
4178 __put_user(env->psw.mask, &sregs->regs.psw.mask);
4179 __put_user(env->psw.addr, &sregs->regs.psw.addr);
4180 for (i = 0; i < 16; i++) {
4181 __put_user(env->regs[i], &sregs->regs.gprs[i]);
4182 }
4183 for (i = 0; i < 16; i++) {
4184 __put_user(env->aregs[i], &sregs->regs.acrs[i]);
4185 }
4186 /*
4187 * We have to store the fp registers to current->thread.fp_regs
4188 * to merge them with the emulated registers.
4189 */
4190 //save_fp_regs(&current->thread.fp_regs); FIXME
4191 for (i = 0; i < 16; i++) {
Eric Farmanc498d8e2015-05-07 14:35:44 -04004192 __put_user(get_freg(env, i)->ll, &sregs->fpregs.fprs[i]);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004193 }
4194}
4195
4196static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01004197 target_sigset_t *set, CPUS390XState *env)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004198{
4199 sigframe *frame;
4200 abi_ulong frame_addr;
4201
4202 frame_addr = get_sigframe(ka, env, sizeof(*frame));
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01004203 trace_user_setup_frame(env, frame_addr);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004204 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01004205 goto give_sigsegv;
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004206 }
4207
Riku Voipio0188fad2014-04-23 13:34:15 +03004208 __put_user(set->sig[0], &frame->sc.oldmask[0]);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004209
4210 save_sigregs(env, &frame->sregs);
4211
4212 __put_user((abi_ulong)(unsigned long)&frame->sregs,
4213 (abi_ulong *)&frame->sc.sregs);
4214
4215 /* Set up to return from userspace. If provided, use a stub
4216 already in userspace. */
4217 if (ka->sa_flags & TARGET_SA_RESTORER) {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01004218 env->regs[14] = (unsigned long)
4219 ka->sa_restorer | PSW_ADDR_AMODE;
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004220 } else {
Chen Gang5b1d59d2016-05-24 14:54:32 +03004221 env->regs[14] = (frame_addr + offsetof(sigframe, retcode))
4222 | PSW_ADDR_AMODE;
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01004223 __put_user(S390_SYSCALL_OPCODE | TARGET_NR_sigreturn,
4224 (uint16_t *)(frame->retcode));
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004225 }
4226
4227 /* Set up backchain. */
Riku Voipio0188fad2014-04-23 13:34:15 +03004228 __put_user(env->regs[15], (abi_ulong *) frame);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004229
4230 /* Set up registers for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02004231 env->regs[15] = frame_addr;
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004232 env->psw.addr = (target_ulong) ka->_sa_handler | PSW_ADDR_AMODE;
4233
4234 env->regs[2] = sig; //map_signal(sig);
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02004235 env->regs[3] = frame_addr += offsetof(typeof(*frame), sc);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004236
4237 /* We forgot to include these in the sigcontext.
4238 To avoid breaking binary compatibility, they are passed as args. */
4239 env->regs[4] = 0; // FIXME: no clue... current->thread.trap_no;
4240 env->regs[5] = 0; // FIXME: no clue... current->thread.prot_addr;
4241
4242 /* Place signal number on stack to allow backtrace from handler. */
Laurent Vivierc1bc91c2016-06-15 18:14:32 +02004243 __put_user(env->regs[2], &frame->signo);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004244 unlock_user_struct(frame, frame_addr, 1);
4245 return;
4246
4247give_sigsegv:
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004248 force_sig(TARGET_SIGSEGV);
4249}
4250
4251static void setup_rt_frame(int sig, struct target_sigaction *ka,
4252 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01004253 target_sigset_t *set, CPUS390XState *env)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004254{
4255 int i;
4256 rt_sigframe *frame;
4257 abi_ulong frame_addr;
4258
4259 frame_addr = get_sigframe(ka, env, sizeof *frame);
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01004260 trace_user_setup_rt_frame(env, frame_addr);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004261 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
4262 goto give_sigsegv;
4263 }
4264
Peter Maydellf6c7a052015-01-08 12:19:48 +00004265 tswap_siginfo(&frame->info, info);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004266
4267 /* Create the ucontext. */
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004268 __put_user(0, &frame->uc.tuc_flags);
4269 __put_user((abi_ulong)0, (abi_ulong *)&frame->uc.tuc_link);
4270 __put_user(target_sigaltstack_used.ss_sp, &frame->uc.tuc_stack.ss_sp);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004271 __put_user(sas_ss_flags(get_sp_from_cpustate(env)),
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01004272 &frame->uc.tuc_stack.ss_flags);
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004273 __put_user(target_sigaltstack_used.ss_size, &frame->uc.tuc_stack.ss_size);
4274 save_sigregs(env, &frame->uc.tuc_mcontext);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004275 for (i = 0; i < TARGET_NSIG_WORDS; i++) {
4276 __put_user((abi_ulong)set->sig[i],
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01004277 (abi_ulong *)&frame->uc.tuc_sigmask.sig[i]);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004278 }
4279
4280 /* Set up to return from userspace. If provided, use a stub
4281 already in userspace. */
4282 if (ka->sa_flags & TARGET_SA_RESTORER) {
4283 env->regs[14] = (unsigned long) ka->sa_restorer | PSW_ADDR_AMODE;
4284 } else {
4285 env->regs[14] = (unsigned long) frame->retcode | PSW_ADDR_AMODE;
Riku Voipio0188fad2014-04-23 13:34:15 +03004286 __put_user(S390_SYSCALL_OPCODE | TARGET_NR_rt_sigreturn,
4287 (uint16_t *)(frame->retcode));
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004288 }
4289
4290 /* Set up backchain. */
Riku Voipio0188fad2014-04-23 13:34:15 +03004291 __put_user(env->regs[15], (abi_ulong *) frame);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004292
4293 /* Set up registers for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02004294 env->regs[15] = frame_addr;
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004295 env->psw.addr = (target_ulong) ka->_sa_handler | PSW_ADDR_AMODE;
4296
4297 env->regs[2] = sig; //map_signal(sig);
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02004298 env->regs[3] = frame_addr + offsetof(typeof(*frame), info);
4299 env->regs[4] = frame_addr + offsetof(typeof(*frame), uc);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004300 return;
4301
4302give_sigsegv:
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004303 force_sig(TARGET_SIGSEGV);
4304}
4305
4306static int
Andreas Färber05390242012-02-25 03:37:53 +01004307restore_sigregs(CPUS390XState *env, target_sigregs *sc)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004308{
4309 int err = 0;
4310 int i;
4311
4312 for (i = 0; i < 16; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03004313 __get_user(env->regs[i], &sc->regs.gprs[i]);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004314 }
4315
Riku Voipio1d8b5122014-04-23 10:26:05 +03004316 __get_user(env->psw.mask, &sc->regs.psw.mask);
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01004317 trace_user_s390x_restore_sigregs(env, (unsigned long long)sc->regs.psw.addr,
4318 (unsigned long long)env->psw.addr);
Riku Voipio1d8b5122014-04-23 10:26:05 +03004319 __get_user(env->psw.addr, &sc->regs.psw.addr);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004320 /* FIXME: 31-bit -> | PSW_ADDR_AMODE */
4321
4322 for (i = 0; i < 16; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03004323 __get_user(env->aregs[i], &sc->regs.acrs[i]);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004324 }
4325 for (i = 0; i < 16; i++) {
Eric Farmanc498d8e2015-05-07 14:35:44 -04004326 __get_user(get_freg(env, i)->ll, &sc->fpregs.fprs[i]);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004327 }
4328
4329 return err;
4330}
4331
Andreas Färber05390242012-02-25 03:37:53 +01004332long do_sigreturn(CPUS390XState *env)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004333{
4334 sigframe *frame;
4335 abi_ulong frame_addr = env->regs[15];
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004336 target_sigset_t target_set;
4337 sigset_t set;
4338
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01004339 trace_user_do_sigreturn(env, frame_addr);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004340 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
4341 goto badframe;
4342 }
Riku Voipiof5f601a2014-04-23 13:00:17 +03004343 __get_user(target_set.sig[0], &frame->sc.oldmask[0]);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004344
4345 target_to_host_sigset_internal(&set, &target_set);
Peter Maydell9eede5b2016-05-27 15:51:46 +01004346 set_sigmask(&set); /* ~_BLOCKABLE? */
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004347
4348 if (restore_sigregs(env, &frame->sregs)) {
4349 goto badframe;
4350 }
4351
4352 unlock_user_struct(frame, frame_addr, 0);
Timothy E Baldwin47405ab2016-05-12 18:47:40 +01004353 return -TARGET_QEMU_ESIGRETURN;
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004354
4355badframe:
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004356 force_sig(TARGET_SIGSEGV);
4357 return 0;
4358}
4359
Andreas Färber05390242012-02-25 03:37:53 +01004360long do_rt_sigreturn(CPUS390XState *env)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004361{
4362 rt_sigframe *frame;
4363 abi_ulong frame_addr = env->regs[15];
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004364 sigset_t set;
4365
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01004366 trace_user_do_rt_sigreturn(env, frame_addr);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004367 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
4368 goto badframe;
4369 }
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004370 target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004371
Peter Maydell9eede5b2016-05-27 15:51:46 +01004372 set_sigmask(&set); /* ~_BLOCKABLE? */
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004373
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004374 if (restore_sigregs(env, &frame->uc.tuc_mcontext)) {
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004375 goto badframe;
4376 }
4377
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004378 if (do_sigaltstack(frame_addr + offsetof(rt_sigframe, uc.tuc_stack), 0,
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004379 get_sp_from_cpustate(env)) == -EFAULT) {
4380 goto badframe;
4381 }
4382 unlock_user_struct(frame, frame_addr, 0);
Timothy E Baldwin47405ab2016-05-12 18:47:40 +01004383 return -TARGET_QEMU_ESIGRETURN;
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004384
4385badframe:
4386 unlock_user_struct(frame, frame_addr, 0);
4387 force_sig(TARGET_SIGSEGV);
4388 return 0;
4389}
4390
Tom Musta61e75fe2014-06-30 08:13:38 -05004391#elif defined(TARGET_PPC)
Nathan Froydbcd49332009-05-12 19:13:18 -07004392
4393/* Size of dummy stack frame allocated when calling signal handler.
4394 See arch/powerpc/include/asm/ptrace.h. */
4395#if defined(TARGET_PPC64)
4396#define SIGNAL_FRAMESIZE 128
4397#else
4398#define SIGNAL_FRAMESIZE 64
4399#endif
4400
Tom Musta61e75fe2014-06-30 08:13:38 -05004401/* See arch/powerpc/include/asm/ucontext.h. Only used for 32-bit PPC;
4402 on 64-bit PPC, sigcontext and mcontext are one and the same. */
4403struct target_mcontext {
4404 target_ulong mc_gregs[48];
4405 /* Includes fpscr. */
4406 uint64_t mc_fregs[33];
4407 target_ulong mc_pad[2];
4408 /* We need to handle Altivec and SPE at the same time, which no
4409 kernel needs to do. Fortunately, the kernel defines this bit to
4410 be Altivec-register-large all the time, rather than trying to
4411 twiddle it based on the specific platform. */
4412 union {
4413 /* SPE vector registers. One extra for SPEFSCR. */
4414 uint32_t spe[33];
4415 /* Altivec vector registers. The packing of VSCR and VRSAVE
4416 varies depending on whether we're PPC64 or not: PPC64 splits
4417 them apart; PPC32 stuffs them together. */
4418#if defined(TARGET_PPC64)
4419#define QEMU_NVRREG 34
4420#else
4421#define QEMU_NVRREG 33
4422#endif
4423 ppc_avr_t altivec[QEMU_NVRREG];
4424#undef QEMU_NVRREG
4425 } mc_vregs __attribute__((__aligned__(16)));
4426};
4427
Nathan Froydbcd49332009-05-12 19:13:18 -07004428/* See arch/powerpc/include/asm/sigcontext.h. */
4429struct target_sigcontext {
4430 target_ulong _unused[4];
4431 int32_t signal;
4432#if defined(TARGET_PPC64)
4433 int32_t pad0;
4434#endif
4435 target_ulong handler;
4436 target_ulong oldmask;
4437 target_ulong regs; /* struct pt_regs __user * */
Tom Musta61e75fe2014-06-30 08:13:38 -05004438#if defined(TARGET_PPC64)
4439 struct target_mcontext mcontext;
4440#endif
Nathan Froydbcd49332009-05-12 19:13:18 -07004441};
4442
4443/* Indices for target_mcontext.mc_gregs, below.
4444 See arch/powerpc/include/asm/ptrace.h for details. */
4445enum {
4446 TARGET_PT_R0 = 0,
4447 TARGET_PT_R1 = 1,
4448 TARGET_PT_R2 = 2,
4449 TARGET_PT_R3 = 3,
4450 TARGET_PT_R4 = 4,
4451 TARGET_PT_R5 = 5,
4452 TARGET_PT_R6 = 6,
4453 TARGET_PT_R7 = 7,
4454 TARGET_PT_R8 = 8,
4455 TARGET_PT_R9 = 9,
4456 TARGET_PT_R10 = 10,
4457 TARGET_PT_R11 = 11,
4458 TARGET_PT_R12 = 12,
4459 TARGET_PT_R13 = 13,
4460 TARGET_PT_R14 = 14,
4461 TARGET_PT_R15 = 15,
4462 TARGET_PT_R16 = 16,
4463 TARGET_PT_R17 = 17,
4464 TARGET_PT_R18 = 18,
4465 TARGET_PT_R19 = 19,
4466 TARGET_PT_R20 = 20,
4467 TARGET_PT_R21 = 21,
4468 TARGET_PT_R22 = 22,
4469 TARGET_PT_R23 = 23,
4470 TARGET_PT_R24 = 24,
4471 TARGET_PT_R25 = 25,
4472 TARGET_PT_R26 = 26,
4473 TARGET_PT_R27 = 27,
4474 TARGET_PT_R28 = 28,
4475 TARGET_PT_R29 = 29,
4476 TARGET_PT_R30 = 30,
4477 TARGET_PT_R31 = 31,
4478 TARGET_PT_NIP = 32,
4479 TARGET_PT_MSR = 33,
4480 TARGET_PT_ORIG_R3 = 34,
4481 TARGET_PT_CTR = 35,
4482 TARGET_PT_LNK = 36,
4483 TARGET_PT_XER = 37,
4484 TARGET_PT_CCR = 38,
4485 /* Yes, there are two registers with #39. One is 64-bit only. */
4486 TARGET_PT_MQ = 39,
4487 TARGET_PT_SOFTE = 39,
4488 TARGET_PT_TRAP = 40,
4489 TARGET_PT_DAR = 41,
4490 TARGET_PT_DSISR = 42,
4491 TARGET_PT_RESULT = 43,
4492 TARGET_PT_REGS_COUNT = 44
4493};
4494
Nathan Froydbcd49332009-05-12 19:13:18 -07004495
4496struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02004497 target_ulong tuc_flags;
4498 target_ulong tuc_link; /* struct ucontext __user * */
4499 struct target_sigaltstack tuc_stack;
Nathan Froydbcd49332009-05-12 19:13:18 -07004500#if !defined(TARGET_PPC64)
Aurelien Jarno60e99242010-03-29 02:12:51 +02004501 int32_t tuc_pad[7];
4502 target_ulong tuc_regs; /* struct mcontext __user *
Nathan Froydbcd49332009-05-12 19:13:18 -07004503 points to uc_mcontext field */
4504#endif
Aurelien Jarno60e99242010-03-29 02:12:51 +02004505 target_sigset_t tuc_sigmask;
Nathan Froydbcd49332009-05-12 19:13:18 -07004506#if defined(TARGET_PPC64)
Anthony Liguoric227f092009-10-01 16:12:16 -05004507 target_sigset_t unused[15]; /* Allow for uc_sigmask growth */
Tom Musta61e75fe2014-06-30 08:13:38 -05004508 struct target_sigcontext tuc_sigcontext;
Nathan Froydbcd49332009-05-12 19:13:18 -07004509#else
Aurelien Jarno60e99242010-03-29 02:12:51 +02004510 int32_t tuc_maskext[30];
4511 int32_t tuc_pad2[3];
4512 struct target_mcontext tuc_mcontext;
Nathan Froydbcd49332009-05-12 19:13:18 -07004513#endif
4514};
4515
4516/* See arch/powerpc/kernel/signal_32.c. */
4517struct target_sigframe {
4518 struct target_sigcontext sctx;
4519 struct target_mcontext mctx;
4520 int32_t abigap[56];
4521};
4522
Tom Musta61e75fe2014-06-30 08:13:38 -05004523#if defined(TARGET_PPC64)
4524
4525#define TARGET_TRAMP_SIZE 6
4526
4527struct target_rt_sigframe {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01004528 /* sys_rt_sigreturn requires the ucontext be the first field */
4529 struct target_ucontext uc;
4530 target_ulong _unused[2];
4531 uint32_t trampoline[TARGET_TRAMP_SIZE];
4532 target_ulong pinfo; /* struct siginfo __user * */
4533 target_ulong puc; /* void __user * */
4534 struct target_siginfo info;
4535 /* 64 bit ABI allows for 288 bytes below sp before decrementing it. */
4536 char abigap[288];
Tom Musta61e75fe2014-06-30 08:13:38 -05004537} __attribute__((aligned(16)));
4538
4539#else
4540
Nathan Froydbcd49332009-05-12 19:13:18 -07004541struct target_rt_sigframe {
4542 struct target_siginfo info;
4543 struct target_ucontext uc;
4544 int32_t abigap[56];
4545};
4546
Tom Musta61e75fe2014-06-30 08:13:38 -05004547#endif
4548
Tom Musta8d6ab332014-06-30 08:13:39 -05004549#if defined(TARGET_PPC64)
4550
4551struct target_func_ptr {
4552 target_ulong entry;
4553 target_ulong toc;
4554};
4555
4556#endif
4557
Nathan Froydbcd49332009-05-12 19:13:18 -07004558/* We use the mc_pad field for the signal return trampoline. */
4559#define tramp mc_pad
4560
4561/* See arch/powerpc/kernel/signal.c. */
4562static target_ulong get_sigframe(struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01004563 CPUPPCState *env,
Nathan Froydbcd49332009-05-12 19:13:18 -07004564 int frame_size)
4565{
Eduardo Habkost9be38592016-06-13 18:57:58 -03004566 target_ulong oldsp;
Nathan Froydbcd49332009-05-12 19:13:18 -07004567
4568 oldsp = env->gpr[1];
4569
4570 if ((ka->sa_flags & TARGET_SA_ONSTACK) &&
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01004571 (sas_ss_flags(oldsp) == 0)) {
Nathan Froydbcd49332009-05-12 19:13:18 -07004572 oldsp = (target_sigaltstack_used.ss_sp
4573 + target_sigaltstack_used.ss_size);
4574 }
4575
Eduardo Habkost9be38592016-06-13 18:57:58 -03004576 return (oldsp - frame_size) & ~0xFUL;
Nathan Froydbcd49332009-05-12 19:13:18 -07004577}
4578
Tom Musta76781082014-06-30 08:13:37 -05004579static void save_user_regs(CPUPPCState *env, struct target_mcontext *frame)
Nathan Froydbcd49332009-05-12 19:13:18 -07004580{
4581 target_ulong msr = env->msr;
4582 int i;
4583 target_ulong ccr = 0;
4584
4585 /* In general, the kernel attempts to be intelligent about what it
4586 needs to save for Altivec/FP/SPE registers. We don't care that
4587 much, so we just go ahead and save everything. */
4588
4589 /* Save general registers. */
4590 for (i = 0; i < ARRAY_SIZE(env->gpr); i++) {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01004591 __put_user(env->gpr[i], &frame->mc_gregs[i]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004592 }
Riku Voipioc650c002014-04-23 13:53:45 +03004593 __put_user(env->nip, &frame->mc_gregs[TARGET_PT_NIP]);
4594 __put_user(env->ctr, &frame->mc_gregs[TARGET_PT_CTR]);
4595 __put_user(env->lr, &frame->mc_gregs[TARGET_PT_LNK]);
4596 __put_user(env->xer, &frame->mc_gregs[TARGET_PT_XER]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004597
4598 for (i = 0; i < ARRAY_SIZE(env->crf); i++) {
4599 ccr |= env->crf[i] << (32 - ((i + 1) * 4));
4600 }
Riku Voipioc650c002014-04-23 13:53:45 +03004601 __put_user(ccr, &frame->mc_gregs[TARGET_PT_CCR]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004602
4603 /* Save Altivec registers if necessary. */
4604 if (env->insns_flags & PPC_ALTIVEC) {
4605 for (i = 0; i < ARRAY_SIZE(env->avr); i++) {
Anthony Liguoric227f092009-10-01 16:12:16 -05004606 ppc_avr_t *avr = &env->avr[i];
4607 ppc_avr_t *vreg = &frame->mc_vregs.altivec[i];
Nathan Froydbcd49332009-05-12 19:13:18 -07004608
Riku Voipioc650c002014-04-23 13:53:45 +03004609 __put_user(avr->u64[0], &vreg->u64[0]);
4610 __put_user(avr->u64[1], &vreg->u64[1]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004611 }
4612 /* Set MSR_VR in the saved MSR value to indicate that
4613 frame->mc_vregs contains valid data. */
4614 msr |= MSR_VR;
Riku Voipioc650c002014-04-23 13:53:45 +03004615 __put_user((uint32_t)env->spr[SPR_VRSAVE],
4616 &frame->mc_vregs.altivec[32].u32[3]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004617 }
4618
4619 /* Save floating point registers. */
4620 if (env->insns_flags & PPC_FLOAT) {
4621 for (i = 0; i < ARRAY_SIZE(env->fpr); i++) {
Riku Voipioc650c002014-04-23 13:53:45 +03004622 __put_user(env->fpr[i], &frame->mc_fregs[i]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004623 }
Riku Voipioc650c002014-04-23 13:53:45 +03004624 __put_user((uint64_t) env->fpscr, &frame->mc_fregs[32]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004625 }
4626
4627 /* Save SPE registers. The kernel only saves the high half. */
4628 if (env->insns_flags & PPC_SPE) {
4629#if defined(TARGET_PPC64)
4630 for (i = 0; i < ARRAY_SIZE(env->gpr); i++) {
Riku Voipioc650c002014-04-23 13:53:45 +03004631 __put_user(env->gpr[i] >> 32, &frame->mc_vregs.spe[i]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004632 }
4633#else
4634 for (i = 0; i < ARRAY_SIZE(env->gprh); i++) {
Riku Voipioc650c002014-04-23 13:53:45 +03004635 __put_user(env->gprh[i], &frame->mc_vregs.spe[i]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004636 }
4637#endif
4638 /* Set MSR_SPE in the saved MSR value to indicate that
4639 frame->mc_vregs contains valid data. */
4640 msr |= MSR_SPE;
Riku Voipioc650c002014-04-23 13:53:45 +03004641 __put_user(env->spe_fscr, &frame->mc_vregs.spe[32]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004642 }
4643
4644 /* Store MSR. */
Riku Voipioc650c002014-04-23 13:53:45 +03004645 __put_user(msr, &frame->mc_gregs[TARGET_PT_MSR]);
Tom Musta76781082014-06-30 08:13:37 -05004646}
Nathan Froydbcd49332009-05-12 19:13:18 -07004647
Tom Musta76781082014-06-30 08:13:37 -05004648static void encode_trampoline(int sigret, uint32_t *tramp)
4649{
Nathan Froydbcd49332009-05-12 19:13:18 -07004650 /* Set up the sigreturn trampoline: li r0,sigret; sc. */
4651 if (sigret) {
Tom Musta76781082014-06-30 08:13:37 -05004652 __put_user(0x38000000 | sigret, &tramp[0]);
4653 __put_user(0x44000002, &tramp[1]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004654 }
Nathan Froydbcd49332009-05-12 19:13:18 -07004655}
4656
Riku Voipioc650c002014-04-23 13:53:45 +03004657static void restore_user_regs(CPUPPCState *env,
4658 struct target_mcontext *frame, int sig)
Nathan Froydbcd49332009-05-12 19:13:18 -07004659{
4660 target_ulong save_r2 = 0;
4661 target_ulong msr;
4662 target_ulong ccr;
4663
4664 int i;
4665
4666 if (!sig) {
4667 save_r2 = env->gpr[2];
4668 }
4669
4670 /* Restore general registers. */
4671 for (i = 0; i < ARRAY_SIZE(env->gpr); i++) {
Riku Voipioc650c002014-04-23 13:53:45 +03004672 __get_user(env->gpr[i], &frame->mc_gregs[i]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004673 }
Riku Voipioc650c002014-04-23 13:53:45 +03004674 __get_user(env->nip, &frame->mc_gregs[TARGET_PT_NIP]);
4675 __get_user(env->ctr, &frame->mc_gregs[TARGET_PT_CTR]);
4676 __get_user(env->lr, &frame->mc_gregs[TARGET_PT_LNK]);
4677 __get_user(env->xer, &frame->mc_gregs[TARGET_PT_XER]);
4678 __get_user(ccr, &frame->mc_gregs[TARGET_PT_CCR]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004679
4680 for (i = 0; i < ARRAY_SIZE(env->crf); i++) {
4681 env->crf[i] = (ccr >> (32 - ((i + 1) * 4))) & 0xf;
4682 }
4683
4684 if (!sig) {
4685 env->gpr[2] = save_r2;
4686 }
4687 /* Restore MSR. */
Riku Voipioc650c002014-04-23 13:53:45 +03004688 __get_user(msr, &frame->mc_gregs[TARGET_PT_MSR]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004689
4690 /* If doing signal return, restore the previous little-endian mode. */
4691 if (sig)
Laurent Vivier49e55cb2016-03-30 18:36:51 +02004692 env->msr = (env->msr & ~(1ull << MSR_LE)) | (msr & (1ull << MSR_LE));
Nathan Froydbcd49332009-05-12 19:13:18 -07004693
4694 /* Restore Altivec registers if necessary. */
4695 if (env->insns_flags & PPC_ALTIVEC) {
4696 for (i = 0; i < ARRAY_SIZE(env->avr); i++) {
Anthony Liguoric227f092009-10-01 16:12:16 -05004697 ppc_avr_t *avr = &env->avr[i];
4698 ppc_avr_t *vreg = &frame->mc_vregs.altivec[i];
Nathan Froydbcd49332009-05-12 19:13:18 -07004699
Riku Voipioc650c002014-04-23 13:53:45 +03004700 __get_user(avr->u64[0], &vreg->u64[0]);
4701 __get_user(avr->u64[1], &vreg->u64[1]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004702 }
4703 /* Set MSR_VEC in the saved MSR value to indicate that
4704 frame->mc_vregs contains valid data. */
Riku Voipioc650c002014-04-23 13:53:45 +03004705 __get_user(env->spr[SPR_VRSAVE],
4706 (target_ulong *)(&frame->mc_vregs.altivec[32].u32[3]));
Nathan Froydbcd49332009-05-12 19:13:18 -07004707 }
4708
4709 /* Restore floating point registers. */
4710 if (env->insns_flags & PPC_FLOAT) {
4711 uint64_t fpscr;
4712 for (i = 0; i < ARRAY_SIZE(env->fpr); i++) {
Riku Voipioc650c002014-04-23 13:53:45 +03004713 __get_user(env->fpr[i], &frame->mc_fregs[i]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004714 }
Riku Voipioc650c002014-04-23 13:53:45 +03004715 __get_user(fpscr, &frame->mc_fregs[32]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004716 env->fpscr = (uint32_t) fpscr;
4717 }
4718
4719 /* Save SPE registers. The kernel only saves the high half. */
4720 if (env->insns_flags & PPC_SPE) {
4721#if defined(TARGET_PPC64)
4722 for (i = 0; i < ARRAY_SIZE(env->gpr); i++) {
4723 uint32_t hi;
4724
Riku Voipioc650c002014-04-23 13:53:45 +03004725 __get_user(hi, &frame->mc_vregs.spe[i]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004726 env->gpr[i] = ((uint64_t)hi << 32) | ((uint32_t) env->gpr[i]);
4727 }
4728#else
4729 for (i = 0; i < ARRAY_SIZE(env->gprh); i++) {
Riku Voipioc650c002014-04-23 13:53:45 +03004730 __get_user(env->gprh[i], &frame->mc_vregs.spe[i]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004731 }
4732#endif
Riku Voipioc650c002014-04-23 13:53:45 +03004733 __get_user(env->spe_fscr, &frame->mc_vregs.spe[32]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004734 }
Nathan Froydbcd49332009-05-12 19:13:18 -07004735}
4736
4737static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01004738 target_sigset_t *set, CPUPPCState *env)
Nathan Froydbcd49332009-05-12 19:13:18 -07004739{
4740 struct target_sigframe *frame;
4741 struct target_sigcontext *sc;
4742 target_ulong frame_addr, newsp;
4743 int err = 0;
Tom Musta14585582014-06-30 08:13:42 -05004744#if defined(TARGET_PPC64)
4745 struct image_info *image = ((TaskState *)thread_cpu->opaque)->info;
4746#endif
Nathan Froydbcd49332009-05-12 19:13:18 -07004747
4748 frame_addr = get_sigframe(ka, env, sizeof(*frame));
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01004749 trace_user_setup_frame(env, frame_addr);
Nathan Froydbcd49332009-05-12 19:13:18 -07004750 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 1))
4751 goto sigsegv;
4752 sc = &frame->sctx;
4753
Riku Voipio1d8b5122014-04-23 10:26:05 +03004754 __put_user(ka->_sa_handler, &sc->handler);
4755 __put_user(set->sig[0], &sc->oldmask);
Tom Musta61e75fe2014-06-30 08:13:38 -05004756#if TARGET_ABI_BITS == 64
Riku Voipio1d8b5122014-04-23 10:26:05 +03004757 __put_user(set->sig[0] >> 32, &sc->_unused[3]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004758#else
Riku Voipio1d8b5122014-04-23 10:26:05 +03004759 __put_user(set->sig[1], &sc->_unused[3]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004760#endif
Riku Voipio1d8b5122014-04-23 10:26:05 +03004761 __put_user(h2g(&frame->mctx), &sc->regs);
4762 __put_user(sig, &sc->signal);
Nathan Froydbcd49332009-05-12 19:13:18 -07004763
4764 /* Save user regs. */
Tom Musta76781082014-06-30 08:13:37 -05004765 save_user_regs(env, &frame->mctx);
4766
4767 /* Construct the trampoline code on the stack. */
4768 encode_trampoline(TARGET_NR_sigreturn, (uint32_t *)&frame->mctx.tramp);
Nathan Froydbcd49332009-05-12 19:13:18 -07004769
4770 /* The kernel checks for the presence of a VDSO here. We don't
4771 emulate a vdso, so use a sigreturn system call. */
4772 env->lr = (target_ulong) h2g(frame->mctx.tramp);
4773
4774 /* Turn off all fp exceptions. */
4775 env->fpscr = 0;
4776
4777 /* Create a stack frame for the caller of the handler. */
4778 newsp = frame_addr - SIGNAL_FRAMESIZE;
Samuel Seaybeb526b2013-01-02 10:53:46 +00004779 err |= put_user(env->gpr[1], newsp, target_ulong);
Nathan Froydbcd49332009-05-12 19:13:18 -07004780
4781 if (err)
4782 goto sigsegv;
4783
4784 /* Set up registers for signal handler. */
4785 env->gpr[1] = newsp;
Peter Maydellb6e2c932015-01-08 12:19:43 +00004786 env->gpr[3] = sig;
Samuel Seay61993a62013-01-04 14:35:48 +00004787 env->gpr[4] = frame_addr + offsetof(struct target_sigframe, sctx);
Tom Musta8d6ab332014-06-30 08:13:39 -05004788
4789#if defined(TARGET_PPC64)
Tom Musta14585582014-06-30 08:13:42 -05004790 if (get_ppc64_abi(image) < 2) {
4791 /* ELFv1 PPC64 function pointers are pointers to OPD entries. */
4792 struct target_func_ptr *handler =
4793 (struct target_func_ptr *)g2h(ka->_sa_handler);
4794 env->nip = tswapl(handler->entry);
4795 env->gpr[2] = tswapl(handler->toc);
4796 } else {
4797 /* ELFv2 PPC64 function pointers are entry points, but R12
4798 * must also be set */
4799 env->nip = tswapl((target_ulong) ka->_sa_handler);
4800 env->gpr[12] = env->nip;
4801 }
Tom Musta8d6ab332014-06-30 08:13:39 -05004802#else
Nathan Froydbcd49332009-05-12 19:13:18 -07004803 env->nip = (target_ulong) ka->_sa_handler;
Tom Musta8d6ab332014-06-30 08:13:39 -05004804#endif
4805
Nathan Froydbcd49332009-05-12 19:13:18 -07004806 /* Signal handlers are entered in big-endian mode. */
Laurent Vivier49e55cb2016-03-30 18:36:51 +02004807 env->msr &= ~(1ull << MSR_LE);
Nathan Froydbcd49332009-05-12 19:13:18 -07004808
4809 unlock_user_struct(frame, frame_addr, 1);
4810 return;
4811
4812sigsegv:
4813 unlock_user_struct(frame, frame_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02004814 force_sig(TARGET_SIGSEGV);
Nathan Froydbcd49332009-05-12 19:13:18 -07004815}
4816
4817static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05004818 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01004819 target_sigset_t *set, CPUPPCState *env)
Nathan Froydbcd49332009-05-12 19:13:18 -07004820{
4821 struct target_rt_sigframe *rt_sf;
Tom Musta61e75fe2014-06-30 08:13:38 -05004822 uint32_t *trampptr = 0;
4823 struct target_mcontext *mctx = 0;
Nathan Froydbcd49332009-05-12 19:13:18 -07004824 target_ulong rt_sf_addr, newsp = 0;
4825 int i, err = 0;
Tom Musta14585582014-06-30 08:13:42 -05004826#if defined(TARGET_PPC64)
4827 struct image_info *image = ((TaskState *)thread_cpu->opaque)->info;
4828#endif
Nathan Froydbcd49332009-05-12 19:13:18 -07004829
4830 rt_sf_addr = get_sigframe(ka, env, sizeof(*rt_sf));
4831 if (!lock_user_struct(VERIFY_WRITE, rt_sf, rt_sf_addr, 1))
4832 goto sigsegv;
4833
Peter Maydellf6c7a052015-01-08 12:19:48 +00004834 tswap_siginfo(&rt_sf->info, info);
Nathan Froydbcd49332009-05-12 19:13:18 -07004835
Riku Voipio1d8b5122014-04-23 10:26:05 +03004836 __put_user(0, &rt_sf->uc.tuc_flags);
4837 __put_user(0, &rt_sf->uc.tuc_link);
4838 __put_user((target_ulong)target_sigaltstack_used.ss_sp,
4839 &rt_sf->uc.tuc_stack.ss_sp);
4840 __put_user(sas_ss_flags(env->gpr[1]),
4841 &rt_sf->uc.tuc_stack.ss_flags);
4842 __put_user(target_sigaltstack_used.ss_size,
4843 &rt_sf->uc.tuc_stack.ss_size);
Tom Musta61e75fe2014-06-30 08:13:38 -05004844#if !defined(TARGET_PPC64)
Riku Voipio1d8b5122014-04-23 10:26:05 +03004845 __put_user(h2g (&rt_sf->uc.tuc_mcontext),
4846 &rt_sf->uc.tuc_regs);
Tom Musta61e75fe2014-06-30 08:13:38 -05004847#endif
Nathan Froydbcd49332009-05-12 19:13:18 -07004848 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03004849 __put_user(set->sig[i], &rt_sf->uc.tuc_sigmask.sig[i]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004850 }
4851
Tom Musta61e75fe2014-06-30 08:13:38 -05004852#if defined(TARGET_PPC64)
4853 mctx = &rt_sf->uc.tuc_sigcontext.mcontext;
4854 trampptr = &rt_sf->trampoline[0];
4855#else
4856 mctx = &rt_sf->uc.tuc_mcontext;
4857 trampptr = (uint32_t *)&rt_sf->uc.tuc_mcontext.tramp;
4858#endif
4859
4860 save_user_regs(env, mctx);
4861 encode_trampoline(TARGET_NR_rt_sigreturn, trampptr);
Nathan Froydbcd49332009-05-12 19:13:18 -07004862
4863 /* The kernel checks for the presence of a VDSO here. We don't
4864 emulate a vdso, so use a sigreturn system call. */
Tom Musta61e75fe2014-06-30 08:13:38 -05004865 env->lr = (target_ulong) h2g(trampptr);
Nathan Froydbcd49332009-05-12 19:13:18 -07004866
4867 /* Turn off all fp exceptions. */
4868 env->fpscr = 0;
4869
4870 /* Create a stack frame for the caller of the handler. */
4871 newsp = rt_sf_addr - (SIGNAL_FRAMESIZE + 16);
Tom Mustafbdc2002014-06-30 08:13:36 -05004872 err |= put_user(env->gpr[1], newsp, target_ulong);
Nathan Froydbcd49332009-05-12 19:13:18 -07004873
4874 if (err)
4875 goto sigsegv;
4876
4877 /* Set up registers for signal handler. */
4878 env->gpr[1] = newsp;
Peter Maydellb6e2c932015-01-08 12:19:43 +00004879 env->gpr[3] = (target_ulong) sig;
Nathan Froydbcd49332009-05-12 19:13:18 -07004880 env->gpr[4] = (target_ulong) h2g(&rt_sf->info);
4881 env->gpr[5] = (target_ulong) h2g(&rt_sf->uc);
4882 env->gpr[6] = (target_ulong) h2g(rt_sf);
Tom Musta8d6ab332014-06-30 08:13:39 -05004883
4884#if defined(TARGET_PPC64)
Tom Musta14585582014-06-30 08:13:42 -05004885 if (get_ppc64_abi(image) < 2) {
4886 /* ELFv1 PPC64 function pointers are pointers to OPD entries. */
4887 struct target_func_ptr *handler =
4888 (struct target_func_ptr *)g2h(ka->_sa_handler);
4889 env->nip = tswapl(handler->entry);
4890 env->gpr[2] = tswapl(handler->toc);
4891 } else {
4892 /* ELFv2 PPC64 function pointers are entry points, but R12
4893 * must also be set */
4894 env->nip = tswapl((target_ulong) ka->_sa_handler);
4895 env->gpr[12] = env->nip;
4896 }
Tom Musta8d6ab332014-06-30 08:13:39 -05004897#else
Nathan Froydbcd49332009-05-12 19:13:18 -07004898 env->nip = (target_ulong) ka->_sa_handler;
Tom Musta8d6ab332014-06-30 08:13:39 -05004899#endif
4900
Nathan Froydbcd49332009-05-12 19:13:18 -07004901 /* Signal handlers are entered in big-endian mode. */
Laurent Vivier49e55cb2016-03-30 18:36:51 +02004902 env->msr &= ~(1ull << MSR_LE);
Nathan Froydbcd49332009-05-12 19:13:18 -07004903
4904 unlock_user_struct(rt_sf, rt_sf_addr, 1);
4905 return;
4906
4907sigsegv:
4908 unlock_user_struct(rt_sf, rt_sf_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02004909 force_sig(TARGET_SIGSEGV);
Nathan Froydbcd49332009-05-12 19:13:18 -07004910
4911}
4912
Andreas Färber05390242012-02-25 03:37:53 +01004913long do_sigreturn(CPUPPCState *env)
Nathan Froydbcd49332009-05-12 19:13:18 -07004914{
4915 struct target_sigcontext *sc = NULL;
4916 struct target_mcontext *sr = NULL;
Peter Maydellb04636f2013-07-29 12:00:31 +01004917 target_ulong sr_addr = 0, sc_addr;
Nathan Froydbcd49332009-05-12 19:13:18 -07004918 sigset_t blocked;
Anthony Liguoric227f092009-10-01 16:12:16 -05004919 target_sigset_t set;
Nathan Froydbcd49332009-05-12 19:13:18 -07004920
4921 sc_addr = env->gpr[1] + SIGNAL_FRAMESIZE;
4922 if (!lock_user_struct(VERIFY_READ, sc, sc_addr, 1))
4923 goto sigsegv;
4924
4925#if defined(TARGET_PPC64)
Tom Musta61e75fe2014-06-30 08:13:38 -05004926 set.sig[0] = sc->oldmask + ((uint64_t)(sc->_unused[3]) << 32);
Nathan Froydbcd49332009-05-12 19:13:18 -07004927#else
Riku Voipiof5f601a2014-04-23 13:00:17 +03004928 __get_user(set.sig[0], &sc->oldmask);
4929 __get_user(set.sig[1], &sc->_unused[3]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004930#endif
4931 target_to_host_sigset_internal(&blocked, &set);
Peter Maydell9eede5b2016-05-27 15:51:46 +01004932 set_sigmask(&blocked);
Nathan Froydbcd49332009-05-12 19:13:18 -07004933
Riku Voipiof5f601a2014-04-23 13:00:17 +03004934 __get_user(sr_addr, &sc->regs);
Nathan Froydbcd49332009-05-12 19:13:18 -07004935 if (!lock_user_struct(VERIFY_READ, sr, sr_addr, 1))
4936 goto sigsegv;
Riku Voipioc650c002014-04-23 13:53:45 +03004937 restore_user_regs(env, sr, 1);
Nathan Froydbcd49332009-05-12 19:13:18 -07004938
4939 unlock_user_struct(sr, sr_addr, 1);
4940 unlock_user_struct(sc, sc_addr, 1);
4941 return -TARGET_QEMU_ESIGRETURN;
4942
4943sigsegv:
4944 unlock_user_struct(sr, sr_addr, 1);
4945 unlock_user_struct(sc, sc_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02004946 force_sig(TARGET_SIGSEGV);
Nathan Froydbcd49332009-05-12 19:13:18 -07004947 return 0;
4948}
4949
4950/* See arch/powerpc/kernel/signal_32.c. */
Andreas Färber05390242012-02-25 03:37:53 +01004951static int do_setcontext(struct target_ucontext *ucp, CPUPPCState *env, int sig)
Nathan Froydbcd49332009-05-12 19:13:18 -07004952{
4953 struct target_mcontext *mcp;
4954 target_ulong mcp_addr;
4955 sigset_t blocked;
Anthony Liguoric227f092009-10-01 16:12:16 -05004956 target_sigset_t set;
Nathan Froydbcd49332009-05-12 19:13:18 -07004957
Aurelien Jarno60e99242010-03-29 02:12:51 +02004958 if (copy_from_user(&set, h2g(ucp) + offsetof(struct target_ucontext, tuc_sigmask),
Nathan Froydbcd49332009-05-12 19:13:18 -07004959 sizeof (set)))
4960 return 1;
4961
Tom Musta19774ec2014-06-30 08:13:40 -05004962#if defined(TARGET_PPC64)
4963 mcp_addr = h2g(ucp) +
4964 offsetof(struct target_ucontext, tuc_sigcontext.mcontext);
4965#else
Riku Voipio9e918dc2014-04-23 14:05:09 +03004966 __get_user(mcp_addr, &ucp->tuc_regs);
Tom Musta19774ec2014-06-30 08:13:40 -05004967#endif
Nathan Froydbcd49332009-05-12 19:13:18 -07004968
4969 if (!lock_user_struct(VERIFY_READ, mcp, mcp_addr, 1))
4970 return 1;
4971
4972 target_to_host_sigset_internal(&blocked, &set);
Peter Maydell9eede5b2016-05-27 15:51:46 +01004973 set_sigmask(&blocked);
Riku Voipioc650c002014-04-23 13:53:45 +03004974 restore_user_regs(env, mcp, sig);
Nathan Froydbcd49332009-05-12 19:13:18 -07004975
4976 unlock_user_struct(mcp, mcp_addr, 1);
4977 return 0;
Nathan Froydbcd49332009-05-12 19:13:18 -07004978}
4979
Andreas Färber05390242012-02-25 03:37:53 +01004980long do_rt_sigreturn(CPUPPCState *env)
Nathan Froydbcd49332009-05-12 19:13:18 -07004981{
4982 struct target_rt_sigframe *rt_sf = NULL;
4983 target_ulong rt_sf_addr;
4984
4985 rt_sf_addr = env->gpr[1] + SIGNAL_FRAMESIZE + 16;
4986 if (!lock_user_struct(VERIFY_READ, rt_sf, rt_sf_addr, 1))
4987 goto sigsegv;
4988
4989 if (do_setcontext(&rt_sf->uc, env, 1))
4990 goto sigsegv;
4991
4992 do_sigaltstack(rt_sf_addr
Aurelien Jarno60e99242010-03-29 02:12:51 +02004993 + offsetof(struct target_rt_sigframe, uc.tuc_stack),
Nathan Froydbcd49332009-05-12 19:13:18 -07004994 0, env->gpr[1]);
4995
4996 unlock_user_struct(rt_sf, rt_sf_addr, 1);
4997 return -TARGET_QEMU_ESIGRETURN;
4998
4999sigsegv:
5000 unlock_user_struct(rt_sf, rt_sf_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02005001 force_sig(TARGET_SIGSEGV);
Nathan Froydbcd49332009-05-12 19:13:18 -07005002 return 0;
5003}
5004
Laurent Vivier492a8742009-08-03 16:12:17 +02005005#elif defined(TARGET_M68K)
5006
5007struct target_sigcontext {
5008 abi_ulong sc_mask;
5009 abi_ulong sc_usp;
5010 abi_ulong sc_d0;
5011 abi_ulong sc_d1;
5012 abi_ulong sc_a0;
5013 abi_ulong sc_a1;
5014 unsigned short sc_sr;
5015 abi_ulong sc_pc;
5016};
5017
5018struct target_sigframe
5019{
5020 abi_ulong pretcode;
5021 int sig;
5022 int code;
5023 abi_ulong psc;
5024 char retcode[8];
5025 abi_ulong extramask[TARGET_NSIG_WORDS-1];
5026 struct target_sigcontext sc;
5027};
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01005028
Anthony Liguoric227f092009-10-01 16:12:16 -05005029typedef int target_greg_t;
Laurent Vivier71811552009-08-03 16:12:18 +02005030#define TARGET_NGREG 18
Anthony Liguoric227f092009-10-01 16:12:16 -05005031typedef target_greg_t target_gregset_t[TARGET_NGREG];
Laurent Vivier71811552009-08-03 16:12:18 +02005032
5033typedef struct target_fpregset {
5034 int f_fpcntl[3];
5035 int f_fpregs[8*3];
Anthony Liguoric227f092009-10-01 16:12:16 -05005036} target_fpregset_t;
Laurent Vivier71811552009-08-03 16:12:18 +02005037
5038struct target_mcontext {
5039 int version;
Anthony Liguoric227f092009-10-01 16:12:16 -05005040 target_gregset_t gregs;
5041 target_fpregset_t fpregs;
Laurent Vivier71811552009-08-03 16:12:18 +02005042};
5043
5044#define TARGET_MCONTEXT_VERSION 2
5045
5046struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02005047 abi_ulong tuc_flags;
5048 abi_ulong tuc_link;
5049 target_stack_t tuc_stack;
5050 struct target_mcontext tuc_mcontext;
5051 abi_long tuc_filler[80];
5052 target_sigset_t tuc_sigmask;
Laurent Vivier71811552009-08-03 16:12:18 +02005053};
5054
5055struct target_rt_sigframe
5056{
5057 abi_ulong pretcode;
5058 int sig;
5059 abi_ulong pinfo;
5060 abi_ulong puc;
5061 char retcode[8];
5062 struct target_siginfo info;
5063 struct target_ucontext uc;
5064};
Laurent Vivier492a8742009-08-03 16:12:17 +02005065
Riku Voipio41ecc722014-04-23 11:01:00 +03005066static void setup_sigcontext(struct target_sigcontext *sc, CPUM68KState *env,
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01005067 abi_ulong mask)
Laurent Vivier492a8742009-08-03 16:12:17 +02005068{
Riku Voipio1d8b5122014-04-23 10:26:05 +03005069 __put_user(mask, &sc->sc_mask);
5070 __put_user(env->aregs[7], &sc->sc_usp);
5071 __put_user(env->dregs[0], &sc->sc_d0);
5072 __put_user(env->dregs[1], &sc->sc_d1);
5073 __put_user(env->aregs[0], &sc->sc_a0);
5074 __put_user(env->aregs[1], &sc->sc_a1);
5075 __put_user(env->sr, &sc->sc_sr);
5076 __put_user(env->pc, &sc->sc_pc);
Laurent Vivier492a8742009-08-03 16:12:17 +02005077}
5078
Riku Voipio016d2e12014-04-23 11:19:48 +03005079static void
Timothy E Baldwin7ccb84a2016-05-12 18:47:39 +01005080restore_sigcontext(CPUM68KState *env, struct target_sigcontext *sc)
Laurent Vivier492a8742009-08-03 16:12:17 +02005081{
Laurent Vivier492a8742009-08-03 16:12:17 +02005082 int temp;
5083
Riku Voipio1d8b5122014-04-23 10:26:05 +03005084 __get_user(env->aregs[7], &sc->sc_usp);
Timothy E Baldwin7ccb84a2016-05-12 18:47:39 +01005085 __get_user(env->dregs[0], &sc->sc_d0);
Riku Voipio1d8b5122014-04-23 10:26:05 +03005086 __get_user(env->dregs[1], &sc->sc_d1);
5087 __get_user(env->aregs[0], &sc->sc_a0);
5088 __get_user(env->aregs[1], &sc->sc_a1);
5089 __get_user(env->pc, &sc->sc_pc);
5090 __get_user(temp, &sc->sc_sr);
Laurent Vivier492a8742009-08-03 16:12:17 +02005091 env->sr = (env->sr & 0xff00) | (temp & 0xff);
Laurent Vivier492a8742009-08-03 16:12:17 +02005092}
5093
5094/*
5095 * Determine which stack to use..
5096 */
5097static inline abi_ulong
Andreas Färber05390242012-02-25 03:37:53 +01005098get_sigframe(struct target_sigaction *ka, CPUM68KState *regs,
5099 size_t frame_size)
Laurent Vivier492a8742009-08-03 16:12:17 +02005100{
5101 unsigned long sp;
5102
5103 sp = regs->aregs[7];
5104
5105 /* This is the X/Open sanctioned signal stack switching. */
5106 if ((ka->sa_flags & TARGET_SA_ONSTACK) && (sas_ss_flags (sp) == 0)) {
5107 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
5108 }
5109
5110 return ((sp - frame_size) & -8UL);
5111}
5112
5113static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01005114 target_sigset_t *set, CPUM68KState *env)
Laurent Vivier492a8742009-08-03 16:12:17 +02005115{
5116 struct target_sigframe *frame;
5117 abi_ulong frame_addr;
5118 abi_ulong retcode_addr;
5119 abi_ulong sc_addr;
Laurent Vivier492a8742009-08-03 16:12:17 +02005120 int i;
5121
5122 frame_addr = get_sigframe(ka, env, sizeof *frame);
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01005123 trace_user_setup_frame(env, frame_addr);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01005124 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
5125 goto give_sigsegv;
5126 }
Laurent Vivier492a8742009-08-03 16:12:17 +02005127
Riku Voipio1d8b5122014-04-23 10:26:05 +03005128 __put_user(sig, &frame->sig);
Laurent Vivier492a8742009-08-03 16:12:17 +02005129
5130 sc_addr = frame_addr + offsetof(struct target_sigframe, sc);
Riku Voipio1d8b5122014-04-23 10:26:05 +03005131 __put_user(sc_addr, &frame->psc);
Laurent Vivier492a8742009-08-03 16:12:17 +02005132
Riku Voipio41ecc722014-04-23 11:01:00 +03005133 setup_sigcontext(&frame->sc, env, set->sig[0]);
Laurent Vivier492a8742009-08-03 16:12:17 +02005134
5135 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
Riku Voipio0188fad2014-04-23 13:34:15 +03005136 __put_user(set->sig[i], &frame->extramask[i - 1]);
Laurent Vivier492a8742009-08-03 16:12:17 +02005137 }
5138
5139 /* Set up to return from userspace. */
5140
5141 retcode_addr = frame_addr + offsetof(struct target_sigframe, retcode);
Riku Voipio1d8b5122014-04-23 10:26:05 +03005142 __put_user(retcode_addr, &frame->pretcode);
Laurent Vivier492a8742009-08-03 16:12:17 +02005143
5144 /* moveq #,d0; trap #0 */
5145
Riku Voipio1d8b5122014-04-23 10:26:05 +03005146 __put_user(0x70004e40 + (TARGET_NR_sigreturn << 16),
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01005147 (uint32_t *)(frame->retcode));
Laurent Vivier492a8742009-08-03 16:12:17 +02005148
Laurent Vivier492a8742009-08-03 16:12:17 +02005149 /* Set up to return from userspace */
5150
5151 env->aregs[7] = frame_addr;
5152 env->pc = ka->_sa_handler;
5153
5154 unlock_user_struct(frame, frame_addr, 1);
5155 return;
5156
5157give_sigsegv:
Riku Voipio66393fb2009-12-04 15:16:32 +02005158 force_sig(TARGET_SIGSEGV);
Laurent Vivier492a8742009-08-03 16:12:17 +02005159}
5160
Laurent Vivier71811552009-08-03 16:12:18 +02005161static inline int target_rt_setup_ucontext(struct target_ucontext *uc,
Andreas Färber05390242012-02-25 03:37:53 +01005162 CPUM68KState *env)
Laurent Vivier71811552009-08-03 16:12:18 +02005163{
Aurelien Jarno60e99242010-03-29 02:12:51 +02005164 target_greg_t *gregs = uc->tuc_mcontext.gregs;
Laurent Vivier71811552009-08-03 16:12:18 +02005165
Riku Voipio1d8b5122014-04-23 10:26:05 +03005166 __put_user(TARGET_MCONTEXT_VERSION, &uc->tuc_mcontext.version);
5167 __put_user(env->dregs[0], &gregs[0]);
5168 __put_user(env->dregs[1], &gregs[1]);
5169 __put_user(env->dregs[2], &gregs[2]);
5170 __put_user(env->dregs[3], &gregs[3]);
5171 __put_user(env->dregs[4], &gregs[4]);
5172 __put_user(env->dregs[5], &gregs[5]);
5173 __put_user(env->dregs[6], &gregs[6]);
5174 __put_user(env->dregs[7], &gregs[7]);
5175 __put_user(env->aregs[0], &gregs[8]);
5176 __put_user(env->aregs[1], &gregs[9]);
5177 __put_user(env->aregs[2], &gregs[10]);
5178 __put_user(env->aregs[3], &gregs[11]);
5179 __put_user(env->aregs[4], &gregs[12]);
5180 __put_user(env->aregs[5], &gregs[13]);
5181 __put_user(env->aregs[6], &gregs[14]);
5182 __put_user(env->aregs[7], &gregs[15]);
5183 __put_user(env->pc, &gregs[16]);
5184 __put_user(env->sr, &gregs[17]);
Laurent Vivier71811552009-08-03 16:12:18 +02005185
Riku Voipio1d8b5122014-04-23 10:26:05 +03005186 return 0;
Laurent Vivier71811552009-08-03 16:12:18 +02005187}
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01005188
Andreas Färber05390242012-02-25 03:37:53 +01005189static inline int target_rt_restore_ucontext(CPUM68KState *env,
Timothy E Baldwin7ccb84a2016-05-12 18:47:39 +01005190 struct target_ucontext *uc)
Laurent Vivier71811552009-08-03 16:12:18 +02005191{
5192 int temp;
Aurelien Jarno60e99242010-03-29 02:12:51 +02005193 target_greg_t *gregs = uc->tuc_mcontext.gregs;
Laurent Vivier71811552009-08-03 16:12:18 +02005194
Riku Voipio1d8b5122014-04-23 10:26:05 +03005195 __get_user(temp, &uc->tuc_mcontext.version);
Laurent Vivier71811552009-08-03 16:12:18 +02005196 if (temp != TARGET_MCONTEXT_VERSION)
5197 goto badframe;
5198
5199 /* restore passed registers */
Riku Voipio1d8b5122014-04-23 10:26:05 +03005200 __get_user(env->dregs[0], &gregs[0]);
5201 __get_user(env->dregs[1], &gregs[1]);
5202 __get_user(env->dregs[2], &gregs[2]);
5203 __get_user(env->dregs[3], &gregs[3]);
5204 __get_user(env->dregs[4], &gregs[4]);
5205 __get_user(env->dregs[5], &gregs[5]);
5206 __get_user(env->dregs[6], &gregs[6]);
5207 __get_user(env->dregs[7], &gregs[7]);
5208 __get_user(env->aregs[0], &gregs[8]);
5209 __get_user(env->aregs[1], &gregs[9]);
5210 __get_user(env->aregs[2], &gregs[10]);
5211 __get_user(env->aregs[3], &gregs[11]);
5212 __get_user(env->aregs[4], &gregs[12]);
5213 __get_user(env->aregs[5], &gregs[13]);
5214 __get_user(env->aregs[6], &gregs[14]);
5215 __get_user(env->aregs[7], &gregs[15]);
5216 __get_user(env->pc, &gregs[16]);
5217 __get_user(temp, &gregs[17]);
Laurent Vivier71811552009-08-03 16:12:18 +02005218 env->sr = (env->sr & 0xff00) | (temp & 0xff);
5219
Riku Voipio1d8b5122014-04-23 10:26:05 +03005220 return 0;
Laurent Vivier71811552009-08-03 16:12:18 +02005221
5222badframe:
5223 return 1;
5224}
5225
Laurent Vivier492a8742009-08-03 16:12:17 +02005226static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05005227 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01005228 target_sigset_t *set, CPUM68KState *env)
Laurent Vivier492a8742009-08-03 16:12:17 +02005229{
Laurent Vivier71811552009-08-03 16:12:18 +02005230 struct target_rt_sigframe *frame;
5231 abi_ulong frame_addr;
5232 abi_ulong retcode_addr;
5233 abi_ulong info_addr;
5234 abi_ulong uc_addr;
5235 int err = 0;
5236 int i;
5237
5238 frame_addr = get_sigframe(ka, env, sizeof *frame);
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01005239 trace_user_setup_rt_frame(env, frame_addr);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01005240 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
5241 goto give_sigsegv;
5242 }
Laurent Vivier71811552009-08-03 16:12:18 +02005243
Riku Voipio1d8b5122014-04-23 10:26:05 +03005244 __put_user(sig, &frame->sig);
Laurent Vivier71811552009-08-03 16:12:18 +02005245
5246 info_addr = frame_addr + offsetof(struct target_rt_sigframe, info);
Riku Voipio1d8b5122014-04-23 10:26:05 +03005247 __put_user(info_addr, &frame->pinfo);
Laurent Vivier71811552009-08-03 16:12:18 +02005248
5249 uc_addr = frame_addr + offsetof(struct target_rt_sigframe, uc);
Riku Voipio1d8b5122014-04-23 10:26:05 +03005250 __put_user(uc_addr, &frame->puc);
Laurent Vivier71811552009-08-03 16:12:18 +02005251
Peter Maydellf6c7a052015-01-08 12:19:48 +00005252 tswap_siginfo(&frame->info, info);
Laurent Vivier71811552009-08-03 16:12:18 +02005253
5254 /* Create the ucontext */
5255
Riku Voipio1d8b5122014-04-23 10:26:05 +03005256 __put_user(0, &frame->uc.tuc_flags);
5257 __put_user(0, &frame->uc.tuc_link);
5258 __put_user(target_sigaltstack_used.ss_sp,
5259 &frame->uc.tuc_stack.ss_sp);
5260 __put_user(sas_ss_flags(env->aregs[7]),
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01005261 &frame->uc.tuc_stack.ss_flags);
Riku Voipio1d8b5122014-04-23 10:26:05 +03005262 __put_user(target_sigaltstack_used.ss_size,
5263 &frame->uc.tuc_stack.ss_size);
Laurent Vivier71811552009-08-03 16:12:18 +02005264 err |= target_rt_setup_ucontext(&frame->uc, env);
5265
5266 if (err)
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01005267 goto give_sigsegv;
Laurent Vivier71811552009-08-03 16:12:18 +02005268
5269 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
Riku Voipio0188fad2014-04-23 13:34:15 +03005270 __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
Laurent Vivier71811552009-08-03 16:12:18 +02005271 }
5272
5273 /* Set up to return from userspace. */
5274
5275 retcode_addr = frame_addr + offsetof(struct target_sigframe, retcode);
Riku Voipio1d8b5122014-04-23 10:26:05 +03005276 __put_user(retcode_addr, &frame->pretcode);
Laurent Vivier71811552009-08-03 16:12:18 +02005277
5278 /* moveq #,d0; notb d0; trap #0 */
5279
Riku Voipio1d8b5122014-04-23 10:26:05 +03005280 __put_user(0x70004600 + ((TARGET_NR_rt_sigreturn ^ 0xff) << 16),
Peter Maydell1669add2014-12-22 17:47:00 +00005281 (uint32_t *)(frame->retcode + 0));
5282 __put_user(0x4e40, (uint16_t *)(frame->retcode + 4));
Laurent Vivier71811552009-08-03 16:12:18 +02005283
5284 if (err)
5285 goto give_sigsegv;
5286
5287 /* Set up to return from userspace */
5288
5289 env->aregs[7] = frame_addr;
5290 env->pc = ka->_sa_handler;
5291
5292 unlock_user_struct(frame, frame_addr, 1);
5293 return;
5294
5295give_sigsegv:
5296 unlock_user_struct(frame, frame_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02005297 force_sig(TARGET_SIGSEGV);
Laurent Vivier492a8742009-08-03 16:12:17 +02005298}
5299
Andreas Färber05390242012-02-25 03:37:53 +01005300long do_sigreturn(CPUM68KState *env)
Laurent Vivier492a8742009-08-03 16:12:17 +02005301{
5302 struct target_sigframe *frame;
5303 abi_ulong frame_addr = env->aregs[7] - 4;
Anthony Liguoric227f092009-10-01 16:12:16 -05005304 target_sigset_t target_set;
Laurent Vivier492a8742009-08-03 16:12:17 +02005305 sigset_t set;
Timothy E Baldwin7ccb84a2016-05-12 18:47:39 +01005306 int i;
Laurent Vivier492a8742009-08-03 16:12:17 +02005307
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01005308 trace_user_do_sigreturn(env, frame_addr);
Laurent Vivier492a8742009-08-03 16:12:17 +02005309 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
5310 goto badframe;
5311
5312 /* set blocked signals */
5313
Riku Voipiof5f601a2014-04-23 13:00:17 +03005314 __get_user(target_set.sig[0], &frame->sc.sc_mask);
Laurent Vivier492a8742009-08-03 16:12:17 +02005315
5316 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
Riku Voipiof5f601a2014-04-23 13:00:17 +03005317 __get_user(target_set.sig[i], &frame->extramask[i - 1]);
Laurent Vivier492a8742009-08-03 16:12:17 +02005318 }
5319
5320 target_to_host_sigset_internal(&set, &target_set);
Peter Maydell9eede5b2016-05-27 15:51:46 +01005321 set_sigmask(&set);
Laurent Vivier492a8742009-08-03 16:12:17 +02005322
5323 /* restore registers */
5324
Timothy E Baldwin7ccb84a2016-05-12 18:47:39 +01005325 restore_sigcontext(env, &frame->sc);
Laurent Vivier492a8742009-08-03 16:12:17 +02005326
5327 unlock_user_struct(frame, frame_addr, 0);
Timothy E Baldwin7ccb84a2016-05-12 18:47:39 +01005328 return -TARGET_QEMU_ESIGRETURN;
Laurent Vivier492a8742009-08-03 16:12:17 +02005329
5330badframe:
Laurent Vivier492a8742009-08-03 16:12:17 +02005331 force_sig(TARGET_SIGSEGV);
5332 return 0;
5333}
5334
Andreas Färber05390242012-02-25 03:37:53 +01005335long do_rt_sigreturn(CPUM68KState *env)
Laurent Vivier492a8742009-08-03 16:12:17 +02005336{
Laurent Vivier71811552009-08-03 16:12:18 +02005337 struct target_rt_sigframe *frame;
5338 abi_ulong frame_addr = env->aregs[7] - 4;
Anthony Liguoric227f092009-10-01 16:12:16 -05005339 target_sigset_t target_set;
Laurent Vivier71811552009-08-03 16:12:18 +02005340 sigset_t set;
Laurent Vivier71811552009-08-03 16:12:18 +02005341
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01005342 trace_user_do_rt_sigreturn(env, frame_addr);
Laurent Vivier71811552009-08-03 16:12:18 +02005343 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
5344 goto badframe;
5345
5346 target_to_host_sigset_internal(&set, &target_set);
Peter Maydell9eede5b2016-05-27 15:51:46 +01005347 set_sigmask(&set);
Laurent Vivier71811552009-08-03 16:12:18 +02005348
5349 /* restore registers */
5350
Timothy E Baldwin7ccb84a2016-05-12 18:47:39 +01005351 if (target_rt_restore_ucontext(env, &frame->uc))
Laurent Vivier71811552009-08-03 16:12:18 +02005352 goto badframe;
5353
5354 if (do_sigaltstack(frame_addr +
Aurelien Jarno60e99242010-03-29 02:12:51 +02005355 offsetof(struct target_rt_sigframe, uc.tuc_stack),
Laurent Vivier71811552009-08-03 16:12:18 +02005356 0, get_sp_from_cpustate(env)) == -EFAULT)
5357 goto badframe;
5358
5359 unlock_user_struct(frame, frame_addr, 0);
Timothy E Baldwin7ccb84a2016-05-12 18:47:39 +01005360 return -TARGET_QEMU_ESIGRETURN;
Laurent Vivier71811552009-08-03 16:12:18 +02005361
5362badframe:
5363 unlock_user_struct(frame, frame_addr, 0);
5364 force_sig(TARGET_SIGSEGV);
5365 return 0;
Laurent Vivier492a8742009-08-03 16:12:17 +02005366}
5367
Richard Henderson6049f4f2009-12-27 18:30:03 -08005368#elif defined(TARGET_ALPHA)
5369
5370struct target_sigcontext {
5371 abi_long sc_onstack;
5372 abi_long sc_mask;
5373 abi_long sc_pc;
5374 abi_long sc_ps;
5375 abi_long sc_regs[32];
5376 abi_long sc_ownedfp;
5377 abi_long sc_fpregs[32];
5378 abi_ulong sc_fpcr;
5379 abi_ulong sc_fp_control;
5380 abi_ulong sc_reserved1;
5381 abi_ulong sc_reserved2;
5382 abi_ulong sc_ssize;
5383 abi_ulong sc_sbase;
5384 abi_ulong sc_traparg_a0;
5385 abi_ulong sc_traparg_a1;
5386 abi_ulong sc_traparg_a2;
5387 abi_ulong sc_fp_trap_pc;
5388 abi_ulong sc_fp_trigger_sum;
5389 abi_ulong sc_fp_trigger_inst;
5390};
5391
5392struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02005393 abi_ulong tuc_flags;
5394 abi_ulong tuc_link;
5395 abi_ulong tuc_osf_sigmask;
5396 target_stack_t tuc_stack;
5397 struct target_sigcontext tuc_mcontext;
5398 target_sigset_t tuc_sigmask;
Richard Henderson6049f4f2009-12-27 18:30:03 -08005399};
5400
5401struct target_sigframe {
5402 struct target_sigcontext sc;
5403 unsigned int retcode[3];
5404};
5405
5406struct target_rt_sigframe {
5407 target_siginfo_t info;
5408 struct target_ucontext uc;
5409 unsigned int retcode[3];
5410};
5411
5412#define INSN_MOV_R30_R16 0x47fe0410
5413#define INSN_LDI_R0 0x201f0000
5414#define INSN_CALLSYS 0x00000083
5415
Riku Voipio41ecc722014-04-23 11:01:00 +03005416static void setup_sigcontext(struct target_sigcontext *sc, CPUAlphaState *env,
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01005417 abi_ulong frame_addr, target_sigset_t *set)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005418{
Riku Voipio41ecc722014-04-23 11:01:00 +03005419 int i;
Richard Henderson6049f4f2009-12-27 18:30:03 -08005420
Riku Voipio1d8b5122014-04-23 10:26:05 +03005421 __put_user(on_sig_stack(frame_addr), &sc->sc_onstack);
5422 __put_user(set->sig[0], &sc->sc_mask);
5423 __put_user(env->pc, &sc->sc_pc);
5424 __put_user(8, &sc->sc_ps);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005425
5426 for (i = 0; i < 31; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03005427 __put_user(env->ir[i], &sc->sc_regs[i]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005428 }
Riku Voipio1d8b5122014-04-23 10:26:05 +03005429 __put_user(0, &sc->sc_regs[31]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005430
5431 for (i = 0; i < 31; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03005432 __put_user(env->fir[i], &sc->sc_fpregs[i]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005433 }
Riku Voipio1d8b5122014-04-23 10:26:05 +03005434 __put_user(0, &sc->sc_fpregs[31]);
5435 __put_user(cpu_alpha_load_fpcr(env), &sc->sc_fpcr);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005436
Riku Voipio1d8b5122014-04-23 10:26:05 +03005437 __put_user(0, &sc->sc_traparg_a0); /* FIXME */
5438 __put_user(0, &sc->sc_traparg_a1); /* FIXME */
5439 __put_user(0, &sc->sc_traparg_a2); /* FIXME */
Richard Henderson6049f4f2009-12-27 18:30:03 -08005440}
5441
Riku Voipio016d2e12014-04-23 11:19:48 +03005442static void restore_sigcontext(CPUAlphaState *env,
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01005443 struct target_sigcontext *sc)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005444{
5445 uint64_t fpcr;
Riku Voipio016d2e12014-04-23 11:19:48 +03005446 int i;
Richard Henderson6049f4f2009-12-27 18:30:03 -08005447
Riku Voipio1d8b5122014-04-23 10:26:05 +03005448 __get_user(env->pc, &sc->sc_pc);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005449
5450 for (i = 0; i < 31; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03005451 __get_user(env->ir[i], &sc->sc_regs[i]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005452 }
5453 for (i = 0; i < 31; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03005454 __get_user(env->fir[i], &sc->sc_fpregs[i]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005455 }
5456
Riku Voipio1d8b5122014-04-23 10:26:05 +03005457 __get_user(fpcr, &sc->sc_fpcr);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005458 cpu_alpha_store_fpcr(env, fpcr);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005459}
5460
5461static inline abi_ulong get_sigframe(struct target_sigaction *sa,
Andreas Färber05390242012-02-25 03:37:53 +01005462 CPUAlphaState *env,
5463 unsigned long framesize)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005464{
5465 abi_ulong sp = env->ir[IR_SP];
5466
5467 /* This is the X/Open sanctioned signal stack switching. */
5468 if ((sa->sa_flags & TARGET_SA_ONSTACK) != 0 && !sas_ss_flags(sp)) {
5469 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
5470 }
5471 return (sp - framesize) & -32;
5472}
5473
5474static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01005475 target_sigset_t *set, CPUAlphaState *env)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005476{
5477 abi_ulong frame_addr, r26;
5478 struct target_sigframe *frame;
5479 int err = 0;
5480
5481 frame_addr = get_sigframe(ka, env, sizeof(*frame));
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01005482 trace_user_setup_frame(env, frame_addr);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005483 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
5484 goto give_sigsegv;
5485 }
5486
Riku Voipio41ecc722014-04-23 11:01:00 +03005487 setup_sigcontext(&frame->sc, env, frame_addr, set);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005488
5489 if (ka->sa_restorer) {
5490 r26 = ka->sa_restorer;
5491 } else {
Riku Voipio1d8b5122014-04-23 10:26:05 +03005492 __put_user(INSN_MOV_R30_R16, &frame->retcode[0]);
5493 __put_user(INSN_LDI_R0 + TARGET_NR_sigreturn,
5494 &frame->retcode[1]);
5495 __put_user(INSN_CALLSYS, &frame->retcode[2]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005496 /* imb() */
5497 r26 = frame_addr;
5498 }
5499
5500 unlock_user_struct(frame, frame_addr, 1);
5501
5502 if (err) {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01005503give_sigsegv:
Richard Henderson6049f4f2009-12-27 18:30:03 -08005504 if (sig == TARGET_SIGSEGV) {
5505 ka->_sa_handler = TARGET_SIG_DFL;
5506 }
5507 force_sig(TARGET_SIGSEGV);
5508 }
5509
5510 env->ir[IR_RA] = r26;
5511 env->ir[IR_PV] = env->pc = ka->_sa_handler;
5512 env->ir[IR_A0] = sig;
5513 env->ir[IR_A1] = 0;
5514 env->ir[IR_A2] = frame_addr + offsetof(struct target_sigframe, sc);
5515 env->ir[IR_SP] = frame_addr;
5516}
5517
5518static void setup_rt_frame(int sig, struct target_sigaction *ka,
5519 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01005520 target_sigset_t *set, CPUAlphaState *env)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005521{
5522 abi_ulong frame_addr, r26;
5523 struct target_rt_sigframe *frame;
5524 int i, err = 0;
5525
5526 frame_addr = get_sigframe(ka, env, sizeof(*frame));
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01005527 trace_user_setup_rt_frame(env, frame_addr);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005528 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
5529 goto give_sigsegv;
5530 }
5531
Peter Maydellf6c7a052015-01-08 12:19:48 +00005532 tswap_siginfo(&frame->info, info);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005533
Riku Voipio1d8b5122014-04-23 10:26:05 +03005534 __put_user(0, &frame->uc.tuc_flags);
5535 __put_user(0, &frame->uc.tuc_link);
5536 __put_user(set->sig[0], &frame->uc.tuc_osf_sigmask);
5537 __put_user(target_sigaltstack_used.ss_sp,
5538 &frame->uc.tuc_stack.ss_sp);
5539 __put_user(sas_ss_flags(env->ir[IR_SP]),
5540 &frame->uc.tuc_stack.ss_flags);
5541 __put_user(target_sigaltstack_used.ss_size,
5542 &frame->uc.tuc_stack.ss_size);
Riku Voipio41ecc722014-04-23 11:01:00 +03005543 setup_sigcontext(&frame->uc.tuc_mcontext, env, frame_addr, set);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005544 for (i = 0; i < TARGET_NSIG_WORDS; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03005545 __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005546 }
5547
5548 if (ka->sa_restorer) {
5549 r26 = ka->sa_restorer;
5550 } else {
Riku Voipio1d8b5122014-04-23 10:26:05 +03005551 __put_user(INSN_MOV_R30_R16, &frame->retcode[0]);
5552 __put_user(INSN_LDI_R0 + TARGET_NR_rt_sigreturn,
5553 &frame->retcode[1]);
5554 __put_user(INSN_CALLSYS, &frame->retcode[2]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005555 /* imb(); */
5556 r26 = frame_addr;
5557 }
5558
5559 if (err) {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01005560give_sigsegv:
5561 if (sig == TARGET_SIGSEGV) {
Richard Henderson6049f4f2009-12-27 18:30:03 -08005562 ka->_sa_handler = TARGET_SIG_DFL;
5563 }
5564 force_sig(TARGET_SIGSEGV);
5565 }
5566
5567 env->ir[IR_RA] = r26;
5568 env->ir[IR_PV] = env->pc = ka->_sa_handler;
5569 env->ir[IR_A0] = sig;
5570 env->ir[IR_A1] = frame_addr + offsetof(struct target_rt_sigframe, info);
5571 env->ir[IR_A2] = frame_addr + offsetof(struct target_rt_sigframe, uc);
5572 env->ir[IR_SP] = frame_addr;
5573}
5574
Andreas Färber05390242012-02-25 03:37:53 +01005575long do_sigreturn(CPUAlphaState *env)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005576{
5577 struct target_sigcontext *sc;
5578 abi_ulong sc_addr = env->ir[IR_A0];
5579 target_sigset_t target_set;
5580 sigset_t set;
5581
5582 if (!lock_user_struct(VERIFY_READ, sc, sc_addr, 1)) {
5583 goto badframe;
5584 }
5585
5586 target_sigemptyset(&target_set);
Riku Voipiof5f601a2014-04-23 13:00:17 +03005587 __get_user(target_set.sig[0], &sc->sc_mask);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005588
5589 target_to_host_sigset_internal(&set, &target_set);
Peter Maydell9eede5b2016-05-27 15:51:46 +01005590 set_sigmask(&set);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005591
Riku Voipio016d2e12014-04-23 11:19:48 +03005592 restore_sigcontext(env, sc);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005593 unlock_user_struct(sc, sc_addr, 0);
Timothy E Baldwin338c8582016-05-12 18:47:36 +01005594 return -TARGET_QEMU_ESIGRETURN;
Richard Henderson6049f4f2009-12-27 18:30:03 -08005595
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01005596badframe:
Richard Henderson6049f4f2009-12-27 18:30:03 -08005597 force_sig(TARGET_SIGSEGV);
5598}
5599
Andreas Färber05390242012-02-25 03:37:53 +01005600long do_rt_sigreturn(CPUAlphaState *env)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005601{
5602 abi_ulong frame_addr = env->ir[IR_A0];
5603 struct target_rt_sigframe *frame;
5604 sigset_t set;
5605
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01005606 trace_user_do_rt_sigreturn(env, frame_addr);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005607 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
5608 goto badframe;
5609 }
Aurelien Jarno60e99242010-03-29 02:12:51 +02005610 target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
Peter Maydell9eede5b2016-05-27 15:51:46 +01005611 set_sigmask(&set);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005612
Riku Voipio016d2e12014-04-23 11:19:48 +03005613 restore_sigcontext(env, &frame->uc.tuc_mcontext);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005614 if (do_sigaltstack(frame_addr + offsetof(struct target_rt_sigframe,
Aurelien Jarno60e99242010-03-29 02:12:51 +02005615 uc.tuc_stack),
Richard Henderson6049f4f2009-12-27 18:30:03 -08005616 0, env->ir[IR_SP]) == -EFAULT) {
5617 goto badframe;
5618 }
5619
5620 unlock_user_struct(frame, frame_addr, 0);
Timothy E Baldwin338c8582016-05-12 18:47:36 +01005621 return -TARGET_QEMU_ESIGRETURN;
Richard Henderson6049f4f2009-12-27 18:30:03 -08005622
5623
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01005624badframe:
Richard Henderson6049f4f2009-12-27 18:30:03 -08005625 unlock_user_struct(frame, frame_addr, 0);
5626 force_sig(TARGET_SIGSEGV);
5627}
5628
Chen Gangbf0f60a2015-09-27 08:10:18 +08005629#elif defined(TARGET_TILEGX)
5630
5631struct target_sigcontext {
5632 union {
5633 /* General-purpose registers. */
5634 abi_ulong gregs[56];
5635 struct {
5636 abi_ulong __gregs[53];
5637 abi_ulong tp; /* Aliases gregs[TREG_TP]. */
5638 abi_ulong sp; /* Aliases gregs[TREG_SP]. */
5639 abi_ulong lr; /* Aliases gregs[TREG_LR]. */
5640 };
5641 };
5642 abi_ulong pc; /* Program counter. */
5643 abi_ulong ics; /* In Interrupt Critical Section? */
5644 abi_ulong faultnum; /* Fault number. */
5645 abi_ulong pad[5];
5646};
5647
5648struct target_ucontext {
5649 abi_ulong tuc_flags;
5650 abi_ulong tuc_link;
5651 target_stack_t tuc_stack;
5652 struct target_sigcontext tuc_mcontext;
5653 target_sigset_t tuc_sigmask; /* mask last for extensibility */
5654};
5655
5656struct target_rt_sigframe {
5657 unsigned char save_area[16]; /* caller save area */
5658 struct target_siginfo info;
5659 struct target_ucontext uc;
Chen Gangf1d9d102016-03-29 21:53:49 +08005660 abi_ulong retcode[2];
Chen Gangbf0f60a2015-09-27 08:10:18 +08005661};
5662
Chen Gangf1d9d102016-03-29 21:53:49 +08005663#define INSN_MOVELI_R10_139 0x00045fe551483000ULL /* { moveli r10, 139 } */
5664#define INSN_SWINT1 0x286b180051485000ULL /* { swint1 } */
5665
5666
Chen Gangbf0f60a2015-09-27 08:10:18 +08005667static void setup_sigcontext(struct target_sigcontext *sc,
5668 CPUArchState *env, int signo)
5669{
5670 int i;
5671
5672 for (i = 0; i < TILEGX_R_COUNT; ++i) {
5673 __put_user(env->regs[i], &sc->gregs[i]);
5674 }
5675
5676 __put_user(env->pc, &sc->pc);
5677 __put_user(0, &sc->ics);
5678 __put_user(signo, &sc->faultnum);
5679}
5680
5681static void restore_sigcontext(CPUTLGState *env, struct target_sigcontext *sc)
5682{
5683 int i;
5684
5685 for (i = 0; i < TILEGX_R_COUNT; ++i) {
5686 __get_user(env->regs[i], &sc->gregs[i]);
5687 }
5688
5689 __get_user(env->pc, &sc->pc);
5690}
5691
5692static abi_ulong get_sigframe(struct target_sigaction *ka, CPUArchState *env,
5693 size_t frame_size)
5694{
5695 unsigned long sp = env->regs[TILEGX_R_SP];
5696
5697 if (on_sig_stack(sp) && !likely(on_sig_stack(sp - frame_size))) {
5698 return -1UL;
5699 }
5700
5701 if ((ka->sa_flags & SA_ONSTACK) && !sas_ss_flags(sp)) {
5702 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
5703 }
5704
5705 sp -= frame_size;
5706 sp &= -16UL;
5707 return sp;
5708}
5709
5710static void setup_rt_frame(int sig, struct target_sigaction *ka,
5711 target_siginfo_t *info,
5712 target_sigset_t *set, CPUArchState *env)
5713{
5714 abi_ulong frame_addr;
5715 struct target_rt_sigframe *frame;
5716 unsigned long restorer;
5717
5718 frame_addr = get_sigframe(ka, env, sizeof(*frame));
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01005719 trace_user_setup_rt_frame(env, frame_addr);
Chen Gangbf0f60a2015-09-27 08:10:18 +08005720 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
5721 goto give_sigsegv;
5722 }
5723
5724 /* Always write at least the signal number for the stack backtracer. */
5725 if (ka->sa_flags & TARGET_SA_SIGINFO) {
5726 /* At sigreturn time, restore the callee-save registers too. */
5727 tswap_siginfo(&frame->info, info);
5728 /* regs->flags |= PT_FLAGS_RESTORE_REGS; FIXME: we can skip it? */
5729 } else {
5730 __put_user(info->si_signo, &frame->info.si_signo);
5731 }
5732
5733 /* Create the ucontext. */
5734 __put_user(0, &frame->uc.tuc_flags);
5735 __put_user(0, &frame->uc.tuc_link);
5736 __put_user(target_sigaltstack_used.ss_sp, &frame->uc.tuc_stack.ss_sp);
5737 __put_user(sas_ss_flags(env->regs[TILEGX_R_SP]),
5738 &frame->uc.tuc_stack.ss_flags);
5739 __put_user(target_sigaltstack_used.ss_size, &frame->uc.tuc_stack.ss_size);
5740 setup_sigcontext(&frame->uc.tuc_mcontext, env, info->si_signo);
5741
Chen Gangbf0f60a2015-09-27 08:10:18 +08005742 if (ka->sa_flags & TARGET_SA_RESTORER) {
Chen Gangf1d9d102016-03-29 21:53:49 +08005743 restorer = (unsigned long) ka->sa_restorer;
5744 } else {
5745 __put_user(INSN_MOVELI_R10_139, &frame->retcode[0]);
5746 __put_user(INSN_SWINT1, &frame->retcode[1]);
5747 restorer = frame_addr + offsetof(struct target_rt_sigframe, retcode);
Chen Gangbf0f60a2015-09-27 08:10:18 +08005748 }
5749 env->pc = (unsigned long) ka->_sa_handler;
5750 env->regs[TILEGX_R_SP] = (unsigned long) frame;
5751 env->regs[TILEGX_R_LR] = restorer;
5752 env->regs[0] = (unsigned long) sig;
5753 env->regs[1] = (unsigned long) &frame->info;
5754 env->regs[2] = (unsigned long) &frame->uc;
5755 /* regs->flags |= PT_FLAGS_CALLER_SAVES; FIXME: we can skip it? */
5756
5757 unlock_user_struct(frame, frame_addr, 1);
5758 return;
5759
5760give_sigsegv:
5761 if (sig == TARGET_SIGSEGV) {
5762 ka->_sa_handler = TARGET_SIG_DFL;
5763 }
5764 force_sig(TARGET_SIGSEGV /* , current */);
5765}
5766
5767long do_rt_sigreturn(CPUTLGState *env)
5768{
5769 abi_ulong frame_addr = env->regs[TILEGX_R_SP];
5770 struct target_rt_sigframe *frame;
5771 sigset_t set;
5772
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01005773 trace_user_do_rt_sigreturn(env, frame_addr);
Chen Gangbf0f60a2015-09-27 08:10:18 +08005774 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
5775 goto badframe;
5776 }
5777 target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
Peter Maydell9eede5b2016-05-27 15:51:46 +01005778 set_sigmask(&set);
Chen Gangbf0f60a2015-09-27 08:10:18 +08005779
5780 restore_sigcontext(env, &frame->uc.tuc_mcontext);
5781 if (do_sigaltstack(frame_addr + offsetof(struct target_rt_sigframe,
5782 uc.tuc_stack),
5783 0, env->regs[TILEGX_R_SP]) == -EFAULT) {
5784 goto badframe;
5785 }
5786
5787 unlock_user_struct(frame, frame_addr, 0);
Peter Maydella9175162016-05-12 18:47:42 +01005788 return -TARGET_QEMU_ESIGRETURN;
Chen Gangbf0f60a2015-09-27 08:10:18 +08005789
5790
5791 badframe:
5792 unlock_user_struct(frame, frame_addr, 0);
5793 force_sig(TARGET_SIGSEGV);
5794}
5795
bellardb346ff42003-06-15 20:05:50 +00005796#else
5797
pbrook624f7972008-05-31 16:11:38 +00005798static void setup_frame(int sig, struct target_sigaction *ka,
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01005799 target_sigset_t *set, CPUArchState *env)
bellardb346ff42003-06-15 20:05:50 +00005800{
5801 fprintf(stderr, "setup_frame: not implemented\n");
5802}
5803
pbrook624f7972008-05-31 16:11:38 +00005804static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05005805 target_siginfo_t *info,
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01005806 target_sigset_t *set, CPUArchState *env)
bellardb346ff42003-06-15 20:05:50 +00005807{
5808 fprintf(stderr, "setup_rt_frame: not implemented\n");
5809}
5810
Andreas Färber9349b4f2012-03-14 01:38:32 +01005811long do_sigreturn(CPUArchState *env)
bellardb346ff42003-06-15 20:05:50 +00005812{
5813 fprintf(stderr, "do_sigreturn: not implemented\n");
bellardf8b0aa22007-11-11 23:03:42 +00005814 return -TARGET_ENOSYS;
bellardb346ff42003-06-15 20:05:50 +00005815}
5816
Andreas Färber9349b4f2012-03-14 01:38:32 +01005817long do_rt_sigreturn(CPUArchState *env)
bellardb346ff42003-06-15 20:05:50 +00005818{
5819 fprintf(stderr, "do_rt_sigreturn: not implemented\n");
bellardf8b0aa22007-11-11 23:03:42 +00005820 return -TARGET_ENOSYS;
bellardb346ff42003-06-15 20:05:50 +00005821}
5822
bellard66fb9762003-03-23 01:06:05 +00005823#endif
5824
Peter Maydell31efaef2016-07-06 15:09:29 +01005825static void handle_pending_signal(CPUArchState *cpu_env, int sig,
5826 struct emulated_sigtable *k)
Peter Maydelleb552502016-05-27 15:51:43 +01005827{
5828 CPUState *cpu = ENV_GET_CPU(cpu_env);
5829 abi_ulong handler;
Peter Maydell3d3efba2016-05-27 15:51:49 +01005830 sigset_t set;
Peter Maydelleb552502016-05-27 15:51:43 +01005831 target_sigset_t target_old_set;
5832 struct target_sigaction *sa;
Peter Maydelleb552502016-05-27 15:51:43 +01005833 TaskState *ts = cpu->opaque;
Peter Maydelleb552502016-05-27 15:51:43 +01005834
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01005835 trace_user_handle_signal(cpu_env, sig);
bellard66fb9762003-03-23 01:06:05 +00005836 /* dequeue signal */
Timothy E Baldwin907f5fd2016-05-27 15:51:52 +01005837 k->pending = 0;
ths3b46e622007-09-17 08:09:54 +00005838
Andreas Färberdb6b81d2013-06-27 19:49:31 +02005839 sig = gdb_handlesig(cpu, sig);
bellard1fddef42005-04-17 19:16:13 +00005840 if (!sig) {
aurel32ca587a82008-12-18 22:44:13 +00005841 sa = NULL;
5842 handler = TARGET_SIG_IGN;
5843 } else {
5844 sa = &sigact_table[sig - 1];
5845 handler = sa->_sa_handler;
bellard1fddef42005-04-17 19:16:13 +00005846 }
bellard66fb9762003-03-23 01:06:05 +00005847
Peter Maydell0cb581d2016-07-18 18:12:24 +01005848 if (do_strace) {
5849 print_taken_signal(sig, &k->info);
5850 }
5851
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
Peter Maydell8bd37732016-07-28 16:44:45 +01005924 restart_scan:
Timothy E Baldwin655ed672016-05-27 15:51:53 +01005925 sig = ts->sync_signal.pending;
5926 if (sig) {
5927 /* Synchronous signals are forced,
5928 * see force_sig_info() and callers in Linux
5929 * Note that not all of our queue_signal() calls in QEMU correspond
5930 * to force_sig_info() calls in Linux (some are send_sig_info()).
5931 * However it seems like a kernel bug to me to allow the process
5932 * to block a synchronous signal since it could then just end up
5933 * looping round and round indefinitely.
5934 */
5935 if (sigismember(&ts->signal_mask, target_to_host_signal_table[sig])
5936 || sigact_table[sig - 1]._sa_handler == TARGET_SIG_IGN) {
5937 sigdelset(&ts->signal_mask, target_to_host_signal_table[sig]);
5938 sigact_table[sig - 1]._sa_handler = TARGET_SIG_DFL;
5939 }
5940
Peter Maydell31efaef2016-07-06 15:09:29 +01005941 handle_pending_signal(cpu_env, sig, &ts->sync_signal);
Timothy E Baldwin655ed672016-05-27 15:51:53 +01005942 }
5943
Peter Maydell3d3efba2016-05-27 15:51:49 +01005944 for (sig = 1; sig <= TARGET_NSIG; sig++) {
5945 blocked_set = ts->in_sigsuspend ?
5946 &ts->sigsuspend_mask : &ts->signal_mask;
5947
5948 if (ts->sigtab[sig - 1].pending &&
5949 (!sigismember(blocked_set,
Timothy E Baldwin655ed672016-05-27 15:51:53 +01005950 target_to_host_signal_table[sig]))) {
Peter Maydell31efaef2016-07-06 15:09:29 +01005951 handle_pending_signal(cpu_env, sig, &ts->sigtab[sig - 1]);
Peter Maydell8bd37732016-07-28 16:44:45 +01005952 /* Restart scan from the beginning, as handle_pending_signal
5953 * might have resulted in a new synchronous signal (eg SIGSEGV).
5954 */
5955 goto restart_scan;
Peter Maydell3d3efba2016-05-27 15:51:49 +01005956 }
Peter Maydelle902d582016-05-27 15:51:44 +01005957 }
Peter Maydell3d3efba2016-05-27 15:51:49 +01005958
5959 /* if no signal is pending, unblock signals and recheck (the act
5960 * of unblocking might cause us to take another host signal which
5961 * will set signal_pending again).
5962 */
5963 atomic_set(&ts->signal_pending, 0);
5964 ts->in_sigsuspend = 0;
5965 set = ts->signal_mask;
5966 sigdelset(&set, SIGSEGV);
5967 sigdelset(&set, SIGBUS);
5968 sigprocmask(SIG_SETMASK, &set, 0);
Peter Maydelle902d582016-05-27 15:51:44 +01005969 }
Peter Maydell3d3efba2016-05-27 15:51:49 +01005970 ts->in_sigsuspend = 0;
Peter Maydelle902d582016-05-27 15:51:44 +01005971}