blob: 43836960c15e31e764df8303568d10d615edd6c7 [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
Peter Maydell28298c92016-07-28 16:44:48 +0100515#if !(defined(TARGET_X86_64) || defined(TARGET_UNICORE32))
Peter Maydell09391662016-07-28 16:44:47 +0100516
517/* Force a SIGSEGV if we couldn't write to memory trying to set
518 * up the signal frame. oldsig is the signal we were trying to handle
519 * at the point of failure.
520 */
521static void force_sigsegv(int oldsig)
522{
523 CPUState *cpu = thread_cpu;
524 CPUArchState *env = cpu->env_ptr;
525 target_siginfo_t info;
526
527 if (oldsig == SIGSEGV) {
528 /* Make sure we don't try to deliver the signal again; this will
529 * end up with handle_pending_signal() calling force_sig().
530 */
531 sigact_table[oldsig - 1]._sa_handler = TARGET_SIG_DFL;
532 }
533 info.si_signo = TARGET_SIGSEGV;
534 info.si_errno = 0;
535 info.si_code = TARGET_SI_KERNEL;
536 info._sifields._kill._pid = 0;
537 info._sifields._kill._uid = 0;
538 queue_signal(env, info.si_signo, QEMU_SI_KILL, &info);
539}
540#endif
bellard66fb9762003-03-23 01:06:05 +0000541
bellard9de5e442003-03-23 16:49:39 +0000542/* abort execution with signal */
Riku Voipio66393fb2009-12-04 15:16:32 +0200543static void QEMU_NORETURN force_sig(int target_sig)
bellard66fb9762003-03-23 01:06:05 +0000544{
Andreas Färber0429a972013-08-26 18:14:44 +0200545 CPUState *cpu = thread_cpu;
546 CPUArchState *env = cpu->env_ptr;
547 TaskState *ts = (TaskState *)cpu->opaque;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +0300548 int host_sig, core_dumped = 0;
aurel32603e4fd2009-04-15 16:18:38 +0000549 struct sigaction act;
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +0100550
Riku Voipio66393fb2009-12-04 15:16:32 +0200551 host_sig = target_to_host_signal(target_sig);
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +0100552 trace_user_force_sig(env, target_sig, host_sig);
Andreas Färbera2247f82013-06-09 19:47:04 +0200553 gdb_signalled(env, target_sig);
aurel32603e4fd2009-04-15 16:18:38 +0000554
Mika Westerbergedf8e2a2009-04-07 09:57:11 +0300555 /* dump core if supported by target binary format */
Riku Voipio66393fb2009-12-04 15:16:32 +0200556 if (core_dump_signal(target_sig) && (ts->bprm->core_dump != NULL)) {
Mika Westerbergedf8e2a2009-04-07 09:57:11 +0300557 stop_all_tasks();
558 core_dumped =
Andreas Färbera2247f82013-06-09 19:47:04 +0200559 ((*ts->bprm->core_dump)(target_sig, env) == 0);
Mika Westerbergedf8e2a2009-04-07 09:57:11 +0300560 }
561 if (core_dumped) {
562 /* we already dumped the core of target process, we don't want
563 * a coredump of qemu itself */
564 struct rlimit nodump;
565 getrlimit(RLIMIT_CORE, &nodump);
566 nodump.rlim_cur=0;
567 setrlimit(RLIMIT_CORE, &nodump);
568 (void) fprintf(stderr, "qemu: uncaught target signal %d (%s) - %s\n",
Riku Voipio66393fb2009-12-04 15:16:32 +0200569 target_sig, strsignal(host_sig), "core dumped" );
Mika Westerbergedf8e2a2009-04-07 09:57:11 +0300570 }
571
Stefan Weil0c587512011-04-28 17:20:32 +0200572 /* The proper exit code for dying from an uncaught signal is
aurel32603e4fd2009-04-15 16:18:38 +0000573 * -<signal>. The kernel doesn't allow exit() or _exit() to pass
574 * a negative value. To get the proper exit code we need to
575 * actually die from an uncaught signal. Here the default signal
576 * handler is installed, we send ourself a signal and we wait for
577 * it to arrive. */
578 sigfillset(&act.sa_mask);
579 act.sa_handler = SIG_DFL;
Peter Maydell3a5d30b2014-02-17 18:55:32 +0000580 act.sa_flags = 0;
aurel32603e4fd2009-04-15 16:18:38 +0000581 sigaction(host_sig, &act, NULL);
582
583 /* For some reason raise(host_sig) doesn't send the signal when
584 * statically linked on x86-64. */
585 kill(getpid(), host_sig);
586
587 /* Make sure the signal isn't masked (just reuse the mask inside
588 of act) */
589 sigdelset(&act.sa_mask, host_sig);
590 sigsuspend(&act.sa_mask);
591
592 /* unreachable */
Blue Swirla6c6f762010-03-13 14:18:50 +0000593 abort();
bellard66fb9762003-03-23 01:06:05 +0000594}
595
bellard9de5e442003-03-23 16:49:39 +0000596/* queue a signal so that it will be send to the virtual CPU as soon
597 as possible */
Peter Maydell9d2803f2016-07-28 16:44:46 +0100598int queue_signal(CPUArchState *env, int sig, int si_type,
599 target_siginfo_t *info)
bellard31e31b82003-02-18 22:55:36 +0000600{
Andreas Färber0429a972013-08-26 18:14:44 +0200601 CPUState *cpu = ENV_GET_CPU(env);
602 TaskState *ts = cpu->opaque;
bellard66fb9762003-03-23 01:06:05 +0000603
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +0100604 trace_user_queue_signal(env, sig);
Peter Maydella7ec0f92014-03-14 14:36:56 +0000605
Peter Maydell9d2803f2016-07-28 16:44:46 +0100606 info->si_code = deposit32(info->si_code, 16, 16, si_type);
Peter Maydella70dadc2016-05-27 15:51:59 +0100607
Timothy E Baldwin655ed672016-05-27 15:51:53 +0100608 ts->sync_signal.info = *info;
609 ts->sync_signal.pending = sig;
Timothy E Baldwin907f5fd2016-05-27 15:51:52 +0100610 /* signal that a new signal is pending */
611 atomic_set(&ts->signal_pending, 1);
612 return 1; /* indicates that the signal was queued */
bellard9de5e442003-03-23 16:49:39 +0000613}
614
Timothy E Baldwin4d330ce2016-05-12 18:47:46 +0100615#ifndef HAVE_SAFE_SYSCALL
616static inline void rewind_if_in_safe_syscall(void *puc)
617{
618 /* Default version: never rewind */
619}
620#endif
621
ths5fafdf22007-09-16 21:08:06 +0000622static void host_signal_handler(int host_signum, siginfo_t *info,
bellard9de5e442003-03-23 16:49:39 +0000623 void *puc)
624{
Andreas Färbera2247f82013-06-09 19:47:04 +0200625 CPUArchState *env = thread_cpu->env_ptr;
Timothy E Baldwin655ed672016-05-27 15:51:53 +0100626 CPUState *cpu = ENV_GET_CPU(env);
627 TaskState *ts = cpu->opaque;
628
bellard9de5e442003-03-23 16:49:39 +0000629 int sig;
Anthony Liguoric227f092009-10-01 16:12:16 -0500630 target_siginfo_t tinfo;
Peter Maydell3d3efba2016-05-27 15:51:49 +0100631 ucontext_t *uc = puc;
Timothy E Baldwin655ed672016-05-27 15:51:53 +0100632 struct emulated_sigtable *k;
bellard9de5e442003-03-23 16:49:39 +0000633
634 /* the CPU emulator uses some host signals to detect exceptions,
aurel32eaa449b2009-01-03 13:14:52 +0000635 we forward to it some signals */
aurel32ca587a82008-12-18 22:44:13 +0000636 if ((host_signum == SIGSEGV || host_signum == SIGBUS)
aurel32eaa449b2009-01-03 13:14:52 +0000637 && info->si_code > 0) {
bellardb346ff42003-06-15 20:05:50 +0000638 if (cpu_signal_handler(host_signum, info, puc))
bellard9de5e442003-03-23 16:49:39 +0000639 return;
640 }
641
642 /* get target signal number */
643 sig = host_to_target_signal(host_signum);
644 if (sig < 1 || sig > TARGET_NSIG)
645 return;
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +0100646 trace_user_host_signal(env, host_signum, sig);
Timothy E Baldwin4d330ce2016-05-12 18:47:46 +0100647
648 rewind_if_in_safe_syscall(puc);
649
bellard9de5e442003-03-23 16:49:39 +0000650 host_to_target_siginfo_noswap(&tinfo, info);
Timothy E Baldwin655ed672016-05-27 15:51:53 +0100651 k = &ts->sigtab[sig - 1];
652 k->info = tinfo;
653 k->pending = sig;
654 ts->signal_pending = 1;
Peter Maydell3d3efba2016-05-27 15:51:49 +0100655
Timothy E Baldwin655ed672016-05-27 15:51:53 +0100656 /* Block host signals until target signal handler entered. We
657 * can't block SIGSEGV or SIGBUS while we're executing guest
658 * code in case the guest code provokes one in the window between
659 * now and it getting out to the main loop. Signals will be
660 * unblocked again in process_pending_signals().
Peter Maydell1d48fdd2016-06-14 12:49:18 +0100661 *
662 * WARNING: we cannot use sigfillset() here because the uc_sigmask
663 * field is a kernel sigset_t, which is much smaller than the
664 * libc sigset_t which sigfillset() operates on. Using sigfillset()
665 * would write 0xff bytes off the end of the structure and trash
666 * data on the struct.
667 * We can't use sizeof(uc->uc_sigmask) either, because the libc
668 * headers define the struct field with the wrong (too large) type.
Timothy E Baldwin655ed672016-05-27 15:51:53 +0100669 */
Peter Maydell1d48fdd2016-06-14 12:49:18 +0100670 memset(&uc->uc_sigmask, 0xff, SIGSET_T_SIZE);
Timothy E Baldwin655ed672016-05-27 15:51:53 +0100671 sigdelset(&uc->uc_sigmask, SIGSEGV);
672 sigdelset(&uc->uc_sigmask, SIGBUS);
673
674 /* interrupt the virtual CPU as soon as possible */
675 cpu_exit(thread_cpu);
bellard31e31b82003-02-18 22:55:36 +0000676}
677
ths0da46a62007-10-20 20:23:07 +0000678/* do_sigaltstack() returns target values and errnos. */
bellard579a97f2007-11-11 14:26:47 +0000679/* compare linux/kernel/signal.c:do_sigaltstack() */
680abi_long do_sigaltstack(abi_ulong uss_addr, abi_ulong uoss_addr, abi_ulong sp)
thsa04e1342007-09-27 13:57:58 +0000681{
682 int ret;
683 struct target_sigaltstack oss;
684
685 /* XXX: test errors */
bellard579a97f2007-11-11 14:26:47 +0000686 if(uoss_addr)
thsa04e1342007-09-27 13:57:58 +0000687 {
688 __put_user(target_sigaltstack_used.ss_sp, &oss.ss_sp);
689 __put_user(target_sigaltstack_used.ss_size, &oss.ss_size);
690 __put_user(sas_ss_flags(sp), &oss.ss_flags);
691 }
692
bellard579a97f2007-11-11 14:26:47 +0000693 if(uss_addr)
thsa04e1342007-09-27 13:57:58 +0000694 {
bellard579a97f2007-11-11 14:26:47 +0000695 struct target_sigaltstack *uss;
696 struct target_sigaltstack ss;
Tom Musta0903c8b2014-08-12 13:53:40 -0500697 size_t minstacksize = TARGET_MINSIGSTKSZ;
698
699#if defined(TARGET_PPC64)
700 /* ELF V2 for PPC64 has a 4K minimum stack size for signal handlers */
701 struct image_info *image = ((TaskState *)thread_cpu->opaque)->info;
702 if (get_ppc64_abi(image) > 1) {
703 minstacksize = 4096;
704 }
705#endif
thsa04e1342007-09-27 13:57:58 +0000706
ths0da46a62007-10-20 20:23:07 +0000707 ret = -TARGET_EFAULT;
Riku Voipio9eeb8302014-04-23 11:26:34 +0300708 if (!lock_user_struct(VERIFY_READ, uss, uss_addr, 1)) {
thsa04e1342007-09-27 13:57:58 +0000709 goto out;
Riku Voipio9eeb8302014-04-23 11:26:34 +0300710 }
711 __get_user(ss.ss_sp, &uss->ss_sp);
712 __get_user(ss.ss_size, &uss->ss_size);
713 __get_user(ss.ss_flags, &uss->ss_flags);
bellard579a97f2007-11-11 14:26:47 +0000714 unlock_user_struct(uss, uss_addr, 0);
thsa04e1342007-09-27 13:57:58 +0000715
ths0da46a62007-10-20 20:23:07 +0000716 ret = -TARGET_EPERM;
thsa04e1342007-09-27 13:57:58 +0000717 if (on_sig_stack(sp))
718 goto out;
719
ths0da46a62007-10-20 20:23:07 +0000720 ret = -TARGET_EINVAL;
thsa04e1342007-09-27 13:57:58 +0000721 if (ss.ss_flags != TARGET_SS_DISABLE
722 && ss.ss_flags != TARGET_SS_ONSTACK
723 && ss.ss_flags != 0)
724 goto out;
725
726 if (ss.ss_flags == TARGET_SS_DISABLE) {
727 ss.ss_size = 0;
728 ss.ss_sp = 0;
729 } else {
ths0da46a62007-10-20 20:23:07 +0000730 ret = -TARGET_ENOMEM;
Tom Musta0903c8b2014-08-12 13:53:40 -0500731 if (ss.ss_size < minstacksize) {
thsa04e1342007-09-27 13:57:58 +0000732 goto out;
Tom Musta0903c8b2014-08-12 13:53:40 -0500733 }
thsa04e1342007-09-27 13:57:58 +0000734 }
735
736 target_sigaltstack_used.ss_sp = ss.ss_sp;
737 target_sigaltstack_used.ss_size = ss.ss_size;
738 }
739
bellard579a97f2007-11-11 14:26:47 +0000740 if (uoss_addr) {
ths0da46a62007-10-20 20:23:07 +0000741 ret = -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +0000742 if (copy_to_user(uoss_addr, &oss, sizeof(oss)))
thsa04e1342007-09-27 13:57:58 +0000743 goto out;
thsa04e1342007-09-27 13:57:58 +0000744 }
745
746 ret = 0;
747out:
748 return ret;
749}
750
Timothy E Baldwinef6a7782016-05-27 15:51:54 +0100751/* do_sigaction() return target values and host errnos */
bellard66fb9762003-03-23 01:06:05 +0000752int do_sigaction(int sig, const struct target_sigaction *act,
753 struct target_sigaction *oact)
bellard31e31b82003-02-18 22:55:36 +0000754{
pbrook624f7972008-05-31 16:11:38 +0000755 struct target_sigaction *k;
bellard773b93e2004-01-04 17:15:59 +0000756 struct sigaction act1;
757 int host_sig;
ths0da46a62007-10-20 20:23:07 +0000758 int ret = 0;
bellard31e31b82003-02-18 22:55:36 +0000759
Timothy E Baldwinef6a7782016-05-27 15:51:54 +0100760 if (sig < 1 || sig > TARGET_NSIG || sig == TARGET_SIGKILL || sig == TARGET_SIGSTOP) {
761 return -TARGET_EINVAL;
762 }
763
764 if (block_signals()) {
765 return -TARGET_ERESTARTSYS;
766 }
767
bellard66fb9762003-03-23 01:06:05 +0000768 k = &sigact_table[sig - 1];
bellard66fb9762003-03-23 01:06:05 +0000769 if (oact) {
Richard Hendersond2565872013-01-04 16:39:32 -0800770 __put_user(k->_sa_handler, &oact->_sa_handler);
771 __put_user(k->sa_flags, &oact->sa_flags);
ths388bb212007-05-13 13:58:00 +0000772#if !defined(TARGET_MIPS)
Richard Hendersond2565872013-01-04 16:39:32 -0800773 __put_user(k->sa_restorer, &oact->sa_restorer);
ths388bb212007-05-13 13:58:00 +0000774#endif
Richard Hendersond2565872013-01-04 16:39:32 -0800775 /* Not swapped. */
pbrook624f7972008-05-31 16:11:38 +0000776 oact->sa_mask = k->sa_mask;
bellard66fb9762003-03-23 01:06:05 +0000777 }
778 if (act) {
pbrook624f7972008-05-31 16:11:38 +0000779 /* FIXME: This is not threadsafe. */
Richard Hendersond2565872013-01-04 16:39:32 -0800780 __get_user(k->_sa_handler, &act->_sa_handler);
781 __get_user(k->sa_flags, &act->sa_flags);
ths388bb212007-05-13 13:58:00 +0000782#if !defined(TARGET_MIPS)
Richard Hendersond2565872013-01-04 16:39:32 -0800783 __get_user(k->sa_restorer, &act->sa_restorer);
ths388bb212007-05-13 13:58:00 +0000784#endif
Richard Hendersond2565872013-01-04 16:39:32 -0800785 /* To be swapped in target_to_host_sigset. */
pbrook624f7972008-05-31 16:11:38 +0000786 k->sa_mask = act->sa_mask;
bellard773b93e2004-01-04 17:15:59 +0000787
788 /* we update the host linux signal state */
789 host_sig = target_to_host_signal(sig);
790 if (host_sig != SIGSEGV && host_sig != SIGBUS) {
791 sigfillset(&act1.sa_mask);
792 act1.sa_flags = SA_SIGINFO;
pbrook624f7972008-05-31 16:11:38 +0000793 if (k->sa_flags & TARGET_SA_RESTART)
bellard773b93e2004-01-04 17:15:59 +0000794 act1.sa_flags |= SA_RESTART;
795 /* NOTE: it is important to update the host kernel signal
796 ignore state to avoid getting unexpected interrupted
797 syscalls */
pbrook624f7972008-05-31 16:11:38 +0000798 if (k->_sa_handler == TARGET_SIG_IGN) {
bellard773b93e2004-01-04 17:15:59 +0000799 act1.sa_sigaction = (void *)SIG_IGN;
pbrook624f7972008-05-31 16:11:38 +0000800 } else if (k->_sa_handler == TARGET_SIG_DFL) {
aurel32ca587a82008-12-18 22:44:13 +0000801 if (fatal_signal (sig))
802 act1.sa_sigaction = host_signal_handler;
803 else
804 act1.sa_sigaction = (void *)SIG_DFL;
bellard773b93e2004-01-04 17:15:59 +0000805 } else {
806 act1.sa_sigaction = host_signal_handler;
807 }
ths0da46a62007-10-20 20:23:07 +0000808 ret = sigaction(host_sig, &act1, NULL);
bellard773b93e2004-01-04 17:15:59 +0000809 }
bellard66fb9762003-03-23 01:06:05 +0000810 }
ths0da46a62007-10-20 20:23:07 +0000811 return ret;
bellard66fb9762003-03-23 01:06:05 +0000812}
bellard31e31b82003-02-18 22:55:36 +0000813
bellard459a4012007-11-11 19:45:10 +0000814#if defined(TARGET_I386) && TARGET_ABI_BITS == 32
bellard66fb9762003-03-23 01:06:05 +0000815
816/* from the Linux kernel */
817
818struct target_fpreg {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100819 uint16_t significand[4];
820 uint16_t exponent;
bellard66fb9762003-03-23 01:06:05 +0000821};
822
823struct target_fpxreg {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100824 uint16_t significand[4];
825 uint16_t exponent;
826 uint16_t padding[3];
bellard66fb9762003-03-23 01:06:05 +0000827};
828
829struct target_xmmreg {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100830 abi_ulong element[4];
bellard66fb9762003-03-23 01:06:05 +0000831};
832
833struct target_fpstate {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100834 /* Regular FPU environment */
835 abi_ulong cw;
836 abi_ulong sw;
837 abi_ulong tag;
838 abi_ulong ipoff;
839 abi_ulong cssel;
840 abi_ulong dataoff;
841 abi_ulong datasel;
842 struct target_fpreg _st[8];
843 uint16_t status;
844 uint16_t magic; /* 0xffff = regular FPU data only */
bellard66fb9762003-03-23 01:06:05 +0000845
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100846 /* FXSR FPU environment */
847 abi_ulong _fxsr_env[6]; /* FXSR FPU env is ignored */
848 abi_ulong mxcsr;
849 abi_ulong reserved;
850 struct target_fpxreg _fxsr_st[8]; /* FXSR FPU reg data is ignored */
851 struct target_xmmreg _xmm[8];
852 abi_ulong padding[56];
bellard66fb9762003-03-23 01:06:05 +0000853};
854
855#define X86_FXSR_MAGIC 0x0000
856
857struct target_sigcontext {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100858 uint16_t gs, __gsh;
859 uint16_t fs, __fsh;
860 uint16_t es, __esh;
861 uint16_t ds, __dsh;
862 abi_ulong edi;
863 abi_ulong esi;
864 abi_ulong ebp;
865 abi_ulong esp;
866 abi_ulong ebx;
867 abi_ulong edx;
868 abi_ulong ecx;
869 abi_ulong eax;
870 abi_ulong trapno;
871 abi_ulong err;
872 abi_ulong eip;
873 uint16_t cs, __csh;
874 abi_ulong eflags;
875 abi_ulong esp_at_signal;
876 uint16_t ss, __ssh;
877 abi_ulong fpstate; /* pointer */
878 abi_ulong oldmask;
879 abi_ulong cr2;
bellard66fb9762003-03-23 01:06:05 +0000880};
881
bellard66fb9762003-03-23 01:06:05 +0000882struct target_ucontext {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100883 abi_ulong tuc_flags;
884 abi_ulong tuc_link;
885 target_stack_t tuc_stack;
886 struct target_sigcontext tuc_mcontext;
887 target_sigset_t tuc_sigmask; /* mask last for extensibility */
bellard66fb9762003-03-23 01:06:05 +0000888};
889
890struct sigframe
891{
blueswir1992f48a2007-10-14 16:27:31 +0000892 abi_ulong pretcode;
bellard66fb9762003-03-23 01:06:05 +0000893 int sig;
894 struct target_sigcontext sc;
895 struct target_fpstate fpstate;
blueswir1992f48a2007-10-14 16:27:31 +0000896 abi_ulong extramask[TARGET_NSIG_WORDS-1];
bellard66fb9762003-03-23 01:06:05 +0000897 char retcode[8];
898};
899
900struct rt_sigframe
901{
blueswir1992f48a2007-10-14 16:27:31 +0000902 abi_ulong pretcode;
bellard66fb9762003-03-23 01:06:05 +0000903 int sig;
blueswir1992f48a2007-10-14 16:27:31 +0000904 abi_ulong pinfo;
905 abi_ulong puc;
bellard66fb9762003-03-23 01:06:05 +0000906 struct target_siginfo info;
907 struct target_ucontext uc;
908 struct target_fpstate fpstate;
909 char retcode[8];
910};
911
912/*
913 * Set up a signal frame.
914 */
915
bellard66fb9762003-03-23 01:06:05 +0000916/* XXX: save x87 state */
Riku Voipio41ecc722014-04-23 11:01:00 +0300917static void setup_sigcontext(struct target_sigcontext *sc,
918 struct target_fpstate *fpstate, CPUX86State *env, abi_ulong mask,
919 abi_ulong fpstate_addr)
bellard66fb9762003-03-23 01:06:05 +0000920{
Andreas Färber27103422013-08-26 08:31:06 +0200921 CPUState *cs = CPU(x86_env_get_cpu(env));
Andreas Färber27103422013-08-26 08:31:06 +0200922 uint16_t magic;
bellard66fb9762003-03-23 01:06:05 +0000923
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100924 /* already locked in setup_frame() */
Riku Voipio1d8b5122014-04-23 10:26:05 +0300925 __put_user(env->segs[R_GS].selector, (unsigned int *)&sc->gs);
926 __put_user(env->segs[R_FS].selector, (unsigned int *)&sc->fs);
927 __put_user(env->segs[R_ES].selector, (unsigned int *)&sc->es);
928 __put_user(env->segs[R_DS].selector, (unsigned int *)&sc->ds);
929 __put_user(env->regs[R_EDI], &sc->edi);
930 __put_user(env->regs[R_ESI], &sc->esi);
931 __put_user(env->regs[R_EBP], &sc->ebp);
932 __put_user(env->regs[R_ESP], &sc->esp);
933 __put_user(env->regs[R_EBX], &sc->ebx);
934 __put_user(env->regs[R_EDX], &sc->edx);
935 __put_user(env->regs[R_ECX], &sc->ecx);
936 __put_user(env->regs[R_EAX], &sc->eax);
937 __put_user(cs->exception_index, &sc->trapno);
938 __put_user(env->error_code, &sc->err);
939 __put_user(env->eip, &sc->eip);
940 __put_user(env->segs[R_CS].selector, (unsigned int *)&sc->cs);
941 __put_user(env->eflags, &sc->eflags);
942 __put_user(env->regs[R_ESP], &sc->esp_at_signal);
943 __put_user(env->segs[R_SS].selector, (unsigned int *)&sc->ss);
bellarded2dcdf2003-05-29 20:06:27 +0000944
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100945 cpu_x86_fsave(env, fpstate_addr, 1);
946 fpstate->status = fpstate->sw;
947 magic = 0xffff;
Riku Voipio1d8b5122014-04-23 10:26:05 +0300948 __put_user(magic, &fpstate->magic);
949 __put_user(fpstate_addr, &sc->fpstate);
bellarded2dcdf2003-05-29 20:06:27 +0000950
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100951 /* non-iBCS2 extensions.. */
Riku Voipio1d8b5122014-04-23 10:26:05 +0300952 __put_user(mask, &sc->oldmask);
953 __put_user(env->cr[2], &sc->cr2);
bellard66fb9762003-03-23 01:06:05 +0000954}
955
956/*
957 * Determine which stack to use..
958 */
959
bellard579a97f2007-11-11 14:26:47 +0000960static inline abi_ulong
pbrook624f7972008-05-31 16:11:38 +0000961get_sigframe(struct target_sigaction *ka, CPUX86State *env, size_t frame_size)
bellard66fb9762003-03-23 01:06:05 +0000962{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100963 unsigned long esp;
bellard66fb9762003-03-23 01:06:05 +0000964
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100965 /* Default to using normal stack */
966 esp = env->regs[R_ESP];
967 /* This is the X/Open sanctioned signal stack switching. */
968 if (ka->sa_flags & TARGET_SA_ONSTACK) {
969 if (sas_ss_flags(esp) == 0) {
970 esp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
thsa04e1342007-09-27 13:57:58 +0000971 }
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100972 } else {
bellard66fb9762003-03-23 01:06:05 +0000973
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100974 /* This is the legacy signal stack switching. */
bellarda52c7572003-06-21 13:14:12 +0000975 if ((env->segs[R_SS].selector & 0xffff) != __USER_DS &&
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100976 !(ka->sa_flags & TARGET_SA_RESTORER) &&
977 ka->sa_restorer) {
pbrook624f7972008-05-31 16:11:38 +0000978 esp = (unsigned long) ka->sa_restorer;
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100979 }
980 }
981 return (esp - frame_size) & -8ul;
bellard66fb9762003-03-23 01:06:05 +0000982}
983
bellard579a97f2007-11-11 14:26:47 +0000984/* compare linux/arch/i386/kernel/signal.c:setup_frame() */
pbrook624f7972008-05-31 16:11:38 +0000985static void setup_frame(int sig, struct target_sigaction *ka,
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100986 target_sigset_t *set, CPUX86State *env)
bellard66fb9762003-03-23 01:06:05 +0000987{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100988 abi_ulong frame_addr;
989 struct sigframe *frame;
990 int i;
bellard66fb9762003-03-23 01:06:05 +0000991
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100992 frame_addr = get_sigframe(ka, env, sizeof(*frame));
993 trace_user_setup_frame(env, frame_addr);
bellard66fb9762003-03-23 01:06:05 +0000994
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100995 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
996 goto give_sigsegv;
bellard579a97f2007-11-11 14:26:47 +0000997
Peter Maydellb6e2c932015-01-08 12:19:43 +0000998 __put_user(sig, &frame->sig);
bellard66fb9762003-03-23 01:06:05 +0000999
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001000 setup_sigcontext(&frame->sc, &frame->fpstate, env, set->sig[0],
1001 frame_addr + offsetof(struct sigframe, fpstate));
bellard66fb9762003-03-23 01:06:05 +00001002
Riku Voipio7df2fa32014-04-23 10:34:53 +03001003 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
1004 __put_user(set->sig[i], &frame->extramask[i - 1]);
1005 }
bellard66fb9762003-03-23 01:06:05 +00001006
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001007 /* Set up to return from userspace. If provided, use a stub
1008 already in userspace. */
1009 if (ka->sa_flags & TARGET_SA_RESTORER) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03001010 __put_user(ka->sa_restorer, &frame->pretcode);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001011 } else {
1012 uint16_t val16;
1013 abi_ulong retcode_addr;
1014 retcode_addr = frame_addr + offsetof(struct sigframe, retcode);
Riku Voipio1d8b5122014-04-23 10:26:05 +03001015 __put_user(retcode_addr, &frame->pretcode);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001016 /* This is popl %eax ; movl $,%eax ; int $0x80 */
1017 val16 = 0xb858;
Riku Voipio1d8b5122014-04-23 10:26:05 +03001018 __put_user(val16, (uint16_t *)(frame->retcode+0));
1019 __put_user(TARGET_NR_sigreturn, (int *)(frame->retcode+2));
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001020 val16 = 0x80cd;
Riku Voipio1d8b5122014-04-23 10:26:05 +03001021 __put_user(val16, (uint16_t *)(frame->retcode+6));
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001022 }
bellard66fb9762003-03-23 01:06:05 +00001023
bellard66fb9762003-03-23 01:06:05 +00001024
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001025 /* Set up registers for signal handler */
1026 env->regs[R_ESP] = frame_addr;
1027 env->eip = ka->_sa_handler;
bellard66fb9762003-03-23 01:06:05 +00001028
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001029 cpu_x86_load_seg(env, R_DS, __USER_DS);
1030 cpu_x86_load_seg(env, R_ES, __USER_DS);
1031 cpu_x86_load_seg(env, R_SS, __USER_DS);
1032 cpu_x86_load_seg(env, R_CS, __USER_CS);
1033 env->eflags &= ~TF_MASK;
bellard66fb9762003-03-23 01:06:05 +00001034
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001035 unlock_user_struct(frame, frame_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00001036
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001037 return;
bellard66fb9762003-03-23 01:06:05 +00001038
1039give_sigsegv:
Peter Maydell09391662016-07-28 16:44:47 +01001040 force_sigsegv(sig);
bellard66fb9762003-03-23 01:06:05 +00001041}
1042
bellard579a97f2007-11-11 14:26:47 +00001043/* compare linux/arch/i386/kernel/signal.c:setup_rt_frame() */
pbrook624f7972008-05-31 16:11:38 +00001044static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05001045 target_siginfo_t *info,
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001046 target_sigset_t *set, CPUX86State *env)
bellard66fb9762003-03-23 01:06:05 +00001047{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001048 abi_ulong frame_addr, addr;
1049 struct rt_sigframe *frame;
1050 int i;
bellard66fb9762003-03-23 01:06:05 +00001051
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001052 frame_addr = get_sigframe(ka, env, sizeof(*frame));
1053 trace_user_setup_rt_frame(env, frame_addr);
bellard66fb9762003-03-23 01:06:05 +00001054
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001055 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
1056 goto give_sigsegv;
bellard66fb9762003-03-23 01:06:05 +00001057
Peter Maydellb6e2c932015-01-08 12:19:43 +00001058 __put_user(sig, &frame->sig);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001059 addr = frame_addr + offsetof(struct rt_sigframe, info);
Riku Voipio1d8b5122014-04-23 10:26:05 +03001060 __put_user(addr, &frame->pinfo);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001061 addr = frame_addr + offsetof(struct rt_sigframe, uc);
Riku Voipio1d8b5122014-04-23 10:26:05 +03001062 __put_user(addr, &frame->puc);
Peter Maydellf6c7a052015-01-08 12:19:48 +00001063 tswap_siginfo(&frame->info, info);
bellard66fb9762003-03-23 01:06:05 +00001064
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001065 /* Create the ucontext. */
Riku Voipio1d8b5122014-04-23 10:26:05 +03001066 __put_user(0, &frame->uc.tuc_flags);
1067 __put_user(0, &frame->uc.tuc_link);
1068 __put_user(target_sigaltstack_used.ss_sp, &frame->uc.tuc_stack.ss_sp);
1069 __put_user(sas_ss_flags(get_sp_from_cpustate(env)),
1070 &frame->uc.tuc_stack.ss_flags);
1071 __put_user(target_sigaltstack_used.ss_size,
1072 &frame->uc.tuc_stack.ss_size);
Riku Voipio41ecc722014-04-23 11:01:00 +03001073 setup_sigcontext(&frame->uc.tuc_mcontext, &frame->fpstate, env,
1074 set->sig[0], frame_addr + offsetof(struct rt_sigframe, fpstate));
1075
Riku Voipio0188fad2014-04-23 13:34:15 +03001076 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
1077 __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
1078 }
bellard66fb9762003-03-23 01:06:05 +00001079
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001080 /* Set up to return from userspace. If provided, use a stub
1081 already in userspace. */
1082 if (ka->sa_flags & TARGET_SA_RESTORER) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03001083 __put_user(ka->sa_restorer, &frame->pretcode);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001084 } else {
1085 uint16_t val16;
1086 addr = frame_addr + offsetof(struct rt_sigframe, retcode);
Riku Voipio1d8b5122014-04-23 10:26:05 +03001087 __put_user(addr, &frame->pretcode);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001088 /* This is movl $,%eax ; int $0x80 */
Riku Voipio1d8b5122014-04-23 10:26:05 +03001089 __put_user(0xb8, (char *)(frame->retcode+0));
1090 __put_user(TARGET_NR_rt_sigreturn, (int *)(frame->retcode+1));
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001091 val16 = 0x80cd;
Riku Voipio1d8b5122014-04-23 10:26:05 +03001092 __put_user(val16, (uint16_t *)(frame->retcode+5));
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001093 }
bellard66fb9762003-03-23 01:06:05 +00001094
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001095 /* Set up registers for signal handler */
1096 env->regs[R_ESP] = frame_addr;
1097 env->eip = ka->_sa_handler;
bellard66fb9762003-03-23 01:06:05 +00001098
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001099 cpu_x86_load_seg(env, R_DS, __USER_DS);
1100 cpu_x86_load_seg(env, R_ES, __USER_DS);
1101 cpu_x86_load_seg(env, R_SS, __USER_DS);
1102 cpu_x86_load_seg(env, R_CS, __USER_CS);
1103 env->eflags &= ~TF_MASK;
bellard66fb9762003-03-23 01:06:05 +00001104
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001105 unlock_user_struct(frame, frame_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00001106
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001107 return;
bellard66fb9762003-03-23 01:06:05 +00001108
1109give_sigsegv:
Peter Maydell09391662016-07-28 16:44:47 +01001110 force_sigsegv(sig);
bellard66fb9762003-03-23 01:06:05 +00001111}
1112
1113static int
Timothy E Baldwin0284b032016-05-12 18:47:30 +01001114restore_sigcontext(CPUX86State *env, struct target_sigcontext *sc)
bellard66fb9762003-03-23 01:06:05 +00001115{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001116 unsigned int err = 0;
1117 abi_ulong fpstate_addr;
1118 unsigned int tmpflags;
bellard66fb9762003-03-23 01:06:05 +00001119
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001120 cpu_x86_load_seg(env, R_GS, tswap16(sc->gs));
1121 cpu_x86_load_seg(env, R_FS, tswap16(sc->fs));
1122 cpu_x86_load_seg(env, R_ES, tswap16(sc->es));
1123 cpu_x86_load_seg(env, R_DS, tswap16(sc->ds));
bellard66fb9762003-03-23 01:06:05 +00001124
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001125 env->regs[R_EDI] = tswapl(sc->edi);
1126 env->regs[R_ESI] = tswapl(sc->esi);
1127 env->regs[R_EBP] = tswapl(sc->ebp);
1128 env->regs[R_ESP] = tswapl(sc->esp);
1129 env->regs[R_EBX] = tswapl(sc->ebx);
1130 env->regs[R_EDX] = tswapl(sc->edx);
1131 env->regs[R_ECX] = tswapl(sc->ecx);
Timothy E Baldwin0284b032016-05-12 18:47:30 +01001132 env->regs[R_EAX] = tswapl(sc->eax);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001133 env->eip = tswapl(sc->eip);
bellard66fb9762003-03-23 01:06:05 +00001134
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001135 cpu_x86_load_seg(env, R_CS, lduw_p(&sc->cs) | 3);
1136 cpu_x86_load_seg(env, R_SS, lduw_p(&sc->ss) | 3);
ths5fafdf22007-09-16 21:08:06 +00001137
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001138 tmpflags = tswapl(sc->eflags);
1139 env->eflags = (env->eflags & ~0x40DD5) | (tmpflags & 0x40DD5);
1140 // regs->orig_eax = -1; /* disable syscall checks */
bellard28be6232007-11-11 22:23:38 +00001141
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001142 fpstate_addr = tswapl(sc->fpstate);
1143 if (fpstate_addr != 0) {
1144 if (!access_ok(VERIFY_READ, fpstate_addr,
1145 sizeof(struct target_fpstate)))
1146 goto badframe;
1147 cpu_x86_frstor(env, fpstate_addr, 1);
1148 }
bellard66fb9762003-03-23 01:06:05 +00001149
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001150 return err;
bellard66fb9762003-03-23 01:06:05 +00001151badframe:
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001152 return 1;
bellard66fb9762003-03-23 01:06:05 +00001153}
1154
1155long do_sigreturn(CPUX86State *env)
1156{
bellard579a97f2007-11-11 14:26:47 +00001157 struct sigframe *frame;
1158 abi_ulong frame_addr = env->regs[R_ESP] - 8;
Anthony Liguoric227f092009-10-01 16:12:16 -05001159 target_sigset_t target_set;
bellard66fb9762003-03-23 01:06:05 +00001160 sigset_t set;
Timothy E Baldwin0284b032016-05-12 18:47:30 +01001161 int i;
bellard66fb9762003-03-23 01:06:05 +00001162
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01001163 trace_user_do_sigreturn(env, frame_addr);
bellard579a97f2007-11-11 14:26:47 +00001164 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
1165 goto badframe;
bellard66fb9762003-03-23 01:06:05 +00001166 /* set blocked signals */
Riku Voipiof5f601a2014-04-23 13:00:17 +03001167 __get_user(target_set.sig[0], &frame->sc.oldmask);
bellard92319442004-06-19 16:58:13 +00001168 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
Riku Voipiof5f601a2014-04-23 13:00:17 +03001169 __get_user(target_set.sig[i], &frame->extramask[i - 1]);
bellard92319442004-06-19 16:58:13 +00001170 }
bellard66fb9762003-03-23 01:06:05 +00001171
bellard92319442004-06-19 16:58:13 +00001172 target_to_host_sigset_internal(&set, &target_set);
Peter Maydell9eede5b2016-05-27 15:51:46 +01001173 set_sigmask(&set);
ths3b46e622007-09-17 08:09:54 +00001174
bellard66fb9762003-03-23 01:06:05 +00001175 /* restore registers */
Timothy E Baldwin0284b032016-05-12 18:47:30 +01001176 if (restore_sigcontext(env, &frame->sc))
bellard66fb9762003-03-23 01:06:05 +00001177 goto badframe;
bellard579a97f2007-11-11 14:26:47 +00001178 unlock_user_struct(frame, frame_addr, 0);
Timothy E Baldwin0284b032016-05-12 18:47:30 +01001179 return -TARGET_QEMU_ESIGRETURN;
bellard66fb9762003-03-23 01:06:05 +00001180
1181badframe:
bellard579a97f2007-11-11 14:26:47 +00001182 unlock_user_struct(frame, frame_addr, 0);
bellard66fb9762003-03-23 01:06:05 +00001183 force_sig(TARGET_SIGSEGV);
1184 return 0;
1185}
1186
1187long do_rt_sigreturn(CPUX86State *env)
1188{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001189 abi_ulong frame_addr;
1190 struct rt_sigframe *frame;
1191 sigset_t set;
bellard66fb9762003-03-23 01:06:05 +00001192
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001193 frame_addr = env->regs[R_ESP] - 4;
1194 trace_user_do_rt_sigreturn(env, frame_addr);
1195 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
1196 goto badframe;
1197 target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
Peter Maydell9eede5b2016-05-27 15:51:46 +01001198 set_sigmask(&set);
ths5fafdf22007-09-16 21:08:06 +00001199
Timothy E Baldwin0284b032016-05-12 18:47:30 +01001200 if (restore_sigcontext(env, &frame->uc.tuc_mcontext)) {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001201 goto badframe;
1202 }
bellard66fb9762003-03-23 01:06:05 +00001203
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001204 if (do_sigaltstack(frame_addr + offsetof(struct rt_sigframe, uc.tuc_stack), 0,
1205 get_sp_from_cpustate(env)) == -EFAULT) {
1206 goto badframe;
1207 }
thsa04e1342007-09-27 13:57:58 +00001208
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001209 unlock_user_struct(frame, frame_addr, 0);
Timothy E Baldwin0284b032016-05-12 18:47:30 +01001210 return -TARGET_QEMU_ESIGRETURN;
bellard66fb9762003-03-23 01:06:05 +00001211
1212badframe:
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001213 unlock_user_struct(frame, frame_addr, 0);
1214 force_sig(TARGET_SIGSEGV);
1215 return 0;
bellard66fb9762003-03-23 01:06:05 +00001216}
1217
Andreas Schwab1744aea2013-09-03 20:12:16 +01001218#elif defined(TARGET_AARCH64)
1219
1220struct target_sigcontext {
1221 uint64_t fault_address;
1222 /* AArch64 registers */
1223 uint64_t regs[31];
1224 uint64_t sp;
1225 uint64_t pc;
1226 uint64_t pstate;
1227 /* 4K reserved for FP/SIMD state and future expansion */
1228 char __reserved[4096] __attribute__((__aligned__(16)));
1229};
1230
1231struct target_ucontext {
1232 abi_ulong tuc_flags;
1233 abi_ulong tuc_link;
1234 target_stack_t tuc_stack;
1235 target_sigset_t tuc_sigmask;
1236 /* glibc uses a 1024-bit sigset_t */
1237 char __unused[1024 / 8 - sizeof(target_sigset_t)];
1238 /* last for future expansion */
1239 struct target_sigcontext tuc_mcontext;
1240};
1241
1242/*
1243 * Header to be used at the beginning of structures extending the user
1244 * context. Such structures must be placed after the rt_sigframe on the stack
1245 * and be 16-byte aligned. The last structure must be a dummy one with the
1246 * magic and size set to 0.
1247 */
1248struct target_aarch64_ctx {
1249 uint32_t magic;
1250 uint32_t size;
1251};
1252
1253#define TARGET_FPSIMD_MAGIC 0x46508001
1254
1255struct target_fpsimd_context {
1256 struct target_aarch64_ctx head;
1257 uint32_t fpsr;
1258 uint32_t fpcr;
1259 uint64_t vregs[32 * 2]; /* really uint128_t vregs[32] */
1260};
1261
1262/*
1263 * Auxiliary context saved in the sigcontext.__reserved array. Not exported to
1264 * user space as it will change with the addition of new context. User space
1265 * should check the magic/size information.
1266 */
1267struct target_aux_context {
1268 struct target_fpsimd_context fpsimd;
1269 /* additional context to be added before "end" */
1270 struct target_aarch64_ctx end;
1271};
1272
1273struct target_rt_sigframe {
1274 struct target_siginfo info;
1275 struct target_ucontext uc;
1276 uint64_t fp;
1277 uint64_t lr;
1278 uint32_t tramp[2];
1279};
1280
1281static int target_setup_sigframe(struct target_rt_sigframe *sf,
1282 CPUARMState *env, target_sigset_t *set)
1283{
1284 int i;
1285 struct target_aux_context *aux =
1286 (struct target_aux_context *)sf->uc.tuc_mcontext.__reserved;
1287
1288 /* set up the stack frame for unwinding */
1289 __put_user(env->xregs[29], &sf->fp);
1290 __put_user(env->xregs[30], &sf->lr);
1291
1292 for (i = 0; i < 31; i++) {
1293 __put_user(env->xregs[i], &sf->uc.tuc_mcontext.regs[i]);
1294 }
1295 __put_user(env->xregs[31], &sf->uc.tuc_mcontext.sp);
1296 __put_user(env->pc, &sf->uc.tuc_mcontext.pc);
Peter Maydelld3563122013-12-17 19:42:30 +00001297 __put_user(pstate_read(env), &sf->uc.tuc_mcontext.pstate);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001298
Peter Maydell7af03922014-05-01 18:36:17 +01001299 __put_user(env->exception.vaddress, &sf->uc.tuc_mcontext.fault_address);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001300
1301 for (i = 0; i < TARGET_NSIG_WORDS; i++) {
1302 __put_user(set->sig[i], &sf->uc.tuc_sigmask.sig[i]);
1303 }
1304
1305 for (i = 0; i < 32; i++) {
1306#ifdef TARGET_WORDS_BIGENDIAN
1307 __put_user(env->vfp.regs[i * 2], &aux->fpsimd.vregs[i * 2 + 1]);
1308 __put_user(env->vfp.regs[i * 2 + 1], &aux->fpsimd.vregs[i * 2]);
1309#else
1310 __put_user(env->vfp.regs[i * 2], &aux->fpsimd.vregs[i * 2]);
1311 __put_user(env->vfp.regs[i * 2 + 1], &aux->fpsimd.vregs[i * 2 + 1]);
1312#endif
1313 }
Will Newtone0ee1382014-01-04 22:15:48 +00001314 __put_user(vfp_get_fpsr(env), &aux->fpsimd.fpsr);
1315 __put_user(vfp_get_fpcr(env), &aux->fpsimd.fpcr);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001316 __put_user(TARGET_FPSIMD_MAGIC, &aux->fpsimd.head.magic);
1317 __put_user(sizeof(struct target_fpsimd_context),
1318 &aux->fpsimd.head.size);
1319
1320 /* set the "end" magic */
1321 __put_user(0, &aux->end.magic);
1322 __put_user(0, &aux->end.size);
1323
1324 return 0;
1325}
1326
1327static int target_restore_sigframe(CPUARMState *env,
1328 struct target_rt_sigframe *sf)
1329{
1330 sigset_t set;
1331 int i;
1332 struct target_aux_context *aux =
1333 (struct target_aux_context *)sf->uc.tuc_mcontext.__reserved;
Will Newtone0ee1382014-01-04 22:15:48 +00001334 uint32_t magic, size, fpsr, fpcr;
Peter Maydelld3563122013-12-17 19:42:30 +00001335 uint64_t pstate;
Andreas Schwab1744aea2013-09-03 20:12:16 +01001336
1337 target_to_host_sigset(&set, &sf->uc.tuc_sigmask);
Peter Maydell9eede5b2016-05-27 15:51:46 +01001338 set_sigmask(&set);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001339
1340 for (i = 0; i < 31; i++) {
1341 __get_user(env->xregs[i], &sf->uc.tuc_mcontext.regs[i]);
1342 }
1343
1344 __get_user(env->xregs[31], &sf->uc.tuc_mcontext.sp);
1345 __get_user(env->pc, &sf->uc.tuc_mcontext.pc);
Peter Maydelld3563122013-12-17 19:42:30 +00001346 __get_user(pstate, &sf->uc.tuc_mcontext.pstate);
1347 pstate_write(env, pstate);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001348
1349 __get_user(magic, &aux->fpsimd.head.magic);
1350 __get_user(size, &aux->fpsimd.head.size);
1351
1352 if (magic != TARGET_FPSIMD_MAGIC
1353 || size != sizeof(struct target_fpsimd_context)) {
1354 return 1;
1355 }
1356
Peter Maydell4cf23482014-03-02 19:36:38 +00001357 for (i = 0; i < 32; i++) {
1358#ifdef TARGET_WORDS_BIGENDIAN
1359 __get_user(env->vfp.regs[i * 2], &aux->fpsimd.vregs[i * 2 + 1]);
1360 __get_user(env->vfp.regs[i * 2 + 1], &aux->fpsimd.vregs[i * 2]);
1361#else
1362 __get_user(env->vfp.regs[i * 2], &aux->fpsimd.vregs[i * 2]);
1363 __get_user(env->vfp.regs[i * 2 + 1], &aux->fpsimd.vregs[i * 2 + 1]);
1364#endif
Andreas Schwab1744aea2013-09-03 20:12:16 +01001365 }
Will Newtone0ee1382014-01-04 22:15:48 +00001366 __get_user(fpsr, &aux->fpsimd.fpsr);
1367 vfp_set_fpsr(env, fpsr);
1368 __get_user(fpcr, &aux->fpsimd.fpcr);
1369 vfp_set_fpcr(env, fpcr);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001370
1371 return 0;
1372}
1373
1374static abi_ulong get_sigframe(struct target_sigaction *ka, CPUARMState *env)
1375{
1376 abi_ulong sp;
1377
1378 sp = env->xregs[31];
1379
1380 /*
1381 * This is the X/Open sanctioned signal stack switching.
1382 */
Riku Voipiob545f632014-07-15 17:01:55 +03001383 if ((ka->sa_flags & TARGET_SA_ONSTACK) && !sas_ss_flags(sp)) {
Andreas Schwab1744aea2013-09-03 20:12:16 +01001384 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
1385 }
1386
1387 sp = (sp - sizeof(struct target_rt_sigframe)) & ~15;
1388
1389 return sp;
1390}
1391
1392static void target_setup_frame(int usig, struct target_sigaction *ka,
1393 target_siginfo_t *info, target_sigset_t *set,
1394 CPUARMState *env)
1395{
1396 struct target_rt_sigframe *frame;
Michael Matz8a3ae912014-03-02 19:36:39 +00001397 abi_ulong frame_addr, return_addr;
Andreas Schwab1744aea2013-09-03 20:12:16 +01001398
1399 frame_addr = get_sigframe(ka, env);
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01001400 trace_user_setup_frame(env, frame_addr);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001401 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
1402 goto give_sigsegv;
1403 }
1404
1405 __put_user(0, &frame->uc.tuc_flags);
1406 __put_user(0, &frame->uc.tuc_link);
1407
1408 __put_user(target_sigaltstack_used.ss_sp,
1409 &frame->uc.tuc_stack.ss_sp);
1410 __put_user(sas_ss_flags(env->xregs[31]),
1411 &frame->uc.tuc_stack.ss_flags);
1412 __put_user(target_sigaltstack_used.ss_size,
1413 &frame->uc.tuc_stack.ss_size);
1414 target_setup_sigframe(frame, env, set);
Michael Matz8a3ae912014-03-02 19:36:39 +00001415 if (ka->sa_flags & TARGET_SA_RESTORER) {
1416 return_addr = ka->sa_restorer;
1417 } else {
1418 /* mov x8,#__NR_rt_sigreturn; svc #0 */
1419 __put_user(0xd2801168, &frame->tramp[0]);
1420 __put_user(0xd4000001, &frame->tramp[1]);
1421 return_addr = frame_addr + offsetof(struct target_rt_sigframe, tramp);
1422 }
Andreas Schwab1744aea2013-09-03 20:12:16 +01001423 env->xregs[0] = usig;
1424 env->xregs[31] = frame_addr;
1425 env->xregs[29] = env->xregs[31] + offsetof(struct target_rt_sigframe, fp);
1426 env->pc = ka->_sa_handler;
Michael Matz8a3ae912014-03-02 19:36:39 +00001427 env->xregs[30] = return_addr;
Andreas Schwab1744aea2013-09-03 20:12:16 +01001428 if (info) {
Peter Maydellf6c7a052015-01-08 12:19:48 +00001429 tswap_siginfo(&frame->info, info);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001430 env->xregs[1] = frame_addr + offsetof(struct target_rt_sigframe, info);
1431 env->xregs[2] = frame_addr + offsetof(struct target_rt_sigframe, uc);
1432 }
1433
1434 unlock_user_struct(frame, frame_addr, 1);
1435 return;
1436
1437 give_sigsegv:
1438 unlock_user_struct(frame, frame_addr, 1);
Peter Maydell09391662016-07-28 16:44:47 +01001439 force_sigsegv(usig);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001440}
1441
1442static void setup_rt_frame(int sig, struct target_sigaction *ka,
1443 target_siginfo_t *info, target_sigset_t *set,
1444 CPUARMState *env)
1445{
1446 target_setup_frame(sig, ka, info, set, env);
1447}
1448
1449static void setup_frame(int sig, struct target_sigaction *ka,
1450 target_sigset_t *set, CPUARMState *env)
1451{
1452 target_setup_frame(sig, ka, 0, set, env);
1453}
1454
1455long do_rt_sigreturn(CPUARMState *env)
1456{
Peter Maydell7f72cd22014-03-12 13:06:00 +00001457 struct target_rt_sigframe *frame = NULL;
Andreas Schwab1744aea2013-09-03 20:12:16 +01001458 abi_ulong frame_addr = env->xregs[31];
1459
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01001460 trace_user_do_rt_sigreturn(env, frame_addr);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001461 if (frame_addr & 15) {
1462 goto badframe;
1463 }
1464
1465 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
1466 goto badframe;
1467 }
1468
1469 if (target_restore_sigframe(env, frame)) {
1470 goto badframe;
1471 }
1472
1473 if (do_sigaltstack(frame_addr +
1474 offsetof(struct target_rt_sigframe, uc.tuc_stack),
1475 0, get_sp_from_cpustate(env)) == -EFAULT) {
1476 goto badframe;
1477 }
1478
1479 unlock_user_struct(frame, frame_addr, 0);
Timothy E Baldwinf0267ef2016-05-12 18:47:31 +01001480 return -TARGET_QEMU_ESIGRETURN;
Andreas Schwab1744aea2013-09-03 20:12:16 +01001481
1482 badframe:
1483 unlock_user_struct(frame, frame_addr, 0);
1484 force_sig(TARGET_SIGSEGV);
1485 return 0;
1486}
1487
1488long do_sigreturn(CPUARMState *env)
1489{
1490 return do_rt_sigreturn(env);
1491}
1492
bellard43fff232003-07-09 19:31:39 +00001493#elif defined(TARGET_ARM)
1494
1495struct target_sigcontext {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001496 abi_ulong trap_no;
1497 abi_ulong error_code;
1498 abi_ulong oldmask;
1499 abi_ulong arm_r0;
1500 abi_ulong arm_r1;
1501 abi_ulong arm_r2;
1502 abi_ulong arm_r3;
1503 abi_ulong arm_r4;
1504 abi_ulong arm_r5;
1505 abi_ulong arm_r6;
1506 abi_ulong arm_r7;
1507 abi_ulong arm_r8;
1508 abi_ulong arm_r9;
1509 abi_ulong arm_r10;
1510 abi_ulong arm_fp;
1511 abi_ulong arm_ip;
1512 abi_ulong arm_sp;
1513 abi_ulong arm_lr;
1514 abi_ulong arm_pc;
1515 abi_ulong arm_cpsr;
1516 abi_ulong fault_address;
bellard43fff232003-07-09 19:31:39 +00001517};
1518
pbrooka745ec62008-05-06 15:36:17 +00001519struct target_ucontext_v1 {
blueswir1992f48a2007-10-14 16:27:31 +00001520 abi_ulong tuc_flags;
1521 abi_ulong tuc_link;
Anthony Liguoric227f092009-10-01 16:12:16 -05001522 target_stack_t tuc_stack;
bellardb8076a72005-04-07 22:20:31 +00001523 struct target_sigcontext tuc_mcontext;
Anthony Liguoric227f092009-10-01 16:12:16 -05001524 target_sigset_t tuc_sigmask; /* mask last for extensibility */
bellard43fff232003-07-09 19:31:39 +00001525};
1526
pbrooka745ec62008-05-06 15:36:17 +00001527struct target_ucontext_v2 {
1528 abi_ulong tuc_flags;
1529 abi_ulong tuc_link;
Anthony Liguoric227f092009-10-01 16:12:16 -05001530 target_stack_t tuc_stack;
pbrooka745ec62008-05-06 15:36:17 +00001531 struct target_sigcontext tuc_mcontext;
Anthony Liguoric227f092009-10-01 16:12:16 -05001532 target_sigset_t tuc_sigmask; /* mask last for extensibility */
Peter Maydell5f0b7c82010-11-24 15:20:03 +00001533 char __unused[128 - sizeof(target_sigset_t)];
pbrooka745ec62008-05-06 15:36:17 +00001534 abi_ulong tuc_regspace[128] __attribute__((__aligned__(8)));
1535};
1536
Peter Maydell0d871bd2010-11-24 15:20:05 +00001537struct target_user_vfp {
1538 uint64_t fpregs[32];
1539 abi_ulong fpscr;
1540};
1541
1542struct target_user_vfp_exc {
1543 abi_ulong fpexc;
1544 abi_ulong fpinst;
1545 abi_ulong fpinst2;
1546};
1547
1548struct target_vfp_sigframe {
1549 abi_ulong magic;
1550 abi_ulong size;
1551 struct target_user_vfp ufp;
1552 struct target_user_vfp_exc ufp_exc;
1553} __attribute__((__aligned__(8)));
1554
Peter Maydell08e11252010-11-24 15:20:07 +00001555struct target_iwmmxt_sigframe {
1556 abi_ulong magic;
1557 abi_ulong size;
1558 uint64_t regs[16];
1559 /* Note that not all the coprocessor control registers are stored here */
1560 uint32_t wcssf;
1561 uint32_t wcasf;
1562 uint32_t wcgr0;
1563 uint32_t wcgr1;
1564 uint32_t wcgr2;
1565 uint32_t wcgr3;
1566} __attribute__((__aligned__(8)));
1567
Peter Maydell0d871bd2010-11-24 15:20:05 +00001568#define TARGET_VFP_MAGIC 0x56465001
Peter Maydell08e11252010-11-24 15:20:07 +00001569#define TARGET_IWMMXT_MAGIC 0x12ef842a
Peter Maydell0d871bd2010-11-24 15:20:05 +00001570
pbrooka8c33202008-05-07 23:22:46 +00001571struct sigframe_v1
bellard43fff232003-07-09 19:31:39 +00001572{
1573 struct target_sigcontext sc;
blueswir1992f48a2007-10-14 16:27:31 +00001574 abi_ulong extramask[TARGET_NSIG_WORDS-1];
1575 abi_ulong retcode;
bellard43fff232003-07-09 19:31:39 +00001576};
1577
pbrooka8c33202008-05-07 23:22:46 +00001578struct sigframe_v2
1579{
1580 struct target_ucontext_v2 uc;
1581 abi_ulong retcode;
1582};
1583
pbrooka745ec62008-05-06 15:36:17 +00001584struct rt_sigframe_v1
bellard43fff232003-07-09 19:31:39 +00001585{
bellardf8b0aa22007-11-11 23:03:42 +00001586 abi_ulong pinfo;
1587 abi_ulong puc;
bellard43fff232003-07-09 19:31:39 +00001588 struct target_siginfo info;
pbrooka745ec62008-05-06 15:36:17 +00001589 struct target_ucontext_v1 uc;
1590 abi_ulong retcode;
1591};
1592
1593struct rt_sigframe_v2
1594{
1595 struct target_siginfo info;
1596 struct target_ucontext_v2 uc;
blueswir1992f48a2007-10-14 16:27:31 +00001597 abi_ulong retcode;
bellard43fff232003-07-09 19:31:39 +00001598};
1599
1600#define TARGET_CONFIG_CPU_32 1
1601
1602/*
1603 * For ARM syscalls, we encode the syscall number into the instruction.
1604 */
1605#define SWI_SYS_SIGRETURN (0xef000000|(TARGET_NR_sigreturn + ARM_SYSCALL_BASE))
1606#define SWI_SYS_RT_SIGRETURN (0xef000000|(TARGET_NR_rt_sigreturn + ARM_SYSCALL_BASE))
1607
1608/*
1609 * For Thumb syscalls, we pass the syscall number via r7. We therefore
1610 * need two 16-bit instructions.
1611 */
1612#define SWI_THUMB_SIGRETURN (0xdf00 << 16 | 0x2700 | (TARGET_NR_sigreturn))
1613#define SWI_THUMB_RT_SIGRETURN (0xdf00 << 16 | 0x2700 | (TARGET_NR_rt_sigreturn))
1614
blueswir1992f48a2007-10-14 16:27:31 +00001615static const abi_ulong retcodes[4] = {
bellard43fff232003-07-09 19:31:39 +00001616 SWI_SYS_SIGRETURN, SWI_THUMB_SIGRETURN,
1617 SWI_SYS_RT_SIGRETURN, SWI_THUMB_RT_SIGRETURN
1618};
1619
1620
Andreas Färber05390242012-02-25 03:37:53 +01001621static inline int valid_user_regs(CPUARMState *regs)
bellard43fff232003-07-09 19:31:39 +00001622{
1623 return 1;
1624}
1625
pbrooka8c33202008-05-07 23:22:46 +00001626static void
bellard43fff232003-07-09 19:31:39 +00001627setup_sigcontext(struct target_sigcontext *sc, /*struct _fpstate *fpstate,*/
Andreas Färber05390242012-02-25 03:37:53 +01001628 CPUARMState *env, abi_ulong mask)
bellard43fff232003-07-09 19:31:39 +00001629{
Paolo Bonzinia0e1e6d2016-03-04 11:30:18 +00001630 __put_user(env->regs[0], &sc->arm_r0);
1631 __put_user(env->regs[1], &sc->arm_r1);
1632 __put_user(env->regs[2], &sc->arm_r2);
1633 __put_user(env->regs[3], &sc->arm_r3);
1634 __put_user(env->regs[4], &sc->arm_r4);
1635 __put_user(env->regs[5], &sc->arm_r5);
1636 __put_user(env->regs[6], &sc->arm_r6);
1637 __put_user(env->regs[7], &sc->arm_r7);
1638 __put_user(env->regs[8], &sc->arm_r8);
1639 __put_user(env->regs[9], &sc->arm_r9);
1640 __put_user(env->regs[10], &sc->arm_r10);
1641 __put_user(env->regs[11], &sc->arm_fp);
1642 __put_user(env->regs[12], &sc->arm_ip);
1643 __put_user(env->regs[13], &sc->arm_sp);
1644 __put_user(env->regs[14], &sc->arm_lr);
1645 __put_user(env->regs[15], &sc->arm_pc);
bellard43fff232003-07-09 19:31:39 +00001646#ifdef TARGET_CONFIG_CPU_32
Paolo Bonzinia0e1e6d2016-03-04 11:30:18 +00001647 __put_user(cpsr_read(env), &sc->arm_cpsr);
bellard43fff232003-07-09 19:31:39 +00001648#endif
1649
Paolo Bonzinia0e1e6d2016-03-04 11:30:18 +00001650 __put_user(/* current->thread.trap_no */ 0, &sc->trap_no);
1651 __put_user(/* current->thread.error_code */ 0, &sc->error_code);
1652 __put_user(/* current->thread.address */ 0, &sc->fault_address);
1653 __put_user(mask, &sc->oldmask);
bellard43fff232003-07-09 19:31:39 +00001654}
1655
bellard579a97f2007-11-11 14:26:47 +00001656static inline abi_ulong
Andreas Färber05390242012-02-25 03:37:53 +01001657get_sigframe(struct target_sigaction *ka, CPUARMState *regs, int framesize)
bellard43fff232003-07-09 19:31:39 +00001658{
Paolo Bonzinia0e1e6d2016-03-04 11:30:18 +00001659 unsigned long sp = regs->regs[13];
bellard43fff232003-07-09 19:31:39 +00001660
Paolo Bonzinia0e1e6d2016-03-04 11:30:18 +00001661 /*
1662 * This is the X/Open sanctioned signal stack switching.
1663 */
1664 if ((ka->sa_flags & TARGET_SA_ONSTACK) && !sas_ss_flags(sp)) {
1665 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
1666 }
1667 /*
1668 * ATPCS B01 mandates 8-byte alignment
1669 */
1670 return (sp - framesize) & ~7;
bellard43fff232003-07-09 19:31:39 +00001671}
1672
Riku Voipio0188fad2014-04-23 13:34:15 +03001673static void
Andreas Färber05390242012-02-25 03:37:53 +01001674setup_return(CPUARMState *env, struct target_sigaction *ka,
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001675 abi_ulong *rc, abi_ulong frame_addr, int usig, abi_ulong rc_addr)
bellard43fff232003-07-09 19:31:39 +00001676{
Paolo Bonzinia0e1e6d2016-03-04 11:30:18 +00001677 abi_ulong handler = ka->_sa_handler;
1678 abi_ulong retcode;
1679 int thumb = handler & 1;
1680 uint32_t cpsr = cpsr_read(env);
Peter Maydell964413d2011-01-14 20:39:19 +01001681
Paolo Bonzinia0e1e6d2016-03-04 11:30:18 +00001682 cpsr &= ~CPSR_IT;
1683 if (thumb) {
1684 cpsr |= CPSR_T;
1685 } else {
1686 cpsr &= ~CPSR_T;
1687 }
bellard43fff232003-07-09 19:31:39 +00001688
Paolo Bonzinia0e1e6d2016-03-04 11:30:18 +00001689 if (ka->sa_flags & TARGET_SA_RESTORER) {
1690 retcode = ka->sa_restorer;
1691 } else {
1692 unsigned int idx = thumb;
bellard43fff232003-07-09 19:31:39 +00001693
Paolo Bonzinia0e1e6d2016-03-04 11:30:18 +00001694 if (ka->sa_flags & TARGET_SA_SIGINFO) {
1695 idx += 2;
1696 }
bellard43fff232003-07-09 19:31:39 +00001697
Riku Voipio0188fad2014-04-23 13:34:15 +03001698 __put_user(retcodes[idx], rc);
Stefan Weilca8a2772011-10-03 22:43:19 +02001699
Paolo Bonzinia0e1e6d2016-03-04 11:30:18 +00001700 retcode = rc_addr + thumb;
1701 }
bellard43fff232003-07-09 19:31:39 +00001702
Paolo Bonzinia0e1e6d2016-03-04 11:30:18 +00001703 env->regs[0] = usig;
1704 env->regs[13] = frame_addr;
1705 env->regs[14] = retcode;
1706 env->regs[15] = handler & (thumb ? ~1 : ~3);
1707 cpsr_write(env, cpsr, CPSR_IT | CPSR_T, CPSRWriteByInstr);
bellard43fff232003-07-09 19:31:39 +00001708}
1709
Andreas Färber05390242012-02-25 03:37:53 +01001710static abi_ulong *setup_sigframe_v2_vfp(abi_ulong *regspace, CPUARMState *env)
Peter Maydell0d871bd2010-11-24 15:20:05 +00001711{
1712 int i;
1713 struct target_vfp_sigframe *vfpframe;
1714 vfpframe = (struct target_vfp_sigframe *)regspace;
1715 __put_user(TARGET_VFP_MAGIC, &vfpframe->magic);
1716 __put_user(sizeof(*vfpframe), &vfpframe->size);
1717 for (i = 0; i < 32; i++) {
Peter Maydell005e1a02011-02-10 13:59:35 +00001718 __put_user(float64_val(env->vfp.regs[i]), &vfpframe->ufp.fpregs[i]);
Peter Maydell0d871bd2010-11-24 15:20:05 +00001719 }
1720 __put_user(vfp_get_fpscr(env), &vfpframe->ufp.fpscr);
1721 __put_user(env->vfp.xregs[ARM_VFP_FPEXC], &vfpframe->ufp_exc.fpexc);
1722 __put_user(env->vfp.xregs[ARM_VFP_FPINST], &vfpframe->ufp_exc.fpinst);
1723 __put_user(env->vfp.xregs[ARM_VFP_FPINST2], &vfpframe->ufp_exc.fpinst2);
1724 return (abi_ulong*)(vfpframe+1);
1725}
1726
Andreas Färber05390242012-02-25 03:37:53 +01001727static abi_ulong *setup_sigframe_v2_iwmmxt(abi_ulong *regspace,
1728 CPUARMState *env)
Peter Maydell08e11252010-11-24 15:20:07 +00001729{
1730 int i;
1731 struct target_iwmmxt_sigframe *iwmmxtframe;
1732 iwmmxtframe = (struct target_iwmmxt_sigframe *)regspace;
1733 __put_user(TARGET_IWMMXT_MAGIC, &iwmmxtframe->magic);
1734 __put_user(sizeof(*iwmmxtframe), &iwmmxtframe->size);
1735 for (i = 0; i < 16; i++) {
1736 __put_user(env->iwmmxt.regs[i], &iwmmxtframe->regs[i]);
1737 }
1738 __put_user(env->vfp.xregs[ARM_IWMMXT_wCSSF], &iwmmxtframe->wcssf);
1739 __put_user(env->vfp.xregs[ARM_IWMMXT_wCASF], &iwmmxtframe->wcssf);
1740 __put_user(env->vfp.xregs[ARM_IWMMXT_wCGR0], &iwmmxtframe->wcgr0);
1741 __put_user(env->vfp.xregs[ARM_IWMMXT_wCGR1], &iwmmxtframe->wcgr1);
1742 __put_user(env->vfp.xregs[ARM_IWMMXT_wCGR2], &iwmmxtframe->wcgr2);
1743 __put_user(env->vfp.xregs[ARM_IWMMXT_wCGR3], &iwmmxtframe->wcgr3);
1744 return (abi_ulong*)(iwmmxtframe+1);
1745}
1746
pbrooka8c33202008-05-07 23:22:46 +00001747static void setup_sigframe_v2(struct target_ucontext_v2 *uc,
Andreas Färber05390242012-02-25 03:37:53 +01001748 target_sigset_t *set, CPUARMState *env)
bellard43fff232003-07-09 19:31:39 +00001749{
pbrooka8c33202008-05-07 23:22:46 +00001750 struct target_sigaltstack stack;
1751 int i;
Peter Maydell0d871bd2010-11-24 15:20:05 +00001752 abi_ulong *regspace;
pbrooka8c33202008-05-07 23:22:46 +00001753
1754 /* Clear all the bits of the ucontext we don't use. */
1755 memset(uc, 0, offsetof(struct target_ucontext_v2, tuc_mcontext));
1756
1757 memset(&stack, 0, sizeof(stack));
1758 __put_user(target_sigaltstack_used.ss_sp, &stack.ss_sp);
1759 __put_user(target_sigaltstack_used.ss_size, &stack.ss_size);
1760 __put_user(sas_ss_flags(get_sp_from_cpustate(env)), &stack.ss_flags);
1761 memcpy(&uc->tuc_stack, &stack, sizeof(stack));
1762
1763 setup_sigcontext(&uc->tuc_mcontext, env, set->sig[0]);
Peter Maydell0d871bd2010-11-24 15:20:05 +00001764 /* Save coprocessor signal frame. */
1765 regspace = uc->tuc_regspace;
1766 if (arm_feature(env, ARM_FEATURE_VFP)) {
1767 regspace = setup_sigframe_v2_vfp(regspace, env);
1768 }
Peter Maydell08e11252010-11-24 15:20:07 +00001769 if (arm_feature(env, ARM_FEATURE_IWMMXT)) {
1770 regspace = setup_sigframe_v2_iwmmxt(regspace, env);
1771 }
1772
Peter Maydell0d871bd2010-11-24 15:20:05 +00001773 /* Write terminating magic word */
1774 __put_user(0, regspace);
1775
pbrooka8c33202008-05-07 23:22:46 +00001776 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
1777 __put_user(set->sig[i], &uc->tuc_sigmask.sig[i]);
1778 }
1779}
1780
1781/* compare linux/arch/arm/kernel/signal.c:setup_frame() */
pbrook624f7972008-05-31 16:11:38 +00001782static void setup_frame_v1(int usig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01001783 target_sigset_t *set, CPUARMState *regs)
pbrooka8c33202008-05-07 23:22:46 +00001784{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001785 struct sigframe_v1 *frame;
1786 abi_ulong frame_addr = get_sigframe(ka, regs, sizeof(*frame));
1787 int i;
bellard43fff232003-07-09 19:31:39 +00001788
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001789 trace_user_setup_frame(regs, frame_addr);
1790 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
Peter Maydell28298c92016-07-28 16:44:48 +01001791 goto sigsegv;
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001792 }
bellard579a97f2007-11-11 14:26:47 +00001793
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001794 setup_sigcontext(&frame->sc, regs, set->sig[0]);
bellard43fff232003-07-09 19:31:39 +00001795
Riku Voipio0188fad2014-04-23 13:34:15 +03001796 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
1797 __put_user(set->sig[i], &frame->extramask[i - 1]);
1798 }
bellard43fff232003-07-09 19:31:39 +00001799
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001800 setup_return(regs, ka, &frame->retcode, frame_addr, usig,
1801 frame_addr + offsetof(struct sigframe_v1, retcode));
bellard579a97f2007-11-11 14:26:47 +00001802
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001803 unlock_user_struct(frame, frame_addr, 1);
Peter Maydell28298c92016-07-28 16:44:48 +01001804 return;
1805sigsegv:
1806 force_sigsegv(usig);
pbrooka8c33202008-05-07 23:22:46 +00001807}
1808
pbrook624f7972008-05-31 16:11:38 +00001809static void setup_frame_v2(int usig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01001810 target_sigset_t *set, CPUARMState *regs)
pbrooka8c33202008-05-07 23:22:46 +00001811{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001812 struct sigframe_v2 *frame;
1813 abi_ulong frame_addr = get_sigframe(ka, regs, sizeof(*frame));
pbrooka8c33202008-05-07 23:22:46 +00001814
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001815 trace_user_setup_frame(regs, frame_addr);
1816 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
Peter Maydell28298c92016-07-28 16:44:48 +01001817 goto sigsegv;
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001818 }
pbrooka8c33202008-05-07 23:22:46 +00001819
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001820 setup_sigframe_v2(&frame->uc, set, regs);
pbrooka8c33202008-05-07 23:22:46 +00001821
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001822 setup_return(regs, ka, &frame->retcode, frame_addr, usig,
1823 frame_addr + offsetof(struct sigframe_v2, retcode));
pbrooka8c33202008-05-07 23:22:46 +00001824
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001825 unlock_user_struct(frame, frame_addr, 1);
Peter Maydell28298c92016-07-28 16:44:48 +01001826 return;
1827sigsegv:
1828 force_sigsegv(usig);
pbrooka8c33202008-05-07 23:22:46 +00001829}
1830
pbrook624f7972008-05-31 16:11:38 +00001831static void setup_frame(int usig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01001832 target_sigset_t *set, CPUARMState *regs)
pbrooka8c33202008-05-07 23:22:46 +00001833{
1834 if (get_osversion() >= 0x020612) {
1835 setup_frame_v2(usig, ka, set, regs);
1836 } else {
1837 setup_frame_v1(usig, ka, set, regs);
1838 }
bellard43fff232003-07-09 19:31:39 +00001839}
1840
bellard579a97f2007-11-11 14:26:47 +00001841/* compare linux/arch/arm/kernel/signal.c:setup_rt_frame() */
pbrook624f7972008-05-31 16:11:38 +00001842static void setup_rt_frame_v1(int usig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05001843 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01001844 target_sigset_t *set, CPUARMState *env)
bellard43fff232003-07-09 19:31:39 +00001845{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001846 struct rt_sigframe_v1 *frame;
1847 abi_ulong frame_addr = get_sigframe(ka, env, sizeof(*frame));
1848 struct target_sigaltstack stack;
1849 int i;
1850 abi_ulong info_addr, uc_addr;
bellard43fff232003-07-09 19:31:39 +00001851
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001852 trace_user_setup_rt_frame(env, frame_addr);
1853 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
Peter Maydell28298c92016-07-28 16:44:48 +01001854 goto sigsegv;
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001855 }
bellardedf779f2004-02-22 13:40:13 +00001856
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001857 info_addr = frame_addr + offsetof(struct rt_sigframe_v1, info);
1858 __put_user(info_addr, &frame->pinfo);
1859 uc_addr = frame_addr + offsetof(struct rt_sigframe_v1, uc);
1860 __put_user(uc_addr, &frame->puc);
1861 tswap_siginfo(&frame->info, info);
bellard43fff232003-07-09 19:31:39 +00001862
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001863 /* Clear all the bits of the ucontext we don't use. */
1864 memset(&frame->uc, 0, offsetof(struct target_ucontext_v1, tuc_mcontext));
bellard43fff232003-07-09 19:31:39 +00001865
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001866 memset(&stack, 0, sizeof(stack));
1867 __put_user(target_sigaltstack_used.ss_sp, &stack.ss_sp);
1868 __put_user(target_sigaltstack_used.ss_size, &stack.ss_size);
1869 __put_user(sas_ss_flags(get_sp_from_cpustate(env)), &stack.ss_flags);
1870 memcpy(&frame->uc.tuc_stack, &stack, sizeof(stack));
thsa04e1342007-09-27 13:57:58 +00001871
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001872 setup_sigcontext(&frame->uc.tuc_mcontext, env, set->sig[0]);
1873 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
1874 __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
1875 }
bellard43fff232003-07-09 19:31:39 +00001876
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001877 setup_return(env, ka, &frame->retcode, frame_addr, usig,
1878 frame_addr + offsetof(struct rt_sigframe_v1, retcode));
pbrooka745ec62008-05-06 15:36:17 +00001879
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001880 env->regs[1] = info_addr;
1881 env->regs[2] = uc_addr;
pbrooka745ec62008-05-06 15:36:17 +00001882
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001883 unlock_user_struct(frame, frame_addr, 1);
Peter Maydell28298c92016-07-28 16:44:48 +01001884 return;
1885sigsegv:
1886 force_sigsegv(usig);
pbrooka745ec62008-05-06 15:36:17 +00001887}
1888
pbrook624f7972008-05-31 16:11:38 +00001889static void setup_rt_frame_v2(int usig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05001890 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01001891 target_sigset_t *set, CPUARMState *env)
pbrooka745ec62008-05-06 15:36:17 +00001892{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001893 struct rt_sigframe_v2 *frame;
1894 abi_ulong frame_addr = get_sigframe(ka, env, sizeof(*frame));
1895 abi_ulong info_addr, uc_addr;
pbrooka745ec62008-05-06 15:36:17 +00001896
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001897 trace_user_setup_rt_frame(env, frame_addr);
1898 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
Peter Maydell28298c92016-07-28 16:44:48 +01001899 goto sigsegv;
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001900 }
pbrooka745ec62008-05-06 15:36:17 +00001901
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001902 info_addr = frame_addr + offsetof(struct rt_sigframe_v2, info);
1903 uc_addr = frame_addr + offsetof(struct rt_sigframe_v2, uc);
1904 tswap_siginfo(&frame->info, info);
pbrooka745ec62008-05-06 15:36:17 +00001905
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001906 setup_sigframe_v2(&frame->uc, set, env);
pbrooka745ec62008-05-06 15:36:17 +00001907
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001908 setup_return(env, ka, &frame->retcode, frame_addr, usig,
1909 frame_addr + offsetof(struct rt_sigframe_v2, retcode));
pbrooka745ec62008-05-06 15:36:17 +00001910
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001911 env->regs[1] = info_addr;
1912 env->regs[2] = uc_addr;
pbrooka745ec62008-05-06 15:36:17 +00001913
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001914 unlock_user_struct(frame, frame_addr, 1);
Peter Maydell28298c92016-07-28 16:44:48 +01001915 return;
1916sigsegv:
1917 force_sigsegv(usig);
bellard43fff232003-07-09 19:31:39 +00001918}
1919
pbrook624f7972008-05-31 16:11:38 +00001920static void setup_rt_frame(int usig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05001921 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01001922 target_sigset_t *set, CPUARMState *env)
pbrooka745ec62008-05-06 15:36:17 +00001923{
1924 if (get_osversion() >= 0x020612) {
1925 setup_rt_frame_v2(usig, ka, info, set, env);
1926 } else {
1927 setup_rt_frame_v1(usig, ka, info, set, env);
1928 }
1929}
1930
bellard43fff232003-07-09 19:31:39 +00001931static int
Andreas Färber05390242012-02-25 03:37:53 +01001932restore_sigcontext(CPUARMState *env, struct target_sigcontext *sc)
bellard43fff232003-07-09 19:31:39 +00001933{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001934 int err = 0;
1935 uint32_t cpsr;
bellard43fff232003-07-09 19:31:39 +00001936
Riku Voipio1d8b5122014-04-23 10:26:05 +03001937 __get_user(env->regs[0], &sc->arm_r0);
1938 __get_user(env->regs[1], &sc->arm_r1);
1939 __get_user(env->regs[2], &sc->arm_r2);
1940 __get_user(env->regs[3], &sc->arm_r3);
1941 __get_user(env->regs[4], &sc->arm_r4);
1942 __get_user(env->regs[5], &sc->arm_r5);
1943 __get_user(env->regs[6], &sc->arm_r6);
1944 __get_user(env->regs[7], &sc->arm_r7);
1945 __get_user(env->regs[8], &sc->arm_r8);
1946 __get_user(env->regs[9], &sc->arm_r9);
1947 __get_user(env->regs[10], &sc->arm_r10);
1948 __get_user(env->regs[11], &sc->arm_fp);
1949 __get_user(env->regs[12], &sc->arm_ip);
1950 __get_user(env->regs[13], &sc->arm_sp);
1951 __get_user(env->regs[14], &sc->arm_lr);
1952 __get_user(env->regs[15], &sc->arm_pc);
bellard43fff232003-07-09 19:31:39 +00001953#ifdef TARGET_CONFIG_CPU_32
Riku Voipio1d8b5122014-04-23 10:26:05 +03001954 __get_user(cpsr, &sc->arm_cpsr);
Peter Maydell50866ba2016-02-23 15:36:43 +00001955 cpsr_write(env, cpsr, CPSR_USER | CPSR_EXEC, CPSRWriteByInstr);
bellard43fff232003-07-09 19:31:39 +00001956#endif
1957
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001958 err |= !valid_user_regs(env);
bellard43fff232003-07-09 19:31:39 +00001959
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001960 return err;
bellard43fff232003-07-09 19:31:39 +00001961}
1962
Andreas Färber05390242012-02-25 03:37:53 +01001963static long do_sigreturn_v1(CPUARMState *env)
bellard43fff232003-07-09 19:31:39 +00001964{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001965 abi_ulong frame_addr;
1966 struct sigframe_v1 *frame = NULL;
1967 target_sigset_t set;
1968 sigset_t host_set;
1969 int i;
bellard43fff232003-07-09 19:31:39 +00001970
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001971 /*
1972 * Since we stacked the signal on a 64-bit boundary,
1973 * then 'sp' should be word aligned here. If it's
1974 * not, then the user is trying to mess with us.
1975 */
1976 frame_addr = env->regs[13];
1977 trace_user_do_sigreturn(env, frame_addr);
1978 if (frame_addr & 7) {
1979 goto badframe;
1980 }
Peter Maydell978fae92013-07-29 12:00:32 +01001981
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001982 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
1983 goto badframe;
1984 }
bellard43fff232003-07-09 19:31:39 +00001985
Riku Voipiof5f601a2014-04-23 13:00:17 +03001986 __get_user(set.sig[0], &frame->sc.oldmask);
1987 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
1988 __get_user(set.sig[i], &frame->extramask[i - 1]);
1989 }
bellard43fff232003-07-09 19:31:39 +00001990
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001991 target_to_host_sigset_internal(&host_set, &set);
Peter Maydell9eede5b2016-05-27 15:51:46 +01001992 set_sigmask(&host_set);
bellard43fff232003-07-09 19:31:39 +00001993
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001994 if (restore_sigcontext(env, &frame->sc)) {
1995 goto badframe;
1996 }
bellard43fff232003-07-09 19:31:39 +00001997
1998#if 0
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001999 /* Send SIGTRAP if we're single-stepping */
2000 if (ptrace_cancel_bpt(current))
2001 send_sig(SIGTRAP, current, 1);
bellard43fff232003-07-09 19:31:39 +00002002#endif
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002003 unlock_user_struct(frame, frame_addr, 0);
Timothy E Baldwinf0267ef2016-05-12 18:47:31 +01002004 return -TARGET_QEMU_ESIGRETURN;
bellard43fff232003-07-09 19:31:39 +00002005
2006badframe:
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002007 force_sig(TARGET_SIGSEGV /* , current */);
2008 return 0;
bellard43fff232003-07-09 19:31:39 +00002009}
2010
Andreas Färber05390242012-02-25 03:37:53 +01002011static abi_ulong *restore_sigframe_v2_vfp(CPUARMState *env, abi_ulong *regspace)
Peter Maydell5f9099d2010-11-24 15:20:06 +00002012{
2013 int i;
2014 abi_ulong magic, sz;
2015 uint32_t fpscr, fpexc;
2016 struct target_vfp_sigframe *vfpframe;
2017 vfpframe = (struct target_vfp_sigframe *)regspace;
2018
2019 __get_user(magic, &vfpframe->magic);
2020 __get_user(sz, &vfpframe->size);
2021 if (magic != TARGET_VFP_MAGIC || sz != sizeof(*vfpframe)) {
2022 return 0;
2023 }
2024 for (i = 0; i < 32; i++) {
Peter Maydell005e1a02011-02-10 13:59:35 +00002025 __get_user(float64_val(env->vfp.regs[i]), &vfpframe->ufp.fpregs[i]);
Peter Maydell5f9099d2010-11-24 15:20:06 +00002026 }
2027 __get_user(fpscr, &vfpframe->ufp.fpscr);
2028 vfp_set_fpscr(env, fpscr);
2029 __get_user(fpexc, &vfpframe->ufp_exc.fpexc);
2030 /* Sanitise FPEXC: ensure VFP is enabled, FPINST2 is invalid
2031 * and the exception flag is cleared
2032 */
2033 fpexc |= (1 << 30);
2034 fpexc &= ~((1 << 31) | (1 << 28));
2035 env->vfp.xregs[ARM_VFP_FPEXC] = fpexc;
2036 __get_user(env->vfp.xregs[ARM_VFP_FPINST], &vfpframe->ufp_exc.fpinst);
2037 __get_user(env->vfp.xregs[ARM_VFP_FPINST2], &vfpframe->ufp_exc.fpinst2);
2038 return (abi_ulong*)(vfpframe + 1);
2039}
2040
Andreas Färber05390242012-02-25 03:37:53 +01002041static abi_ulong *restore_sigframe_v2_iwmmxt(CPUARMState *env,
2042 abi_ulong *regspace)
Peter Maydella59d69d2010-11-24 15:20:08 +00002043{
2044 int i;
2045 abi_ulong magic, sz;
2046 struct target_iwmmxt_sigframe *iwmmxtframe;
2047 iwmmxtframe = (struct target_iwmmxt_sigframe *)regspace;
2048
2049 __get_user(magic, &iwmmxtframe->magic);
2050 __get_user(sz, &iwmmxtframe->size);
2051 if (magic != TARGET_IWMMXT_MAGIC || sz != sizeof(*iwmmxtframe)) {
2052 return 0;
2053 }
2054 for (i = 0; i < 16; i++) {
2055 __get_user(env->iwmmxt.regs[i], &iwmmxtframe->regs[i]);
2056 }
2057 __get_user(env->vfp.xregs[ARM_IWMMXT_wCSSF], &iwmmxtframe->wcssf);
2058 __get_user(env->vfp.xregs[ARM_IWMMXT_wCASF], &iwmmxtframe->wcssf);
2059 __get_user(env->vfp.xregs[ARM_IWMMXT_wCGR0], &iwmmxtframe->wcgr0);
2060 __get_user(env->vfp.xregs[ARM_IWMMXT_wCGR1], &iwmmxtframe->wcgr1);
2061 __get_user(env->vfp.xregs[ARM_IWMMXT_wCGR2], &iwmmxtframe->wcgr2);
2062 __get_user(env->vfp.xregs[ARM_IWMMXT_wCGR3], &iwmmxtframe->wcgr3);
2063 return (abi_ulong*)(iwmmxtframe + 1);
2064}
2065
Andreas Färber05390242012-02-25 03:37:53 +01002066static int do_sigframe_return_v2(CPUARMState *env, target_ulong frame_addr,
pbrooka8c33202008-05-07 23:22:46 +00002067 struct target_ucontext_v2 *uc)
2068{
2069 sigset_t host_set;
Peter Maydell5f9099d2010-11-24 15:20:06 +00002070 abi_ulong *regspace;
pbrooka8c33202008-05-07 23:22:46 +00002071
2072 target_to_host_sigset(&host_set, &uc->tuc_sigmask);
Peter Maydell9eede5b2016-05-27 15:51:46 +01002073 set_sigmask(&host_set);
pbrooka8c33202008-05-07 23:22:46 +00002074
2075 if (restore_sigcontext(env, &uc->tuc_mcontext))
2076 return 1;
2077
Peter Maydell5f9099d2010-11-24 15:20:06 +00002078 /* Restore coprocessor signal frame */
2079 regspace = uc->tuc_regspace;
2080 if (arm_feature(env, ARM_FEATURE_VFP)) {
2081 regspace = restore_sigframe_v2_vfp(env, regspace);
2082 if (!regspace) {
2083 return 1;
2084 }
2085 }
Peter Maydella59d69d2010-11-24 15:20:08 +00002086 if (arm_feature(env, ARM_FEATURE_IWMMXT)) {
2087 regspace = restore_sigframe_v2_iwmmxt(env, regspace);
2088 if (!regspace) {
2089 return 1;
2090 }
2091 }
Peter Maydell5f9099d2010-11-24 15:20:06 +00002092
pbrooka8c33202008-05-07 23:22:46 +00002093 if (do_sigaltstack(frame_addr + offsetof(struct target_ucontext_v2, tuc_stack), 0, get_sp_from_cpustate(env)) == -EFAULT)
2094 return 1;
2095
2096#if 0
2097 /* Send SIGTRAP if we're single-stepping */
2098 if (ptrace_cancel_bpt(current))
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002099 send_sig(SIGTRAP, current, 1);
pbrooka8c33202008-05-07 23:22:46 +00002100#endif
2101
2102 return 0;
2103}
2104
Andreas Färber05390242012-02-25 03:37:53 +01002105static long do_sigreturn_v2(CPUARMState *env)
pbrooka8c33202008-05-07 23:22:46 +00002106{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002107 abi_ulong frame_addr;
2108 struct sigframe_v2 *frame = NULL;
pbrooka8c33202008-05-07 23:22:46 +00002109
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002110 /*
2111 * Since we stacked the signal on a 64-bit boundary,
2112 * then 'sp' should be word aligned here. If it's
2113 * not, then the user is trying to mess with us.
2114 */
2115 frame_addr = env->regs[13];
2116 trace_user_do_sigreturn(env, frame_addr);
2117 if (frame_addr & 7) {
2118 goto badframe;
2119 }
Peter Maydell978fae92013-07-29 12:00:32 +01002120
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002121 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
2122 goto badframe;
2123 }
pbrooka8c33202008-05-07 23:22:46 +00002124
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002125 if (do_sigframe_return_v2(env, frame_addr, &frame->uc)) {
2126 goto badframe;
2127 }
pbrooka8c33202008-05-07 23:22:46 +00002128
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002129 unlock_user_struct(frame, frame_addr, 0);
Timothy E Baldwinf0267ef2016-05-12 18:47:31 +01002130 return -TARGET_QEMU_ESIGRETURN;
pbrooka8c33202008-05-07 23:22:46 +00002131
2132badframe:
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002133 unlock_user_struct(frame, frame_addr, 0);
2134 force_sig(TARGET_SIGSEGV /* , current */);
2135 return 0;
pbrooka8c33202008-05-07 23:22:46 +00002136}
2137
Andreas Färber05390242012-02-25 03:37:53 +01002138long do_sigreturn(CPUARMState *env)
pbrooka8c33202008-05-07 23:22:46 +00002139{
2140 if (get_osversion() >= 0x020612) {
2141 return do_sigreturn_v2(env);
2142 } else {
2143 return do_sigreturn_v1(env);
2144 }
2145}
2146
Andreas Färber05390242012-02-25 03:37:53 +01002147static long do_rt_sigreturn_v1(CPUARMState *env)
bellard43fff232003-07-09 19:31:39 +00002148{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002149 abi_ulong frame_addr;
2150 struct rt_sigframe_v1 *frame = NULL;
2151 sigset_t host_set;
bellard43fff232003-07-09 19:31:39 +00002152
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002153 /*
2154 * Since we stacked the signal on a 64-bit boundary,
2155 * then 'sp' should be word aligned here. If it's
2156 * not, then the user is trying to mess with us.
2157 */
2158 frame_addr = env->regs[13];
2159 trace_user_do_rt_sigreturn(env, frame_addr);
2160 if (frame_addr & 7) {
2161 goto badframe;
2162 }
Peter Maydell978fae92013-07-29 12:00:32 +01002163
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002164 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
2165 goto badframe;
2166 }
bellard43fff232003-07-09 19:31:39 +00002167
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002168 target_to_host_sigset(&host_set, &frame->uc.tuc_sigmask);
Peter Maydell9eede5b2016-05-27 15:51:46 +01002169 set_sigmask(&host_set);
bellard43fff232003-07-09 19:31:39 +00002170
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002171 if (restore_sigcontext(env, &frame->uc.tuc_mcontext)) {
2172 goto badframe;
2173 }
bellard43fff232003-07-09 19:31:39 +00002174
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002175 if (do_sigaltstack(frame_addr + offsetof(struct rt_sigframe_v1, uc.tuc_stack), 0, get_sp_from_cpustate(env)) == -EFAULT)
2176 goto badframe;
thsa04e1342007-09-27 13:57:58 +00002177
bellard43fff232003-07-09 19:31:39 +00002178#if 0
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002179 /* Send SIGTRAP if we're single-stepping */
2180 if (ptrace_cancel_bpt(current))
2181 send_sig(SIGTRAP, current, 1);
bellard43fff232003-07-09 19:31:39 +00002182#endif
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002183 unlock_user_struct(frame, frame_addr, 0);
Timothy E Baldwinf0267ef2016-05-12 18:47:31 +01002184 return -TARGET_QEMU_ESIGRETURN;
bellard43fff232003-07-09 19:31:39 +00002185
2186badframe:
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002187 unlock_user_struct(frame, frame_addr, 0);
2188 force_sig(TARGET_SIGSEGV /* , current */);
2189 return 0;
bellard43fff232003-07-09 19:31:39 +00002190}
2191
Andreas Färber05390242012-02-25 03:37:53 +01002192static long do_rt_sigreturn_v2(CPUARMState *env)
pbrooka745ec62008-05-06 15:36:17 +00002193{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002194 abi_ulong frame_addr;
2195 struct rt_sigframe_v2 *frame = NULL;
pbrooka745ec62008-05-06 15:36:17 +00002196
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002197 /*
2198 * Since we stacked the signal on a 64-bit boundary,
2199 * then 'sp' should be word aligned here. If it's
2200 * not, then the user is trying to mess with us.
2201 */
2202 frame_addr = env->regs[13];
2203 trace_user_do_rt_sigreturn(env, frame_addr);
2204 if (frame_addr & 7) {
2205 goto badframe;
2206 }
Peter Maydell978fae92013-07-29 12:00:32 +01002207
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002208 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
2209 goto badframe;
2210 }
pbrooka745ec62008-05-06 15:36:17 +00002211
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002212 if (do_sigframe_return_v2(env, frame_addr, &frame->uc)) {
2213 goto badframe;
2214 }
pbrooka745ec62008-05-06 15:36:17 +00002215
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002216 unlock_user_struct(frame, frame_addr, 0);
Timothy E Baldwinf0267ef2016-05-12 18:47:31 +01002217 return -TARGET_QEMU_ESIGRETURN;
pbrooka745ec62008-05-06 15:36:17 +00002218
2219badframe:
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002220 unlock_user_struct(frame, frame_addr, 0);
2221 force_sig(TARGET_SIGSEGV /* , current */);
2222 return 0;
pbrooka745ec62008-05-06 15:36:17 +00002223}
2224
Andreas Färber05390242012-02-25 03:37:53 +01002225long do_rt_sigreturn(CPUARMState *env)
pbrooka745ec62008-05-06 15:36:17 +00002226{
2227 if (get_osversion() >= 0x020612) {
2228 return do_rt_sigreturn_v2(env);
2229 } else {
2230 return do_rt_sigreturn_v1(env);
2231 }
2232}
2233
bellard6d5e2162004-09-30 22:04:13 +00002234#elif defined(TARGET_SPARC)
bellard80a9d032005-01-03 23:31:27 +00002235
bellard6d5e2162004-09-30 22:04:13 +00002236#define __SUNOS_MAXWIN 31
2237
2238/* This is what SunOS does, so shall I. */
2239struct target_sigcontext {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002240 abi_ulong sigc_onstack; /* state to restore */
bellard6d5e2162004-09-30 22:04:13 +00002241
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002242 abi_ulong sigc_mask; /* sigmask to restore */
2243 abi_ulong sigc_sp; /* stack pointer */
2244 abi_ulong sigc_pc; /* program counter */
2245 abi_ulong sigc_npc; /* next program counter */
2246 abi_ulong sigc_psr; /* for condition codes etc */
2247 abi_ulong sigc_g1; /* User uses these two registers */
2248 abi_ulong sigc_o0; /* within the trampoline code. */
bellard6d5e2162004-09-30 22:04:13 +00002249
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002250 /* Now comes information regarding the users window set
bellard6d5e2162004-09-30 22:04:13 +00002251 * at the time of the signal.
2252 */
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002253 abi_ulong sigc_oswins; /* outstanding windows */
bellard6d5e2162004-09-30 22:04:13 +00002254
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002255 /* stack ptrs for each regwin buf */
2256 char *sigc_spbuf[__SUNOS_MAXWIN];
bellard6d5e2162004-09-30 22:04:13 +00002257
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002258 /* Windows to restore after signal */
2259 struct {
2260 abi_ulong locals[8];
2261 abi_ulong ins[8];
2262 } sigc_wbuf[__SUNOS_MAXWIN];
bellard6d5e2162004-09-30 22:04:13 +00002263};
2264/* A Sparc stack frame */
2265struct sparc_stackf {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002266 abi_ulong locals[8];
2267 abi_ulong ins[8];
2268 /* It's simpler to treat fp and callers_pc as elements of ins[]
Peter Maydelle321c342011-02-01 15:54:52 +00002269 * since we never need to access them ourselves.
2270 */
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002271 char *structptr;
2272 abi_ulong xargs[6];
2273 abi_ulong xxargs[1];
bellard6d5e2162004-09-30 22:04:13 +00002274};
2275
2276typedef struct {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002277 struct {
2278 abi_ulong psr;
2279 abi_ulong pc;
2280 abi_ulong npc;
2281 abi_ulong y;
2282 abi_ulong u_regs[16]; /* globals and ins */
2283 } si_regs;
2284 int si_mask;
bellard6d5e2162004-09-30 22:04:13 +00002285} __siginfo_t;
2286
2287typedef struct {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002288 abi_ulong si_float_regs[32];
2289 unsigned long si_fsr;
2290 unsigned long si_fpqdepth;
2291 struct {
2292 unsigned long *insn_addr;
2293 unsigned long insn;
2294 } si_fpqueue [16];
Anthony Liguoric227f092009-10-01 16:12:16 -05002295} qemu_siginfo_fpu_t;
bellard6d5e2162004-09-30 22:04:13 +00002296
2297
2298struct target_signal_frame {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002299 struct sparc_stackf ss;
2300 __siginfo_t info;
2301 abi_ulong fpu_save;
2302 abi_ulong insns[2] __attribute__ ((aligned (8)));
2303 abi_ulong extramask[TARGET_NSIG_WORDS - 1];
2304 abi_ulong extra_size; /* Should be 0 */
2305 qemu_siginfo_fpu_t fpu_state;
bellard6d5e2162004-09-30 22:04:13 +00002306};
2307struct target_rt_signal_frame {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002308 struct sparc_stackf ss;
2309 siginfo_t info;
2310 abi_ulong regs[20];
2311 sigset_t mask;
2312 abi_ulong fpu_save;
2313 unsigned int insns[2];
2314 stack_t stack;
2315 unsigned int extra_size; /* Should be 0 */
2316 qemu_siginfo_fpu_t fpu_state;
bellard6d5e2162004-09-30 22:04:13 +00002317};
2318
bellarde80cfcf2004-12-19 23:18:01 +00002319#define UREG_O0 16
2320#define UREG_O6 22
2321#define UREG_I0 0
2322#define UREG_I1 1
2323#define UREG_I2 2
blueswir15bfb56b2007-10-05 17:01:51 +00002324#define UREG_I3 3
2325#define UREG_I4 4
2326#define UREG_I5 5
bellarde80cfcf2004-12-19 23:18:01 +00002327#define UREG_I6 6
2328#define UREG_I7 7
2329#define UREG_L0 8
bellard6d5e2162004-09-30 22:04:13 +00002330#define UREG_FP UREG_I6
2331#define UREG_SP UREG_O6
2332
pbrook624f7972008-05-31 16:11:38 +00002333static inline abi_ulong get_sigframe(struct target_sigaction *sa,
Andreas Färber05390242012-02-25 03:37:53 +01002334 CPUSPARCState *env,
2335 unsigned long framesize)
bellard6d5e2162004-09-30 22:04:13 +00002336{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002337 abi_ulong sp;
bellard6d5e2162004-09-30 22:04:13 +00002338
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002339 sp = env->regwptr[UREG_FP];
bellard6d5e2162004-09-30 22:04:13 +00002340
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002341 /* This is the X/Open sanctioned signal stack switching. */
2342 if (sa->sa_flags & TARGET_SA_ONSTACK) {
2343 if (!on_sig_stack(sp)
2344 && !((target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size) & 7)) {
2345 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
2346 }
2347 }
2348 return sp - framesize;
bellard6d5e2162004-09-30 22:04:13 +00002349}
2350
2351static int
Andreas Färber05390242012-02-25 03:37:53 +01002352setup___siginfo(__siginfo_t *si, CPUSPARCState *env, abi_ulong mask)
bellard6d5e2162004-09-30 22:04:13 +00002353{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002354 int err = 0, i;
bellard6d5e2162004-09-30 22:04:13 +00002355
Riku Voipio1d8b5122014-04-23 10:26:05 +03002356 __put_user(env->psr, &si->si_regs.psr);
2357 __put_user(env->pc, &si->si_regs.pc);
2358 __put_user(env->npc, &si->si_regs.npc);
2359 __put_user(env->y, &si->si_regs.y);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002360 for (i=0; i < 8; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002361 __put_user(env->gregs[i], &si->si_regs.u_regs[i]);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002362 }
2363 for (i=0; i < 8; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002364 __put_user(env->regwptr[UREG_I0 + i], &si->si_regs.u_regs[i+8]);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002365 }
Riku Voipio1d8b5122014-04-23 10:26:05 +03002366 __put_user(mask, &si->si_mask);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002367 return err;
bellard6d5e2162004-09-30 22:04:13 +00002368}
bellarde80cfcf2004-12-19 23:18:01 +00002369
bellard80a9d032005-01-03 23:31:27 +00002370#if 0
bellard6d5e2162004-09-30 22:04:13 +00002371static int
2372setup_sigcontext(struct target_sigcontext *sc, /*struct _fpstate *fpstate,*/
Andreas Färber05390242012-02-25 03:37:53 +01002373 CPUSPARCState *env, unsigned long mask)
bellard6d5e2162004-09-30 22:04:13 +00002374{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002375 int err = 0;
bellard6d5e2162004-09-30 22:04:13 +00002376
Riku Voipio1d8b5122014-04-23 10:26:05 +03002377 __put_user(mask, &sc->sigc_mask);
2378 __put_user(env->regwptr[UREG_SP], &sc->sigc_sp);
2379 __put_user(env->pc, &sc->sigc_pc);
2380 __put_user(env->npc, &sc->sigc_npc);
2381 __put_user(env->psr, &sc->sigc_psr);
2382 __put_user(env->gregs[1], &sc->sigc_g1);
2383 __put_user(env->regwptr[UREG_O0], &sc->sigc_o0);
bellard6d5e2162004-09-30 22:04:13 +00002384
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002385 return err;
bellard6d5e2162004-09-30 22:04:13 +00002386}
bellard80a9d032005-01-03 23:31:27 +00002387#endif
bellard6d5e2162004-09-30 22:04:13 +00002388#define NF_ALIGNEDSZ (((sizeof(struct target_signal_frame) + 7) & (~7)))
2389
pbrook624f7972008-05-31 16:11:38 +00002390static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01002391 target_sigset_t *set, CPUSPARCState *env)
bellard6d5e2162004-09-30 22:04:13 +00002392{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002393 abi_ulong sf_addr;
2394 struct target_signal_frame *sf;
2395 int sigframe_size, err, i;
bellard6d5e2162004-09-30 22:04:13 +00002396
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002397 /* 1. Make sure everything is clean */
2398 //synchronize_user_stack();
bellard6d5e2162004-09-30 22:04:13 +00002399
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002400 sigframe_size = NF_ALIGNEDSZ;
2401 sf_addr = get_sigframe(ka, env, sigframe_size);
2402 trace_user_setup_frame(env, sf_addr);
bellard6d5e2162004-09-30 22:04:13 +00002403
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002404 sf = lock_user(VERIFY_WRITE, sf_addr,
2405 sizeof(struct target_signal_frame), 0);
2406 if (!sf) {
2407 goto sigsegv;
2408 }
bellard6d5e2162004-09-30 22:04:13 +00002409#if 0
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002410 if (invalid_frame_pointer(sf, sigframe_size))
2411 goto sigill_and_return;
bellard6d5e2162004-09-30 22:04:13 +00002412#endif
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002413 /* 2. Save the current process state */
2414 err = setup___siginfo(&sf->info, env, set->sig[0]);
Riku Voipio1d8b5122014-04-23 10:26:05 +03002415 __put_user(0, &sf->extra_size);
bellard6d5e2162004-09-30 22:04:13 +00002416
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002417 //save_fpu_state(regs, &sf->fpu_state);
2418 //__put_user(&sf->fpu_state, &sf->fpu_save);
bellard6d5e2162004-09-30 22:04:13 +00002419
Riku Voipio1d8b5122014-04-23 10:26:05 +03002420 __put_user(set->sig[0], &sf->info.si_mask);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002421 for (i = 0; i < TARGET_NSIG_WORDS - 1; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002422 __put_user(set->sig[i + 1], &sf->extramask[i]);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002423 }
bellard6d5e2162004-09-30 22:04:13 +00002424
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002425 for (i = 0; i < 8; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002426 __put_user(env->regwptr[i + UREG_L0], &sf->ss.locals[i]);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002427 }
2428 for (i = 0; i < 8; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002429 __put_user(env->regwptr[i + UREG_I0], &sf->ss.ins[i]);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002430 }
2431 if (err)
2432 goto sigsegv;
bellard6d5e2162004-09-30 22:04:13 +00002433
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002434 /* 3. signal handler back-trampoline and parameters */
2435 env->regwptr[UREG_FP] = sf_addr;
2436 env->regwptr[UREG_I0] = sig;
2437 env->regwptr[UREG_I1] = sf_addr +
2438 offsetof(struct target_signal_frame, info);
2439 env->regwptr[UREG_I2] = sf_addr +
2440 offsetof(struct target_signal_frame, info);
bellard6d5e2162004-09-30 22:04:13 +00002441
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002442 /* 4. signal handler */
2443 env->pc = ka->_sa_handler;
2444 env->npc = (env->pc + 4);
2445 /* 5. return to kernel instructions */
2446 if (ka->sa_restorer) {
2447 env->regwptr[UREG_I7] = ka->sa_restorer;
2448 } else {
2449 uint32_t val32;
bellard459a4012007-11-11 19:45:10 +00002450
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002451 env->regwptr[UREG_I7] = sf_addr +
2452 offsetof(struct target_signal_frame, insns) - 2 * 4;
bellard6d5e2162004-09-30 22:04:13 +00002453
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002454 /* mov __NR_sigreturn, %g1 */
2455 val32 = 0x821020d8;
Riku Voipio1d8b5122014-04-23 10:26:05 +03002456 __put_user(val32, &sf->insns[0]);
bellard6d5e2162004-09-30 22:04:13 +00002457
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002458 /* t 0x10 */
2459 val32 = 0x91d02010;
Riku Voipio1d8b5122014-04-23 10:26:05 +03002460 __put_user(val32, &sf->insns[1]);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002461 if (err)
2462 goto sigsegv;
bellard6d5e2162004-09-30 22:04:13 +00002463
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002464 /* Flush instruction space. */
2465 // flush_sig_insns(current->mm, (unsigned long) &(sf->insns[0]));
2466 // tb_flush(env);
2467 }
2468 unlock_user(sf, sf_addr, sizeof(struct target_signal_frame));
2469 return;
bellard459a4012007-11-11 19:45:10 +00002470#if 0
2471sigill_and_return:
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002472 force_sig(TARGET_SIGILL);
bellard459a4012007-11-11 19:45:10 +00002473#endif
bellard6d5e2162004-09-30 22:04:13 +00002474sigsegv:
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002475 unlock_user(sf, sf_addr, sizeof(struct target_signal_frame));
Peter Maydell09391662016-07-28 16:44:47 +01002476 force_sigsegv(sig);
bellard6d5e2162004-09-30 22:04:13 +00002477}
bellard6d5e2162004-09-30 22:04:13 +00002478
pbrook624f7972008-05-31 16:11:38 +00002479static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05002480 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01002481 target_sigset_t *set, CPUSPARCState *env)
bellard6d5e2162004-09-30 22:04:13 +00002482{
2483 fprintf(stderr, "setup_rt_frame: not implemented\n");
2484}
2485
Andreas Färber05390242012-02-25 03:37:53 +01002486long do_sigreturn(CPUSPARCState *env)
bellard6d5e2162004-09-30 22:04:13 +00002487{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002488 abi_ulong sf_addr;
2489 struct target_signal_frame *sf;
2490 uint32_t up_psr, pc, npc;
2491 target_sigset_t set;
2492 sigset_t host_set;
2493 int err=0, i;
bellard6d5e2162004-09-30 22:04:13 +00002494
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002495 sf_addr = env->regwptr[UREG_FP];
2496 trace_user_do_sigreturn(env, sf_addr);
2497 if (!lock_user_struct(VERIFY_READ, sf, sf_addr, 1)) {
2498 goto segv_and_exit;
2499 }
bellard6d5e2162004-09-30 22:04:13 +00002500
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002501 /* 1. Make sure we are not getting garbage from the user */
bellard6d5e2162004-09-30 22:04:13 +00002502
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002503 if (sf_addr & 3)
2504 goto segv_and_exit;
bellard6d5e2162004-09-30 22:04:13 +00002505
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002506 __get_user(pc, &sf->info.si_regs.pc);
2507 __get_user(npc, &sf->info.si_regs.npc);
bellard6d5e2162004-09-30 22:04:13 +00002508
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002509 if ((pc | npc) & 3) {
2510 goto segv_and_exit;
2511 }
bellard6d5e2162004-09-30 22:04:13 +00002512
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002513 /* 2. Restore the state */
2514 __get_user(up_psr, &sf->info.si_regs.psr);
bellarde80cfcf2004-12-19 23:18:01 +00002515
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002516 /* User can only change condition codes and FPU enabling in %psr. */
2517 env->psr = (up_psr & (PSR_ICC /* | PSR_EF */))
2518 | (env->psr & ~(PSR_ICC /* | PSR_EF */));
bellarda315a142005-01-30 22:59:18 +00002519
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002520 env->pc = pc;
2521 env->npc = npc;
2522 __get_user(env->y, &sf->info.si_regs.y);
2523 for (i=0; i < 8; i++) {
2524 __get_user(env->gregs[i], &sf->info.si_regs.u_regs[i]);
2525 }
2526 for (i=0; i < 8; i++) {
2527 __get_user(env->regwptr[i + UREG_I0], &sf->info.si_regs.u_regs[i+8]);
2528 }
bellard6d5e2162004-09-30 22:04:13 +00002529
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002530 /* FIXME: implement FPU save/restore:
Peter Maydell2aec3a22011-06-16 17:37:14 +01002531 * __get_user(fpu_save, &sf->fpu_save);
2532 * if (fpu_save)
2533 * err |= restore_fpu_state(env, fpu_save);
2534 */
bellard6d5e2162004-09-30 22:04:13 +00002535
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002536 /* This is pretty much atomic, no amount locking would prevent
bellard6d5e2162004-09-30 22:04:13 +00002537 * the races which exist anyways.
2538 */
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002539 __get_user(set.sig[0], &sf->info.si_mask);
2540 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
2541 __get_user(set.sig[i], &sf->extramask[i - 1]);
2542 }
bellarde80cfcf2004-12-19 23:18:01 +00002543
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002544 target_to_host_sigset_internal(&host_set, &set);
Peter Maydell9eede5b2016-05-27 15:51:46 +01002545 set_sigmask(&host_set);
bellard6d5e2162004-09-30 22:04:13 +00002546
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002547 if (err) {
2548 goto segv_and_exit;
2549 }
2550 unlock_user_struct(sf, sf_addr, 0);
Timothy E Baldwinc0bea682016-05-12 18:47:34 +01002551 return -TARGET_QEMU_ESIGRETURN;
bellard6d5e2162004-09-30 22:04:13 +00002552
2553segv_and_exit:
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002554 unlock_user_struct(sf, sf_addr, 0);
2555 force_sig(TARGET_SIGSEGV);
bellard6d5e2162004-09-30 22:04:13 +00002556}
2557
Andreas Färber05390242012-02-25 03:37:53 +01002558long do_rt_sigreturn(CPUSPARCState *env)
bellard6d5e2162004-09-30 22:04:13 +00002559{
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01002560 trace_user_do_rt_sigreturn(env, 0);
bellard6d5e2162004-09-30 22:04:13 +00002561 fprintf(stderr, "do_rt_sigreturn: not implemented\n");
bellardf8b0aa22007-11-11 23:03:42 +00002562 return -TARGET_ENOSYS;
bellard6d5e2162004-09-30 22:04:13 +00002563}
2564
bellard459a4012007-11-11 19:45:10 +00002565#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
blueswir15bfb56b2007-10-05 17:01:51 +00002566#define MC_TSTATE 0
2567#define MC_PC 1
2568#define MC_NPC 2
2569#define MC_Y 3
2570#define MC_G1 4
2571#define MC_G2 5
2572#define MC_G3 6
2573#define MC_G4 7
2574#define MC_G5 8
2575#define MC_G6 9
2576#define MC_G7 10
2577#define MC_O0 11
2578#define MC_O1 12
2579#define MC_O2 13
2580#define MC_O3 14
2581#define MC_O4 15
2582#define MC_O5 16
2583#define MC_O6 17
2584#define MC_O7 18
2585#define MC_NGREG 19
2586
Anthony Liguoric227f092009-10-01 16:12:16 -05002587typedef abi_ulong target_mc_greg_t;
2588typedef target_mc_greg_t target_mc_gregset_t[MC_NGREG];
blueswir15bfb56b2007-10-05 17:01:51 +00002589
2590struct target_mc_fq {
blueswir1992f48a2007-10-14 16:27:31 +00002591 abi_ulong *mcfq_addr;
blueswir15bfb56b2007-10-05 17:01:51 +00002592 uint32_t mcfq_insn;
2593};
2594
2595struct target_mc_fpu {
2596 union {
2597 uint32_t sregs[32];
2598 uint64_t dregs[32];
2599 //uint128_t qregs[16];
2600 } mcfpu_fregs;
blueswir1992f48a2007-10-14 16:27:31 +00002601 abi_ulong mcfpu_fsr;
2602 abi_ulong mcfpu_fprs;
2603 abi_ulong mcfpu_gsr;
blueswir15bfb56b2007-10-05 17:01:51 +00002604 struct target_mc_fq *mcfpu_fq;
2605 unsigned char mcfpu_qcnt;
2606 unsigned char mcfpu_qentsz;
2607 unsigned char mcfpu_enab;
2608};
Anthony Liguoric227f092009-10-01 16:12:16 -05002609typedef struct target_mc_fpu target_mc_fpu_t;
blueswir15bfb56b2007-10-05 17:01:51 +00002610
2611typedef struct {
Anthony Liguoric227f092009-10-01 16:12:16 -05002612 target_mc_gregset_t mc_gregs;
2613 target_mc_greg_t mc_fp;
2614 target_mc_greg_t mc_i7;
2615 target_mc_fpu_t mc_fpregs;
2616} target_mcontext_t;
blueswir15bfb56b2007-10-05 17:01:51 +00002617
2618struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02002619 struct target_ucontext *tuc_link;
2620 abi_ulong tuc_flags;
2621 target_sigset_t tuc_sigmask;
2622 target_mcontext_t tuc_mcontext;
blueswir15bfb56b2007-10-05 17:01:51 +00002623};
2624
2625/* A V9 register window */
2626struct target_reg_window {
blueswir1992f48a2007-10-14 16:27:31 +00002627 abi_ulong locals[8];
2628 abi_ulong ins[8];
blueswir15bfb56b2007-10-05 17:01:51 +00002629};
2630
2631#define TARGET_STACK_BIAS 2047
2632
2633/* {set, get}context() needed for 64-bit SparcLinux userland. */
2634void sparc64_set_context(CPUSPARCState *env)
2635{
bellard459a4012007-11-11 19:45:10 +00002636 abi_ulong ucp_addr;
2637 struct target_ucontext *ucp;
Anthony Liguoric227f092009-10-01 16:12:16 -05002638 target_mc_gregset_t *grp;
blueswir1992f48a2007-10-14 16:27:31 +00002639 abi_ulong pc, npc, tstate;
bellard459a4012007-11-11 19:45:10 +00002640 abi_ulong fp, i7, w_addr;
blueswir15bfb56b2007-10-05 17:01:51 +00002641 unsigned int i;
blueswir15bfb56b2007-10-05 17:01:51 +00002642
bellard459a4012007-11-11 19:45:10 +00002643 ucp_addr = env->regwptr[UREG_I0];
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002644 if (!lock_user_struct(VERIFY_READ, ucp, ucp_addr, 1)) {
bellard459a4012007-11-11 19:45:10 +00002645 goto do_sigsegv;
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002646 }
Aurelien Jarno60e99242010-03-29 02:12:51 +02002647 grp = &ucp->tuc_mcontext.mc_gregs;
Riku Voipio1d8b5122014-04-23 10:26:05 +03002648 __get_user(pc, &((*grp)[MC_PC]));
2649 __get_user(npc, &((*grp)[MC_NPC]));
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002650 if ((pc | npc) & 3) {
blueswir15bfb56b2007-10-05 17:01:51 +00002651 goto do_sigsegv;
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002652 }
blueswir15bfb56b2007-10-05 17:01:51 +00002653 if (env->regwptr[UREG_I1]) {
Anthony Liguoric227f092009-10-01 16:12:16 -05002654 target_sigset_t target_set;
blueswir15bfb56b2007-10-05 17:01:51 +00002655 sigset_t set;
2656
2657 if (TARGET_NSIG_WORDS == 1) {
Riku Voipiobe3ef5c2014-04-23 14:02:36 +03002658 __get_user(target_set.sig[0], &ucp->tuc_sigmask.sig[0]);
blueswir15bfb56b2007-10-05 17:01:51 +00002659 } else {
bellard459a4012007-11-11 19:45:10 +00002660 abi_ulong *src, *dst;
Aurelien Jarno60e99242010-03-29 02:12:51 +02002661 src = ucp->tuc_sigmask.sig;
bellard459a4012007-11-11 19:45:10 +00002662 dst = target_set.sig;
Stefan Weil0d9e61c2013-12-07 14:48:08 +01002663 for (i = 0; i < TARGET_NSIG_WORDS; i++, dst++, src++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002664 __get_user(*dst, src);
Stefan Weil0d9e61c2013-12-07 14:48:08 +01002665 }
blueswir15bfb56b2007-10-05 17:01:51 +00002666 }
2667 target_to_host_sigset_internal(&set, &target_set);
Peter Maydell9eede5b2016-05-27 15:51:46 +01002668 set_sigmask(&set);
blueswir15bfb56b2007-10-05 17:01:51 +00002669 }
2670 env->pc = pc;
2671 env->npc = npc;
Riku Voipio1d8b5122014-04-23 10:26:05 +03002672 __get_user(env->y, &((*grp)[MC_Y]));
2673 __get_user(tstate, &((*grp)[MC_TSTATE]));
blueswir15bfb56b2007-10-05 17:01:51 +00002674 env->asi = (tstate >> 24) & 0xff;
Blue Swirl5a834bb2010-05-09 20:19:04 +00002675 cpu_put_ccr(env, tstate >> 32);
2676 cpu_put_cwp64(env, tstate & 0x1f);
Riku Voipio1d8b5122014-04-23 10:26:05 +03002677 __get_user(env->gregs[1], (&(*grp)[MC_G1]));
2678 __get_user(env->gregs[2], (&(*grp)[MC_G2]));
2679 __get_user(env->gregs[3], (&(*grp)[MC_G3]));
2680 __get_user(env->gregs[4], (&(*grp)[MC_G4]));
2681 __get_user(env->gregs[5], (&(*grp)[MC_G5]));
2682 __get_user(env->gregs[6], (&(*grp)[MC_G6]));
2683 __get_user(env->gregs[7], (&(*grp)[MC_G7]));
2684 __get_user(env->regwptr[UREG_I0], (&(*grp)[MC_O0]));
2685 __get_user(env->regwptr[UREG_I1], (&(*grp)[MC_O1]));
2686 __get_user(env->regwptr[UREG_I2], (&(*grp)[MC_O2]));
2687 __get_user(env->regwptr[UREG_I3], (&(*grp)[MC_O3]));
2688 __get_user(env->regwptr[UREG_I4], (&(*grp)[MC_O4]));
2689 __get_user(env->regwptr[UREG_I5], (&(*grp)[MC_O5]));
2690 __get_user(env->regwptr[UREG_I6], (&(*grp)[MC_O6]));
2691 __get_user(env->regwptr[UREG_I7], (&(*grp)[MC_O7]));
blueswir15bfb56b2007-10-05 17:01:51 +00002692
Riku Voipio1d8b5122014-04-23 10:26:05 +03002693 __get_user(fp, &(ucp->tuc_mcontext.mc_fp));
2694 __get_user(i7, &(ucp->tuc_mcontext.mc_i7));
blueswir15bfb56b2007-10-05 17:01:51 +00002695
bellard459a4012007-11-11 19:45:10 +00002696 w_addr = TARGET_STACK_BIAS+env->regwptr[UREG_I6];
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002697 if (put_user(fp, w_addr + offsetof(struct target_reg_window, ins[6]),
2698 abi_ulong) != 0) {
bellard459a4012007-11-11 19:45:10 +00002699 goto do_sigsegv;
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002700 }
2701 if (put_user(i7, w_addr + offsetof(struct target_reg_window, ins[7]),
2702 abi_ulong) != 0) {
bellard459a4012007-11-11 19:45:10 +00002703 goto do_sigsegv;
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002704 }
Peter Maydellc7b016b2011-06-16 17:37:15 +01002705 /* FIXME this does not match how the kernel handles the FPU in
2706 * its sparc64_set_context implementation. In particular the FPU
2707 * is only restored if fenab is non-zero in:
2708 * __get_user(fenab, &(ucp->tuc_mcontext.mc_fpregs.mcfpu_enab));
2709 */
Riku Voipiobe3ef5c2014-04-23 14:02:36 +03002710 __get_user(env->fprs, &(ucp->tuc_mcontext.mc_fpregs.mcfpu_fprs));
bellard459a4012007-11-11 19:45:10 +00002711 {
Richard Henderson30038fd2011-10-17 10:42:49 -07002712 uint32_t *src = ucp->tuc_mcontext.mc_fpregs.mcfpu_fregs.sregs;
2713 for (i = 0; i < 64; i++, src++) {
2714 if (i & 1) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002715 __get_user(env->fpr[i/2].l.lower, src);
Richard Henderson30038fd2011-10-17 10:42:49 -07002716 } else {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002717 __get_user(env->fpr[i/2].l.upper, src);
Richard Henderson30038fd2011-10-17 10:42:49 -07002718 }
2719 }
bellard459a4012007-11-11 19:45:10 +00002720 }
Riku Voipio1d8b5122014-04-23 10:26:05 +03002721 __get_user(env->fsr,
2722 &(ucp->tuc_mcontext.mc_fpregs.mcfpu_fsr));
2723 __get_user(env->gsr,
2724 &(ucp->tuc_mcontext.mc_fpregs.mcfpu_gsr));
bellard459a4012007-11-11 19:45:10 +00002725 unlock_user_struct(ucp, ucp_addr, 0);
blueswir15bfb56b2007-10-05 17:01:51 +00002726 return;
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002727do_sigsegv:
bellard459a4012007-11-11 19:45:10 +00002728 unlock_user_struct(ucp, ucp_addr, 0);
Riku Voipio66393fb2009-12-04 15:16:32 +02002729 force_sig(TARGET_SIGSEGV);
blueswir15bfb56b2007-10-05 17:01:51 +00002730}
2731
2732void sparc64_get_context(CPUSPARCState *env)
2733{
bellard459a4012007-11-11 19:45:10 +00002734 abi_ulong ucp_addr;
2735 struct target_ucontext *ucp;
Anthony Liguoric227f092009-10-01 16:12:16 -05002736 target_mc_gregset_t *grp;
2737 target_mcontext_t *mcp;
bellard459a4012007-11-11 19:45:10 +00002738 abi_ulong fp, i7, w_addr;
blueswir15bfb56b2007-10-05 17:01:51 +00002739 int err;
2740 unsigned int i;
Anthony Liguoric227f092009-10-01 16:12:16 -05002741 target_sigset_t target_set;
blueswir15bfb56b2007-10-05 17:01:51 +00002742 sigset_t set;
2743
bellard459a4012007-11-11 19:45:10 +00002744 ucp_addr = env->regwptr[UREG_I0];
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002745 if (!lock_user_struct(VERIFY_WRITE, ucp, ucp_addr, 0)) {
bellard459a4012007-11-11 19:45:10 +00002746 goto do_sigsegv;
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002747 }
bellard459a4012007-11-11 19:45:10 +00002748
Aurelien Jarno60e99242010-03-29 02:12:51 +02002749 mcp = &ucp->tuc_mcontext;
blueswir15bfb56b2007-10-05 17:01:51 +00002750 grp = &mcp->mc_gregs;
2751
2752 /* Skip over the trap instruction, first. */
2753 env->pc = env->npc;
2754 env->npc += 4;
2755
Peter Maydell3d3efba2016-05-27 15:51:49 +01002756 /* If we're only reading the signal mask then do_sigprocmask()
2757 * is guaranteed not to fail, which is important because we don't
2758 * have any way to signal a failure or restart this operation since
2759 * this is not a normal syscall.
2760 */
2761 err = do_sigprocmask(0, NULL, &set);
2762 assert(err == 0);
blueswir15bfb56b2007-10-05 17:01:51 +00002763 host_to_target_sigset_internal(&target_set, &set);
bellard459a4012007-11-11 19:45:10 +00002764 if (TARGET_NSIG_WORDS == 1) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002765 __put_user(target_set.sig[0],
2766 (abi_ulong *)&ucp->tuc_sigmask);
bellard459a4012007-11-11 19:45:10 +00002767 } else {
2768 abi_ulong *src, *dst;
2769 src = target_set.sig;
Aurelien Jarno60e99242010-03-29 02:12:51 +02002770 dst = ucp->tuc_sigmask.sig;
Stefan Weil0d9e61c2013-12-07 14:48:08 +01002771 for (i = 0; i < TARGET_NSIG_WORDS; i++, dst++, src++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002772 __put_user(*src, dst);
Stefan Weil0d9e61c2013-12-07 14:48:08 +01002773 }
blueswir15bfb56b2007-10-05 17:01:51 +00002774 if (err)
2775 goto do_sigsegv;
2776 }
2777
bellard459a4012007-11-11 19:45:10 +00002778 /* XXX: tstate must be saved properly */
Riku Voipio1d8b5122014-04-23 10:26:05 +03002779 // __put_user(env->tstate, &((*grp)[MC_TSTATE]));
2780 __put_user(env->pc, &((*grp)[MC_PC]));
2781 __put_user(env->npc, &((*grp)[MC_NPC]));
2782 __put_user(env->y, &((*grp)[MC_Y]));
2783 __put_user(env->gregs[1], &((*grp)[MC_G1]));
2784 __put_user(env->gregs[2], &((*grp)[MC_G2]));
2785 __put_user(env->gregs[3], &((*grp)[MC_G3]));
2786 __put_user(env->gregs[4], &((*grp)[MC_G4]));
2787 __put_user(env->gregs[5], &((*grp)[MC_G5]));
2788 __put_user(env->gregs[6], &((*grp)[MC_G6]));
2789 __put_user(env->gregs[7], &((*grp)[MC_G7]));
2790 __put_user(env->regwptr[UREG_I0], &((*grp)[MC_O0]));
2791 __put_user(env->regwptr[UREG_I1], &((*grp)[MC_O1]));
2792 __put_user(env->regwptr[UREG_I2], &((*grp)[MC_O2]));
2793 __put_user(env->regwptr[UREG_I3], &((*grp)[MC_O3]));
2794 __put_user(env->regwptr[UREG_I4], &((*grp)[MC_O4]));
2795 __put_user(env->regwptr[UREG_I5], &((*grp)[MC_O5]));
2796 __put_user(env->regwptr[UREG_I6], &((*grp)[MC_O6]));
2797 __put_user(env->regwptr[UREG_I7], &((*grp)[MC_O7]));
blueswir15bfb56b2007-10-05 17:01:51 +00002798
bellard459a4012007-11-11 19:45:10 +00002799 w_addr = TARGET_STACK_BIAS+env->regwptr[UREG_I6];
2800 fp = i7 = 0;
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002801 if (get_user(fp, w_addr + offsetof(struct target_reg_window, ins[6]),
2802 abi_ulong) != 0) {
bellard459a4012007-11-11 19:45:10 +00002803 goto do_sigsegv;
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002804 }
2805 if (get_user(i7, w_addr + offsetof(struct target_reg_window, ins[7]),
2806 abi_ulong) != 0) {
bellard459a4012007-11-11 19:45:10 +00002807 goto do_sigsegv;
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002808 }
Riku Voipio1d8b5122014-04-23 10:26:05 +03002809 __put_user(fp, &(mcp->mc_fp));
2810 __put_user(i7, &(mcp->mc_i7));
blueswir15bfb56b2007-10-05 17:01:51 +00002811
bellard459a4012007-11-11 19:45:10 +00002812 {
Richard Henderson30038fd2011-10-17 10:42:49 -07002813 uint32_t *dst = ucp->tuc_mcontext.mc_fpregs.mcfpu_fregs.sregs;
2814 for (i = 0; i < 64; i++, dst++) {
2815 if (i & 1) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002816 __put_user(env->fpr[i/2].l.lower, dst);
Richard Henderson30038fd2011-10-17 10:42:49 -07002817 } else {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002818 __put_user(env->fpr[i/2].l.upper, dst);
Richard Henderson30038fd2011-10-17 10:42:49 -07002819 }
2820 }
bellard459a4012007-11-11 19:45:10 +00002821 }
Riku Voipio1d8b5122014-04-23 10:26:05 +03002822 __put_user(env->fsr, &(mcp->mc_fpregs.mcfpu_fsr));
2823 __put_user(env->gsr, &(mcp->mc_fpregs.mcfpu_gsr));
2824 __put_user(env->fprs, &(mcp->mc_fpregs.mcfpu_fprs));
blueswir15bfb56b2007-10-05 17:01:51 +00002825
2826 if (err)
2827 goto do_sigsegv;
bellard459a4012007-11-11 19:45:10 +00002828 unlock_user_struct(ucp, ucp_addr, 1);
blueswir15bfb56b2007-10-05 17:01:51 +00002829 return;
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002830do_sigsegv:
bellard459a4012007-11-11 19:45:10 +00002831 unlock_user_struct(ucp, ucp_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02002832 force_sig(TARGET_SIGSEGV);
blueswir15bfb56b2007-10-05 17:01:51 +00002833}
2834#endif
Richard Hendersonff970902013-02-10 10:30:42 -08002835#elif defined(TARGET_MIPS) || defined(TARGET_MIPS64)
bellard106ec872006-06-27 21:08:10 +00002836
Richard Hendersonff970902013-02-10 10:30:42 -08002837# if defined(TARGET_ABI_MIPSO32)
bellard106ec872006-06-27 21:08:10 +00002838struct target_sigcontext {
2839 uint32_t sc_regmask; /* Unused */
2840 uint32_t sc_status;
2841 uint64_t sc_pc;
2842 uint64_t sc_regs[32];
2843 uint64_t sc_fpregs[32];
2844 uint32_t sc_ownedfp; /* Unused */
2845 uint32_t sc_fpc_csr;
2846 uint32_t sc_fpc_eir; /* Unused */
2847 uint32_t sc_used_math;
2848 uint32_t sc_dsp; /* dsp status, was sc_ssflags */
Paul Brook94c54952009-07-09 18:40:15 +01002849 uint32_t pad0;
bellard106ec872006-06-27 21:08:10 +00002850 uint64_t sc_mdhi;
2851 uint64_t sc_mdlo;
2852 target_ulong sc_hi1; /* Was sc_cause */
2853 target_ulong sc_lo1; /* Was sc_badvaddr */
2854 target_ulong sc_hi2; /* Was sc_sigset[4] */
2855 target_ulong sc_lo2;
2856 target_ulong sc_hi3;
2857 target_ulong sc_lo3;
2858};
Richard Hendersonff970902013-02-10 10:30:42 -08002859# else /* N32 || N64 */
2860struct target_sigcontext {
2861 uint64_t sc_regs[32];
2862 uint64_t sc_fpregs[32];
2863 uint64_t sc_mdhi;
2864 uint64_t sc_hi1;
2865 uint64_t sc_hi2;
2866 uint64_t sc_hi3;
2867 uint64_t sc_mdlo;
2868 uint64_t sc_lo1;
2869 uint64_t sc_lo2;
2870 uint64_t sc_lo3;
2871 uint64_t sc_pc;
2872 uint32_t sc_fpc_csr;
2873 uint32_t sc_used_math;
2874 uint32_t sc_dsp;
2875 uint32_t sc_reserved;
2876};
2877# endif /* O32 */
bellard106ec872006-06-27 21:08:10 +00002878
2879struct sigframe {
2880 uint32_t sf_ass[4]; /* argument save space for o32 */
2881 uint32_t sf_code[2]; /* signal trampoline */
2882 struct target_sigcontext sf_sc;
Anthony Liguoric227f092009-10-01 16:12:16 -05002883 target_sigset_t sf_mask;
bellard106ec872006-06-27 21:08:10 +00002884};
2885
pbrook0b1bcb02009-04-21 01:41:10 +00002886struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02002887 target_ulong tuc_flags;
2888 target_ulong tuc_link;
2889 target_stack_t tuc_stack;
Paul Brook94c54952009-07-09 18:40:15 +01002890 target_ulong pad0;
Aurelien Jarno60e99242010-03-29 02:12:51 +02002891 struct target_sigcontext tuc_mcontext;
2892 target_sigset_t tuc_sigmask;
pbrook0b1bcb02009-04-21 01:41:10 +00002893};
2894
2895struct target_rt_sigframe {
2896 uint32_t rs_ass[4]; /* argument save space for o32 */
2897 uint32_t rs_code[2]; /* signal trampoline */
2898 struct target_siginfo rs_info;
2899 struct target_ucontext rs_uc;
2900};
2901
bellard106ec872006-06-27 21:08:10 +00002902/* Install trampoline to jump back from signal handler */
2903static inline int install_sigtramp(unsigned int *tramp, unsigned int syscall)
2904{
Richard Henderson084d0492013-02-10 10:30:44 -08002905 int err = 0;
bellard106ec872006-06-27 21:08:10 +00002906
2907 /*
Richard Henderson084d0492013-02-10 10:30:44 -08002908 * Set up the return code ...
2909 *
2910 * li v0, __NR__foo_sigreturn
2911 * syscall
2912 */
bellard106ec872006-06-27 21:08:10 +00002913
Riku Voipio1d8b5122014-04-23 10:26:05 +03002914 __put_user(0x24020000 + syscall, tramp + 0);
2915 __put_user(0x0000000c , tramp + 1);
bellard106ec872006-06-27 21:08:10 +00002916 return err;
2917}
2918
Riku Voipio41ecc722014-04-23 11:01:00 +03002919static inline void setup_sigcontext(CPUMIPSState *regs,
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002920 struct target_sigcontext *sc)
bellard106ec872006-06-27 21:08:10 +00002921{
Richard Henderson084d0492013-02-10 10:30:44 -08002922 int i;
bellard106ec872006-06-27 21:08:10 +00002923
Riku Voipio1d8b5122014-04-23 10:26:05 +03002924 __put_user(exception_resume_pc(regs), &sc->sc_pc);
Kwok Cheung Yeung1239b472013-05-17 14:51:21 -07002925 regs->hflags &= ~MIPS_HFLAG_BMASK;
bellard106ec872006-06-27 21:08:10 +00002926
Richard Henderson084d0492013-02-10 10:30:44 -08002927 __put_user(0, &sc->sc_regs[0]);
2928 for (i = 1; i < 32; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002929 __put_user(regs->active_tc.gpr[i], &sc->sc_regs[i]);
Richard Henderson084d0492013-02-10 10:30:44 -08002930 }
bellard106ec872006-06-27 21:08:10 +00002931
Riku Voipio1d8b5122014-04-23 10:26:05 +03002932 __put_user(regs->active_tc.HI[0], &sc->sc_mdhi);
2933 __put_user(regs->active_tc.LO[0], &sc->sc_mdlo);
bellard106ec872006-06-27 21:08:10 +00002934
Richard Henderson084d0492013-02-10 10:30:44 -08002935 /* Rather than checking for dsp existence, always copy. The storage
2936 would just be garbage otherwise. */
Riku Voipio1d8b5122014-04-23 10:26:05 +03002937 __put_user(regs->active_tc.HI[1], &sc->sc_hi1);
2938 __put_user(regs->active_tc.HI[2], &sc->sc_hi2);
2939 __put_user(regs->active_tc.HI[3], &sc->sc_hi3);
2940 __put_user(regs->active_tc.LO[1], &sc->sc_lo1);
2941 __put_user(regs->active_tc.LO[2], &sc->sc_lo2);
2942 __put_user(regs->active_tc.LO[3], &sc->sc_lo3);
Richard Henderson084d0492013-02-10 10:30:44 -08002943 {
2944 uint32_t dsp = cpu_rddsp(0x3ff, regs);
Riku Voipio1d8b5122014-04-23 10:26:05 +03002945 __put_user(dsp, &sc->sc_dsp);
bellard106ec872006-06-27 21:08:10 +00002946 }
Richard Henderson084d0492013-02-10 10:30:44 -08002947
Riku Voipio1d8b5122014-04-23 10:26:05 +03002948 __put_user(1, &sc->sc_used_math);
Richard Henderson084d0492013-02-10 10:30:44 -08002949
2950 for (i = 0; i < 32; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002951 __put_user(regs->active_fpu.fpr[i].d, &sc->sc_fpregs[i]);
bellard106ec872006-06-27 21:08:10 +00002952 }
bellard106ec872006-06-27 21:08:10 +00002953}
2954
Riku Voipio016d2e12014-04-23 11:19:48 +03002955static inline void
Andreas Färber05390242012-02-25 03:37:53 +01002956restore_sigcontext(CPUMIPSState *regs, struct target_sigcontext *sc)
bellard106ec872006-06-27 21:08:10 +00002957{
Richard Henderson084d0492013-02-10 10:30:44 -08002958 int i;
bellard106ec872006-06-27 21:08:10 +00002959
Riku Voipio1d8b5122014-04-23 10:26:05 +03002960 __get_user(regs->CP0_EPC, &sc->sc_pc);
bellard106ec872006-06-27 21:08:10 +00002961
Riku Voipio1d8b5122014-04-23 10:26:05 +03002962 __get_user(regs->active_tc.HI[0], &sc->sc_mdhi);
2963 __get_user(regs->active_tc.LO[0], &sc->sc_mdlo);
bellard106ec872006-06-27 21:08:10 +00002964
Richard Henderson084d0492013-02-10 10:30:44 -08002965 for (i = 1; i < 32; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002966 __get_user(regs->active_tc.gpr[i], &sc->sc_regs[i]);
bellard106ec872006-06-27 21:08:10 +00002967 }
2968
Riku Voipio1d8b5122014-04-23 10:26:05 +03002969 __get_user(regs->active_tc.HI[1], &sc->sc_hi1);
2970 __get_user(regs->active_tc.HI[2], &sc->sc_hi2);
2971 __get_user(regs->active_tc.HI[3], &sc->sc_hi3);
2972 __get_user(regs->active_tc.LO[1], &sc->sc_lo1);
2973 __get_user(regs->active_tc.LO[2], &sc->sc_lo2);
2974 __get_user(regs->active_tc.LO[3], &sc->sc_lo3);
Richard Henderson084d0492013-02-10 10:30:44 -08002975 {
2976 uint32_t dsp;
Riku Voipio1d8b5122014-04-23 10:26:05 +03002977 __get_user(dsp, &sc->sc_dsp);
Richard Henderson084d0492013-02-10 10:30:44 -08002978 cpu_wrdsp(dsp, 0x3ff, regs);
2979 }
2980
2981 for (i = 0; i < 32; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002982 __get_user(regs->active_fpu.fpr[i].d, &sc->sc_fpregs[i]);
Richard Henderson084d0492013-02-10 10:30:44 -08002983 }
bellard106ec872006-06-27 21:08:10 +00002984}
Richard Hendersonff970902013-02-10 10:30:42 -08002985
bellard106ec872006-06-27 21:08:10 +00002986/*
2987 * Determine which stack to use..
2988 */
bellard579a97f2007-11-11 14:26:47 +00002989static inline abi_ulong
Andreas Färber05390242012-02-25 03:37:53 +01002990get_sigframe(struct target_sigaction *ka, CPUMIPSState *regs, size_t frame_size)
bellard106ec872006-06-27 21:08:10 +00002991{
2992 unsigned long sp;
2993
2994 /* Default to using normal stack */
thsb5dc7732008-06-27 10:02:35 +00002995 sp = regs->active_tc.gpr[29];
bellard106ec872006-06-27 21:08:10 +00002996
2997 /*
Stefan Weil93148aa2012-02-26 18:46:12 +01002998 * FPU emulator may have its own trampoline active just
bellard106ec872006-06-27 21:08:10 +00002999 * above the user stack, 16-bytes before the next lowest
3000 * 16 byte boundary. Try to avoid trashing it.
3001 */
3002 sp -= 32;
3003
bellard106ec872006-06-27 21:08:10 +00003004 /* This is the X/Open sanctioned signal stack switching. */
pbrook624f7972008-05-31 16:11:38 +00003005 if ((ka->sa_flags & TARGET_SA_ONSTACK) && (sas_ss_flags (sp) == 0)) {
thsa04e1342007-09-27 13:57:58 +00003006 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
3007 }
bellard106ec872006-06-27 21:08:10 +00003008
bellard579a97f2007-11-11 14:26:47 +00003009 return (sp - frame_size) & ~7;
bellard106ec872006-06-27 21:08:10 +00003010}
3011
Kwok Cheung Yeungea3164a2013-05-17 14:51:20 -07003012static void mips_set_hflags_isa_mode_from_pc(CPUMIPSState *env)
3013{
3014 if (env->insn_flags & (ASE_MIPS16 | ASE_MICROMIPS)) {
3015 env->hflags &= ~MIPS_HFLAG_M16;
3016 env->hflags |= (env->active_tc.PC & 1) << MIPS_HFLAG_M16_SHIFT;
3017 env->active_tc.PC &= ~(target_ulong) 1;
3018 }
3019}
3020
Richard Hendersonff970902013-02-10 10:30:42 -08003021# if defined(TARGET_ABI_MIPSO32)
bellard579a97f2007-11-11 14:26:47 +00003022/* compare linux/arch/mips/kernel/signal.c:setup_frame() */
pbrook624f7972008-05-31 16:11:38 +00003023static void setup_frame(int sig, struct target_sigaction * ka,
Andreas Färber05390242012-02-25 03:37:53 +01003024 target_sigset_t *set, CPUMIPSState *regs)
bellard106ec872006-06-27 21:08:10 +00003025{
3026 struct sigframe *frame;
bellard579a97f2007-11-11 14:26:47 +00003027 abi_ulong frame_addr;
bellard106ec872006-06-27 21:08:10 +00003028 int i;
3029
bellard579a97f2007-11-11 14:26:47 +00003030 frame_addr = get_sigframe(ka, regs, sizeof(*frame));
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01003031 trace_user_setup_frame(regs, frame_addr);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003032 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
3033 goto give_sigsegv;
3034 }
bellard106ec872006-06-27 21:08:10 +00003035
3036 install_sigtramp(frame->sf_code, TARGET_NR_sigreturn);
3037
Riku Voipio41ecc722014-04-23 11:01:00 +03003038 setup_sigcontext(regs, &frame->sf_sc);
bellard106ec872006-06-27 21:08:10 +00003039
3040 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
Riku Voipio0188fad2014-04-23 13:34:15 +03003041 __put_user(set->sig[i], &frame->sf_mask.sig[i]);
bellard106ec872006-06-27 21:08:10 +00003042 }
3043
3044 /*
3045 * Arguments to signal handler:
3046 *
3047 * a0 = signal number
3048 * a1 = 0 (should be cause)
3049 * a2 = pointer to struct sigcontext
3050 *
3051 * $25 and PC point to the signal handler, $29 points to the
3052 * struct sigframe.
3053 */
thsb5dc7732008-06-27 10:02:35 +00003054 regs->active_tc.gpr[ 4] = sig;
3055 regs->active_tc.gpr[ 5] = 0;
3056 regs->active_tc.gpr[ 6] = frame_addr + offsetof(struct sigframe, sf_sc);
3057 regs->active_tc.gpr[29] = frame_addr;
3058 regs->active_tc.gpr[31] = frame_addr + offsetof(struct sigframe, sf_code);
bellard106ec872006-06-27 21:08:10 +00003059 /* The original kernel code sets CP0_EPC to the handler
3060 * since it returns to userland using eret
3061 * we cannot do this here, and we must set PC directly */
thsb5dc7732008-06-27 10:02:35 +00003062 regs->active_tc.PC = regs->active_tc.gpr[25] = ka->_sa_handler;
Kwok Cheung Yeungea3164a2013-05-17 14:51:20 -07003063 mips_set_hflags_isa_mode_from_pc(regs);
bellard579a97f2007-11-11 14:26:47 +00003064 unlock_user_struct(frame, frame_addr, 1);
bellard106ec872006-06-27 21:08:10 +00003065 return;
3066
3067give_sigsegv:
Peter Maydell09391662016-07-28 16:44:47 +01003068 force_sigsegv(sig);
bellard106ec872006-06-27 21:08:10 +00003069}
3070
Andreas Färber05390242012-02-25 03:37:53 +01003071long do_sigreturn(CPUMIPSState *regs)
bellard106ec872006-06-27 21:08:10 +00003072{
ths388bb212007-05-13 13:58:00 +00003073 struct sigframe *frame;
bellard579a97f2007-11-11 14:26:47 +00003074 abi_ulong frame_addr;
ths388bb212007-05-13 13:58:00 +00003075 sigset_t blocked;
Anthony Liguoric227f092009-10-01 16:12:16 -05003076 target_sigset_t target_set;
ths388bb212007-05-13 13:58:00 +00003077 int i;
bellard106ec872006-06-27 21:08:10 +00003078
thsb5dc7732008-06-27 10:02:35 +00003079 frame_addr = regs->active_tc.gpr[29];
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01003080 trace_user_do_sigreturn(regs, frame_addr);
bellard579a97f2007-11-11 14:26:47 +00003081 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003082 goto badframe;
bellard106ec872006-06-27 21:08:10 +00003083
ths388bb212007-05-13 13:58:00 +00003084 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
Riku Voipiof5f601a2014-04-23 13:00:17 +03003085 __get_user(target_set.sig[i], &frame->sf_mask.sig[i]);
ths388bb212007-05-13 13:58:00 +00003086 }
bellard106ec872006-06-27 21:08:10 +00003087
ths388bb212007-05-13 13:58:00 +00003088 target_to_host_sigset_internal(&blocked, &target_set);
Peter Maydell9eede5b2016-05-27 15:51:46 +01003089 set_sigmask(&blocked);
bellard106ec872006-06-27 21:08:10 +00003090
Riku Voipio016d2e12014-04-23 11:19:48 +03003091 restore_sigcontext(regs, &frame->sf_sc);
bellard106ec872006-06-27 21:08:10 +00003092
3093#if 0
ths388bb212007-05-13 13:58:00 +00003094 /*
3095 * Don't let your children do this ...
3096 */
3097 __asm__ __volatile__(
bellard106ec872006-06-27 21:08:10 +00003098 "move\t$29, %0\n\t"
3099 "j\tsyscall_exit"
3100 :/* no outputs */
3101 :"r" (&regs));
ths388bb212007-05-13 13:58:00 +00003102 /* Unreached */
bellard106ec872006-06-27 21:08:10 +00003103#endif
ths3b46e622007-09-17 08:09:54 +00003104
thsb5dc7732008-06-27 10:02:35 +00003105 regs->active_tc.PC = regs->CP0_EPC;
Kwok Cheung Yeungea3164a2013-05-17 14:51:20 -07003106 mips_set_hflags_isa_mode_from_pc(regs);
ths388bb212007-05-13 13:58:00 +00003107 /* I am not sure this is right, but it seems to work
bellard106ec872006-06-27 21:08:10 +00003108 * maybe a problem with nested signals ? */
3109 regs->CP0_EPC = 0;
pbrook0b1bcb02009-04-21 01:41:10 +00003110 return -TARGET_QEMU_ESIGRETURN;
bellard106ec872006-06-27 21:08:10 +00003111
3112badframe:
ths388bb212007-05-13 13:58:00 +00003113 force_sig(TARGET_SIGSEGV/*, current*/);
3114 return 0;
bellard106ec872006-06-27 21:08:10 +00003115}
Richard Hendersonff970902013-02-10 10:30:42 -08003116# endif /* O32 */
bellard106ec872006-06-27 21:08:10 +00003117
pbrook624f7972008-05-31 16:11:38 +00003118static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05003119 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01003120 target_sigset_t *set, CPUMIPSState *env)
bellard106ec872006-06-27 21:08:10 +00003121{
pbrook0b1bcb02009-04-21 01:41:10 +00003122 struct target_rt_sigframe *frame;
3123 abi_ulong frame_addr;
3124 int i;
3125
3126 frame_addr = get_sigframe(ka, env, sizeof(*frame));
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01003127 trace_user_setup_rt_frame(env, frame_addr);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003128 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
3129 goto give_sigsegv;
3130 }
pbrook0b1bcb02009-04-21 01:41:10 +00003131
3132 install_sigtramp(frame->rs_code, TARGET_NR_rt_sigreturn);
3133
Peter Maydellf6c7a052015-01-08 12:19:48 +00003134 tswap_siginfo(&frame->rs_info, info);
pbrook0b1bcb02009-04-21 01:41:10 +00003135
Aurelien Jarno60e99242010-03-29 02:12:51 +02003136 __put_user(0, &frame->rs_uc.tuc_flags);
3137 __put_user(0, &frame->rs_uc.tuc_link);
3138 __put_user(target_sigaltstack_used.ss_sp, &frame->rs_uc.tuc_stack.ss_sp);
3139 __put_user(target_sigaltstack_used.ss_size, &frame->rs_uc.tuc_stack.ss_size);
pbrook0b1bcb02009-04-21 01:41:10 +00003140 __put_user(sas_ss_flags(get_sp_from_cpustate(env)),
Aurelien Jarno60e99242010-03-29 02:12:51 +02003141 &frame->rs_uc.tuc_stack.ss_flags);
pbrook0b1bcb02009-04-21 01:41:10 +00003142
Aurelien Jarno60e99242010-03-29 02:12:51 +02003143 setup_sigcontext(env, &frame->rs_uc.tuc_mcontext);
pbrook0b1bcb02009-04-21 01:41:10 +00003144
3145 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
Aurelien Jarno60e99242010-03-29 02:12:51 +02003146 __put_user(set->sig[i], &frame->rs_uc.tuc_sigmask.sig[i]);
pbrook0b1bcb02009-04-21 01:41:10 +00003147 }
3148
3149 /*
3150 * Arguments to signal handler:
3151 *
3152 * a0 = signal number
Richard W.M. Jones02d2bd52012-07-05 03:32:44 +00003153 * a1 = pointer to siginfo_t
pbrook0b1bcb02009-04-21 01:41:10 +00003154 * a2 = pointer to struct ucontext
3155 *
3156 * $25 and PC point to the signal handler, $29 points to the
3157 * struct sigframe.
3158 */
3159 env->active_tc.gpr[ 4] = sig;
3160 env->active_tc.gpr[ 5] = frame_addr
3161 + offsetof(struct target_rt_sigframe, rs_info);
3162 env->active_tc.gpr[ 6] = frame_addr
3163 + offsetof(struct target_rt_sigframe, rs_uc);
3164 env->active_tc.gpr[29] = frame_addr;
3165 env->active_tc.gpr[31] = frame_addr
3166 + offsetof(struct target_rt_sigframe, rs_code);
3167 /* The original kernel code sets CP0_EPC to the handler
3168 * since it returns to userland using eret
3169 * we cannot do this here, and we must set PC directly */
3170 env->active_tc.PC = env->active_tc.gpr[25] = ka->_sa_handler;
Kwok Cheung Yeungea3164a2013-05-17 14:51:20 -07003171 mips_set_hflags_isa_mode_from_pc(env);
pbrook0b1bcb02009-04-21 01:41:10 +00003172 unlock_user_struct(frame, frame_addr, 1);
3173 return;
3174
3175give_sigsegv:
3176 unlock_user_struct(frame, frame_addr, 1);
Peter Maydell09391662016-07-28 16:44:47 +01003177 force_sigsegv(sig);
bellard106ec872006-06-27 21:08:10 +00003178}
3179
Andreas Färber05390242012-02-25 03:37:53 +01003180long do_rt_sigreturn(CPUMIPSState *env)
bellard106ec872006-06-27 21:08:10 +00003181{
pbrook0b1bcb02009-04-21 01:41:10 +00003182 struct target_rt_sigframe *frame;
3183 abi_ulong frame_addr;
3184 sigset_t blocked;
3185
pbrook0b1bcb02009-04-21 01:41:10 +00003186 frame_addr = env->active_tc.gpr[29];
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01003187 trace_user_do_rt_sigreturn(env, frame_addr);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003188 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
3189 goto badframe;
3190 }
pbrook0b1bcb02009-04-21 01:41:10 +00003191
Aurelien Jarno60e99242010-03-29 02:12:51 +02003192 target_to_host_sigset(&blocked, &frame->rs_uc.tuc_sigmask);
Peter Maydell9eede5b2016-05-27 15:51:46 +01003193 set_sigmask(&blocked);
pbrook0b1bcb02009-04-21 01:41:10 +00003194
Riku Voipio016d2e12014-04-23 11:19:48 +03003195 restore_sigcontext(env, &frame->rs_uc.tuc_mcontext);
pbrook0b1bcb02009-04-21 01:41:10 +00003196
3197 if (do_sigaltstack(frame_addr +
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003198 offsetof(struct target_rt_sigframe, rs_uc.tuc_stack),
3199 0, get_sp_from_cpustate(env)) == -EFAULT)
pbrook0b1bcb02009-04-21 01:41:10 +00003200 goto badframe;
3201
3202 env->active_tc.PC = env->CP0_EPC;
Kwok Cheung Yeungea3164a2013-05-17 14:51:20 -07003203 mips_set_hflags_isa_mode_from_pc(env);
pbrook0b1bcb02009-04-21 01:41:10 +00003204 /* I am not sure this is right, but it seems to work
3205 * maybe a problem with nested signals ? */
3206 env->CP0_EPC = 0;
3207 return -TARGET_QEMU_ESIGRETURN;
3208
3209badframe:
3210 force_sig(TARGET_SIGSEGV/*, current*/);
3211 return 0;
bellard106ec872006-06-27 21:08:10 +00003212}
bellard6d5e2162004-09-30 22:04:13 +00003213
thsc3b5bc82007-12-02 06:31:25 +00003214#elif defined(TARGET_SH4)
3215
3216/*
3217 * code and data structures from linux kernel:
3218 * include/asm-sh/sigcontext.h
3219 * arch/sh/kernel/signal.c
3220 */
3221
3222struct target_sigcontext {
3223 target_ulong oldmask;
3224
3225 /* CPU registers */
3226 target_ulong sc_gregs[16];
3227 target_ulong sc_pc;
3228 target_ulong sc_pr;
3229 target_ulong sc_sr;
3230 target_ulong sc_gbr;
3231 target_ulong sc_mach;
3232 target_ulong sc_macl;
3233
3234 /* FPU registers */
3235 target_ulong sc_fpregs[16];
3236 target_ulong sc_xfpregs[16];
3237 unsigned int sc_fpscr;
3238 unsigned int sc_fpul;
3239 unsigned int sc_ownedfp;
3240};
3241
3242struct target_sigframe
3243{
3244 struct target_sigcontext sc;
3245 target_ulong extramask[TARGET_NSIG_WORDS-1];
3246 uint16_t retcode[3];
3247};
3248
3249
3250struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02003251 target_ulong tuc_flags;
3252 struct target_ucontext *tuc_link;
3253 target_stack_t tuc_stack;
3254 struct target_sigcontext tuc_mcontext;
3255 target_sigset_t tuc_sigmask; /* mask last for extensibility */
thsc3b5bc82007-12-02 06:31:25 +00003256};
3257
3258struct target_rt_sigframe
3259{
3260 struct target_siginfo info;
3261 struct target_ucontext uc;
3262 uint16_t retcode[3];
3263};
3264
3265
3266#define MOVW(n) (0x9300|((n)-2)) /* Move mem word at PC+n to R3 */
3267#define TRAP_NOARG 0xc310 /* Syscall w/no args (NR in R3) SH3/4 */
3268
pbrook624f7972008-05-31 16:11:38 +00003269static abi_ulong get_sigframe(struct target_sigaction *ka,
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003270 unsigned long sp, size_t frame_size)
thsc3b5bc82007-12-02 06:31:25 +00003271{
pbrook624f7972008-05-31 16:11:38 +00003272 if ((ka->sa_flags & TARGET_SA_ONSTACK) && (sas_ss_flags(sp) == 0)) {
thsc3b5bc82007-12-02 06:31:25 +00003273 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
3274 }
3275
3276 return (sp - frame_size) & -8ul;
3277}
3278
Riku Voipio41ecc722014-04-23 11:01:00 +03003279static void setup_sigcontext(struct target_sigcontext *sc,
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003280 CPUSH4State *regs, unsigned long mask)
thsc3b5bc82007-12-02 06:31:25 +00003281{
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003282 int i;
thsc3b5bc82007-12-02 06:31:25 +00003283
Riku Voipio1d8b5122014-04-23 10:26:05 +03003284#define COPY(x) __put_user(regs->x, &sc->sc_##x)
thsc3b5bc82007-12-02 06:31:25 +00003285 COPY(gregs[0]); COPY(gregs[1]);
3286 COPY(gregs[2]); COPY(gregs[3]);
3287 COPY(gregs[4]); COPY(gregs[5]);
3288 COPY(gregs[6]); COPY(gregs[7]);
3289 COPY(gregs[8]); COPY(gregs[9]);
3290 COPY(gregs[10]); COPY(gregs[11]);
3291 COPY(gregs[12]); COPY(gregs[13]);
3292 COPY(gregs[14]); COPY(gregs[15]);
3293 COPY(gbr); COPY(mach);
3294 COPY(macl); COPY(pr);
3295 COPY(sr); COPY(pc);
3296#undef COPY
3297
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003298 for (i=0; i<16; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03003299 __put_user(regs->fregs[i], &sc->sc_fpregs[i]);
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003300 }
Riku Voipio1d8b5122014-04-23 10:26:05 +03003301 __put_user(regs->fpscr, &sc->sc_fpscr);
3302 __put_user(regs->fpul, &sc->sc_fpul);
thsc3b5bc82007-12-02 06:31:25 +00003303
3304 /* non-iBCS2 extensions.. */
Riku Voipio1d8b5122014-04-23 10:26:05 +03003305 __put_user(mask, &sc->oldmask);
thsc3b5bc82007-12-02 06:31:25 +00003306}
3307
Timothy E Baldwinba412492016-05-12 18:47:35 +01003308static void restore_sigcontext(CPUSH4State *regs, struct target_sigcontext *sc)
thsc3b5bc82007-12-02 06:31:25 +00003309{
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003310 int i;
thsc3b5bc82007-12-02 06:31:25 +00003311
Riku Voipio1d8b5122014-04-23 10:26:05 +03003312#define COPY(x) __get_user(regs->x, &sc->sc_##x)
Timothy E Baldwinba412492016-05-12 18:47:35 +01003313 COPY(gregs[0]); COPY(gregs[1]);
thsc3b5bc82007-12-02 06:31:25 +00003314 COPY(gregs[2]); COPY(gregs[3]);
3315 COPY(gregs[4]); COPY(gregs[5]);
3316 COPY(gregs[6]); COPY(gregs[7]);
3317 COPY(gregs[8]); COPY(gregs[9]);
3318 COPY(gregs[10]); COPY(gregs[11]);
3319 COPY(gregs[12]); COPY(gregs[13]);
3320 COPY(gregs[14]); COPY(gregs[15]);
3321 COPY(gbr); COPY(mach);
3322 COPY(macl); COPY(pr);
3323 COPY(sr); COPY(pc);
3324#undef COPY
3325
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003326 for (i=0; i<16; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03003327 __get_user(regs->fregs[i], &sc->sc_fpregs[i]);
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003328 }
Riku Voipio1d8b5122014-04-23 10:26:05 +03003329 __get_user(regs->fpscr, &sc->sc_fpscr);
3330 __get_user(regs->fpul, &sc->sc_fpul);
thsc3b5bc82007-12-02 06:31:25 +00003331
3332 regs->tra = -1; /* disable syscall checks */
thsc3b5bc82007-12-02 06:31:25 +00003333}
3334
pbrook624f7972008-05-31 16:11:38 +00003335static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01003336 target_sigset_t *set, CPUSH4State *regs)
thsc3b5bc82007-12-02 06:31:25 +00003337{
3338 struct target_sigframe *frame;
3339 abi_ulong frame_addr;
3340 int i;
thsc3b5bc82007-12-02 06:31:25 +00003341
3342 frame_addr = get_sigframe(ka, regs->gregs[15], sizeof(*frame));
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01003343 trace_user_setup_frame(regs, frame_addr);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003344 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
3345 goto give_sigsegv;
3346 }
thsc3b5bc82007-12-02 06:31:25 +00003347
Riku Voipio41ecc722014-04-23 11:01:00 +03003348 setup_sigcontext(&frame->sc, regs, set->sig[0]);
thsc3b5bc82007-12-02 06:31:25 +00003349
3350 for (i = 0; i < TARGET_NSIG_WORDS - 1; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03003351 __put_user(set->sig[i + 1], &frame->extramask[i]);
thsc3b5bc82007-12-02 06:31:25 +00003352 }
3353
3354 /* Set up to return from userspace. If provided, use a stub
3355 already in userspace. */
pbrook624f7972008-05-31 16:11:38 +00003356 if (ka->sa_flags & TARGET_SA_RESTORER) {
3357 regs->pr = (unsigned long) ka->sa_restorer;
thsc3b5bc82007-12-02 06:31:25 +00003358 } else {
3359 /* Generate return code (system call to sigreturn) */
Laurent Vivier2a0fa682015-11-23 11:38:26 +01003360 abi_ulong retcode_addr = frame_addr +
3361 offsetof(struct target_sigframe, retcode);
Riku Voipio1d8b5122014-04-23 10:26:05 +03003362 __put_user(MOVW(2), &frame->retcode[0]);
3363 __put_user(TRAP_NOARG, &frame->retcode[1]);
3364 __put_user((TARGET_NR_sigreturn), &frame->retcode[2]);
Laurent Vivier2a0fa682015-11-23 11:38:26 +01003365 regs->pr = (unsigned long) retcode_addr;
thsc3b5bc82007-12-02 06:31:25 +00003366 }
3367
thsc3b5bc82007-12-02 06:31:25 +00003368 /* Set up registers for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003369 regs->gregs[15] = frame_addr;
Peter Maydellb6e2c932015-01-08 12:19:43 +00003370 regs->gregs[4] = sig; /* Arg for signal handler */
thsc3b5bc82007-12-02 06:31:25 +00003371 regs->gregs[5] = 0;
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003372 regs->gregs[6] = frame_addr += offsetof(typeof(*frame), sc);
pbrook624f7972008-05-31 16:11:38 +00003373 regs->pc = (unsigned long) ka->_sa_handler;
thsc3b5bc82007-12-02 06:31:25 +00003374
3375 unlock_user_struct(frame, frame_addr, 1);
3376 return;
3377
3378give_sigsegv:
3379 unlock_user_struct(frame, frame_addr, 1);
Peter Maydell09391662016-07-28 16:44:47 +01003380 force_sigsegv(sig);
thsc3b5bc82007-12-02 06:31:25 +00003381}
3382
pbrook624f7972008-05-31 16:11:38 +00003383static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05003384 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01003385 target_sigset_t *set, CPUSH4State *regs)
thsc3b5bc82007-12-02 06:31:25 +00003386{
3387 struct target_rt_sigframe *frame;
3388 abi_ulong frame_addr;
3389 int i;
thsc3b5bc82007-12-02 06:31:25 +00003390
3391 frame_addr = get_sigframe(ka, regs->gregs[15], sizeof(*frame));
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01003392 trace_user_setup_rt_frame(regs, frame_addr);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003393 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
3394 goto give_sigsegv;
3395 }
thsc3b5bc82007-12-02 06:31:25 +00003396
Peter Maydellf6c7a052015-01-08 12:19:48 +00003397 tswap_siginfo(&frame->info, info);
thsc3b5bc82007-12-02 06:31:25 +00003398
3399 /* Create the ucontext. */
Riku Voipio1d8b5122014-04-23 10:26:05 +03003400 __put_user(0, &frame->uc.tuc_flags);
3401 __put_user(0, (unsigned long *)&frame->uc.tuc_link);
3402 __put_user((unsigned long)target_sigaltstack_used.ss_sp,
3403 &frame->uc.tuc_stack.ss_sp);
3404 __put_user(sas_ss_flags(regs->gregs[15]),
3405 &frame->uc.tuc_stack.ss_flags);
3406 __put_user(target_sigaltstack_used.ss_size,
3407 &frame->uc.tuc_stack.ss_size);
3408 setup_sigcontext(&frame->uc.tuc_mcontext,
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003409 regs, set->sig[0]);
thsc3b5bc82007-12-02 06:31:25 +00003410 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03003411 __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
thsc3b5bc82007-12-02 06:31:25 +00003412 }
3413
3414 /* Set up to return from userspace. If provided, use a stub
3415 already in userspace. */
pbrook624f7972008-05-31 16:11:38 +00003416 if (ka->sa_flags & TARGET_SA_RESTORER) {
3417 regs->pr = (unsigned long) ka->sa_restorer;
thsc3b5bc82007-12-02 06:31:25 +00003418 } else {
3419 /* Generate return code (system call to sigreturn) */
Laurent Vivier2a0fa682015-11-23 11:38:26 +01003420 abi_ulong retcode_addr = frame_addr +
3421 offsetof(struct target_rt_sigframe, retcode);
Riku Voipio1d8b5122014-04-23 10:26:05 +03003422 __put_user(MOVW(2), &frame->retcode[0]);
3423 __put_user(TRAP_NOARG, &frame->retcode[1]);
3424 __put_user((TARGET_NR_rt_sigreturn), &frame->retcode[2]);
Laurent Vivier2a0fa682015-11-23 11:38:26 +01003425 regs->pr = (unsigned long) retcode_addr;
thsc3b5bc82007-12-02 06:31:25 +00003426 }
3427
thsc3b5bc82007-12-02 06:31:25 +00003428 /* Set up registers for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003429 regs->gregs[15] = frame_addr;
Peter Maydellb6e2c932015-01-08 12:19:43 +00003430 regs->gregs[4] = sig; /* Arg for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003431 regs->gregs[5] = frame_addr + offsetof(typeof(*frame), info);
3432 regs->gregs[6] = frame_addr + offsetof(typeof(*frame), uc);
pbrook624f7972008-05-31 16:11:38 +00003433 regs->pc = (unsigned long) ka->_sa_handler;
thsc3b5bc82007-12-02 06:31:25 +00003434
3435 unlock_user_struct(frame, frame_addr, 1);
3436 return;
3437
3438give_sigsegv:
3439 unlock_user_struct(frame, frame_addr, 1);
Peter Maydell09391662016-07-28 16:44:47 +01003440 force_sigsegv(sig);
thsc3b5bc82007-12-02 06:31:25 +00003441}
3442
Andreas Färber05390242012-02-25 03:37:53 +01003443long do_sigreturn(CPUSH4State *regs)
thsc3b5bc82007-12-02 06:31:25 +00003444{
3445 struct target_sigframe *frame;
3446 abi_ulong frame_addr;
3447 sigset_t blocked;
Anthony Liguoric227f092009-10-01 16:12:16 -05003448 target_sigset_t target_set;
thsc3b5bc82007-12-02 06:31:25 +00003449 int i;
3450 int err = 0;
3451
thsc3b5bc82007-12-02 06:31:25 +00003452 frame_addr = regs->gregs[15];
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01003453 trace_user_do_sigreturn(regs, frame_addr);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003454 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
3455 goto badframe;
3456 }
thsc3b5bc82007-12-02 06:31:25 +00003457
Riku Voipio1d8b5122014-04-23 10:26:05 +03003458 __get_user(target_set.sig[0], &frame->sc.oldmask);
thsc3b5bc82007-12-02 06:31:25 +00003459 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03003460 __get_user(target_set.sig[i], &frame->extramask[i - 1]);
thsc3b5bc82007-12-02 06:31:25 +00003461 }
3462
3463 if (err)
3464 goto badframe;
3465
3466 target_to_host_sigset_internal(&blocked, &target_set);
Peter Maydell9eede5b2016-05-27 15:51:46 +01003467 set_sigmask(&blocked);
thsc3b5bc82007-12-02 06:31:25 +00003468
Timothy E Baldwinba412492016-05-12 18:47:35 +01003469 restore_sigcontext(regs, &frame->sc);
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}
3479
Andreas Färber05390242012-02-25 03:37:53 +01003480long do_rt_sigreturn(CPUSH4State *regs)
thsc3b5bc82007-12-02 06:31:25 +00003481{
3482 struct target_rt_sigframe *frame;
3483 abi_ulong frame_addr;
3484 sigset_t blocked;
3485
thsc3b5bc82007-12-02 06:31:25 +00003486 frame_addr = regs->gregs[15];
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01003487 trace_user_do_rt_sigreturn(regs, frame_addr);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003488 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
3489 goto badframe;
3490 }
thsc3b5bc82007-12-02 06:31:25 +00003491
Aurelien Jarno60e99242010-03-29 02:12:51 +02003492 target_to_host_sigset(&blocked, &frame->uc.tuc_sigmask);
Peter Maydell9eede5b2016-05-27 15:51:46 +01003493 set_sigmask(&blocked);
thsc3b5bc82007-12-02 06:31:25 +00003494
Timothy E Baldwinba412492016-05-12 18:47:35 +01003495 restore_sigcontext(regs, &frame->uc.tuc_mcontext);
thsc3b5bc82007-12-02 06:31:25 +00003496
3497 if (do_sigaltstack(frame_addr +
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003498 offsetof(struct target_rt_sigframe, uc.tuc_stack),
3499 0, get_sp_from_cpustate(regs)) == -EFAULT) {
thsc3b5bc82007-12-02 06:31:25 +00003500 goto badframe;
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003501 }
thsc3b5bc82007-12-02 06:31:25 +00003502
3503 unlock_user_struct(frame, frame_addr, 0);
Timothy E Baldwinba412492016-05-12 18:47:35 +01003504 return -TARGET_QEMU_ESIGRETURN;
thsc3b5bc82007-12-02 06:31:25 +00003505
3506badframe:
3507 unlock_user_struct(frame, frame_addr, 0);
3508 force_sig(TARGET_SIGSEGV);
3509 return 0;
3510}
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003511#elif defined(TARGET_MICROBLAZE)
3512
3513struct target_sigcontext {
3514 struct target_pt_regs regs; /* needs to be first */
3515 uint32_t oldmask;
3516};
3517
Edgar E. Iglesiasb2178702010-07-23 09:30:37 +02003518struct target_stack_t {
3519 abi_ulong ss_sp;
3520 int ss_flags;
3521 unsigned int ss_size;
3522};
3523
3524struct target_ucontext {
Richard Hendersonf711df62010-11-22 14:57:52 -08003525 abi_ulong tuc_flags;
3526 abi_ulong tuc_link;
3527 struct target_stack_t tuc_stack;
3528 struct target_sigcontext tuc_mcontext;
3529 uint32_t tuc_extramask[TARGET_NSIG_WORDS - 1];
Edgar E. Iglesiasb2178702010-07-23 09:30:37 +02003530};
3531
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003532/* Signal frames. */
3533struct target_signal_frame {
Edgar E. Iglesiasb2178702010-07-23 09:30:37 +02003534 struct target_ucontext uc;
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003535 uint32_t extramask[TARGET_NSIG_WORDS - 1];
3536 uint32_t tramp[2];
3537};
3538
3539struct rt_signal_frame {
Richard W.M. Jones02d2bd52012-07-05 03:32:44 +00003540 siginfo_t info;
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003541 struct ucontext uc;
3542 uint32_t tramp[2];
3543};
3544
Andreas Färber05390242012-02-25 03:37:53 +01003545static void setup_sigcontext(struct target_sigcontext *sc, CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003546{
3547 __put_user(env->regs[0], &sc->regs.r0);
3548 __put_user(env->regs[1], &sc->regs.r1);
3549 __put_user(env->regs[2], &sc->regs.r2);
3550 __put_user(env->regs[3], &sc->regs.r3);
3551 __put_user(env->regs[4], &sc->regs.r4);
3552 __put_user(env->regs[5], &sc->regs.r5);
3553 __put_user(env->regs[6], &sc->regs.r6);
3554 __put_user(env->regs[7], &sc->regs.r7);
3555 __put_user(env->regs[8], &sc->regs.r8);
3556 __put_user(env->regs[9], &sc->regs.r9);
3557 __put_user(env->regs[10], &sc->regs.r10);
3558 __put_user(env->regs[11], &sc->regs.r11);
3559 __put_user(env->regs[12], &sc->regs.r12);
3560 __put_user(env->regs[13], &sc->regs.r13);
3561 __put_user(env->regs[14], &sc->regs.r14);
3562 __put_user(env->regs[15], &sc->regs.r15);
3563 __put_user(env->regs[16], &sc->regs.r16);
3564 __put_user(env->regs[17], &sc->regs.r17);
3565 __put_user(env->regs[18], &sc->regs.r18);
3566 __put_user(env->regs[19], &sc->regs.r19);
3567 __put_user(env->regs[20], &sc->regs.r20);
3568 __put_user(env->regs[21], &sc->regs.r21);
3569 __put_user(env->regs[22], &sc->regs.r22);
3570 __put_user(env->regs[23], &sc->regs.r23);
3571 __put_user(env->regs[24], &sc->regs.r24);
3572 __put_user(env->regs[25], &sc->regs.r25);
3573 __put_user(env->regs[26], &sc->regs.r26);
3574 __put_user(env->regs[27], &sc->regs.r27);
3575 __put_user(env->regs[28], &sc->regs.r28);
3576 __put_user(env->regs[29], &sc->regs.r29);
3577 __put_user(env->regs[30], &sc->regs.r30);
3578 __put_user(env->regs[31], &sc->regs.r31);
3579 __put_user(env->sregs[SR_PC], &sc->regs.pc);
3580}
3581
Andreas Färber05390242012-02-25 03:37:53 +01003582static void restore_sigcontext(struct target_sigcontext *sc, CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003583{
3584 __get_user(env->regs[0], &sc->regs.r0);
3585 __get_user(env->regs[1], &sc->regs.r1);
3586 __get_user(env->regs[2], &sc->regs.r2);
3587 __get_user(env->regs[3], &sc->regs.r3);
3588 __get_user(env->regs[4], &sc->regs.r4);
3589 __get_user(env->regs[5], &sc->regs.r5);
3590 __get_user(env->regs[6], &sc->regs.r6);
3591 __get_user(env->regs[7], &sc->regs.r7);
3592 __get_user(env->regs[8], &sc->regs.r8);
3593 __get_user(env->regs[9], &sc->regs.r9);
3594 __get_user(env->regs[10], &sc->regs.r10);
3595 __get_user(env->regs[11], &sc->regs.r11);
3596 __get_user(env->regs[12], &sc->regs.r12);
3597 __get_user(env->regs[13], &sc->regs.r13);
3598 __get_user(env->regs[14], &sc->regs.r14);
3599 __get_user(env->regs[15], &sc->regs.r15);
3600 __get_user(env->regs[16], &sc->regs.r16);
3601 __get_user(env->regs[17], &sc->regs.r17);
3602 __get_user(env->regs[18], &sc->regs.r18);
3603 __get_user(env->regs[19], &sc->regs.r19);
3604 __get_user(env->regs[20], &sc->regs.r20);
3605 __get_user(env->regs[21], &sc->regs.r21);
3606 __get_user(env->regs[22], &sc->regs.r22);
3607 __get_user(env->regs[23], &sc->regs.r23);
3608 __get_user(env->regs[24], &sc->regs.r24);
3609 __get_user(env->regs[25], &sc->regs.r25);
3610 __get_user(env->regs[26], &sc->regs.r26);
3611 __get_user(env->regs[27], &sc->regs.r27);
3612 __get_user(env->regs[28], &sc->regs.r28);
3613 __get_user(env->regs[29], &sc->regs.r29);
3614 __get_user(env->regs[30], &sc->regs.r30);
3615 __get_user(env->regs[31], &sc->regs.r31);
3616 __get_user(env->sregs[SR_PC], &sc->regs.pc);
3617}
3618
3619static abi_ulong get_sigframe(struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01003620 CPUMBState *env, int frame_size)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003621{
3622 abi_ulong sp = env->regs[1];
3623
Riku Voipiob545f632014-07-15 17:01:55 +03003624 if ((ka->sa_flags & TARGET_SA_ONSTACK) != 0 && !on_sig_stack(sp)) {
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003625 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
Riku Voipiob545f632014-07-15 17:01:55 +03003626 }
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003627
3628 return ((sp - frame_size) & -8UL);
3629}
3630
3631static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01003632 target_sigset_t *set, CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003633{
3634 struct target_signal_frame *frame;
3635 abi_ulong frame_addr;
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003636 int i;
3637
3638 frame_addr = get_sigframe(ka, env, sizeof *frame);
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01003639 trace_user_setup_frame(env, frame_addr);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003640 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
3641 goto badframe;
3642
3643 /* Save the mask. */
Riku Voipio1d8b5122014-04-23 10:26:05 +03003644 __put_user(set->sig[0], &frame->uc.tuc_mcontext.oldmask);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003645
3646 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
Riku Voipio0188fad2014-04-23 13:34:15 +03003647 __put_user(set->sig[i], &frame->extramask[i - 1]);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003648 }
3649
Richard Hendersonf711df62010-11-22 14:57:52 -08003650 setup_sigcontext(&frame->uc.tuc_mcontext, env);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003651
3652 /* Set up to return from userspace. If provided, use a stub
3653 already in userspace. */
3654 /* minus 8 is offset to cater for "rtsd r15,8" offset */
3655 if (ka->sa_flags & TARGET_SA_RESTORER) {
3656 env->regs[15] = ((unsigned long)ka->sa_restorer)-8;
3657 } else {
3658 uint32_t t;
3659 /* Note, these encodings are _big endian_! */
3660 /* addi r12, r0, __NR_sigreturn */
3661 t = 0x31800000UL | TARGET_NR_sigreturn;
Riku Voipio1d8b5122014-04-23 10:26:05 +03003662 __put_user(t, frame->tramp + 0);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003663 /* brki r14, 0x8 */
3664 t = 0xb9cc0008UL;
Riku Voipio1d8b5122014-04-23 10:26:05 +03003665 __put_user(t, frame->tramp + 1);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003666
3667 /* Return from sighandler will jump to the tramp.
3668 Negative 8 offset because return is rtsd r15, 8 */
Chen Gang166c97e2016-03-29 22:13:45 +08003669 env->regs[15] = frame_addr + offsetof(struct target_signal_frame, tramp)
3670 - 8;
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003671 }
3672
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003673 /* Set up registers for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003674 env->regs[1] = frame_addr;
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003675 /* Signal handler args: */
3676 env->regs[5] = sig; /* Arg 0: signum */
Edgar E. Iglesias187b4e02010-07-15 15:32:51 +02003677 env->regs[6] = 0;
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003678 /* arg 1: sigcontext */
3679 env->regs[7] = frame_addr += offsetof(typeof(*frame), uc);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003680
3681 /* Offset of 4 to handle microblaze rtid r14, 0 */
3682 env->sregs[SR_PC] = (unsigned long)ka->_sa_handler;
3683
3684 unlock_user_struct(frame, frame_addr, 1);
3685 return;
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003686badframe:
Peter Maydell09391662016-07-28 16:44:47 +01003687 force_sigsegv(sig);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003688}
3689
3690static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05003691 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01003692 target_sigset_t *set, CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003693{
3694 fprintf(stderr, "Microblaze setup_rt_frame: not implemented\n");
3695}
3696
Andreas Färber05390242012-02-25 03:37:53 +01003697long do_sigreturn(CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003698{
3699 struct target_signal_frame *frame;
3700 abi_ulong frame_addr;
Anthony Liguoric227f092009-10-01 16:12:16 -05003701 target_sigset_t target_set;
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003702 sigset_t set;
3703 int i;
3704
3705 frame_addr = env->regs[R_SP];
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01003706 trace_user_do_sigreturn(env, frame_addr);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003707 /* Make sure the guest isn't playing games. */
3708 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 1))
3709 goto badframe;
3710
3711 /* Restore blocked signals */
Riku Voipiof5f601a2014-04-23 13:00:17 +03003712 __get_user(target_set.sig[0], &frame->uc.tuc_mcontext.oldmask);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003713 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003714 __get_user(target_set.sig[i], &frame->extramask[i - 1]);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003715 }
3716 target_to_host_sigset_internal(&set, &target_set);
Peter Maydell9eede5b2016-05-27 15:51:46 +01003717 set_sigmask(&set);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003718
Richard Hendersonf711df62010-11-22 14:57:52 -08003719 restore_sigcontext(&frame->uc.tuc_mcontext, env);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003720 /* We got here through a sigreturn syscall, our path back is via an
3721 rtb insn so setup r14 for that. */
3722 env->regs[14] = env->sregs[SR_PC];
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003723
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003724 unlock_user_struct(frame, frame_addr, 0);
Timothy E Baldwin4134ecf2016-05-12 18:47:44 +01003725 return -TARGET_QEMU_ESIGRETURN;
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003726badframe:
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003727 force_sig(TARGET_SIGSEGV);
3728}
3729
Andreas Färber05390242012-02-25 03:37:53 +01003730long do_rt_sigreturn(CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003731{
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01003732 trace_user_do_rt_sigreturn(env, 0);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003733 fprintf(stderr, "Microblaze do_rt_sigreturn: not implemented\n");
3734 return -TARGET_ENOSYS;
3735}
3736
edgar_iglb6d3abd2008-02-28 11:29:27 +00003737#elif defined(TARGET_CRIS)
3738
3739struct target_sigcontext {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003740 struct target_pt_regs regs; /* needs to be first */
3741 uint32_t oldmask;
3742 uint32_t usp; /* usp before stacking this gunk on it */
edgar_iglb6d3abd2008-02-28 11:29:27 +00003743};
3744
3745/* Signal frames. */
3746struct target_signal_frame {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003747 struct target_sigcontext sc;
3748 uint32_t extramask[TARGET_NSIG_WORDS - 1];
3749 uint16_t retcode[4]; /* Trampoline code. */
edgar_iglb6d3abd2008-02-28 11:29:27 +00003750};
3751
3752struct rt_signal_frame {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003753 siginfo_t *pinfo;
3754 void *puc;
3755 siginfo_t info;
3756 struct ucontext uc;
3757 uint16_t retcode[4]; /* Trampoline code. */
edgar_iglb6d3abd2008-02-28 11:29:27 +00003758};
3759
Andreas Färber05390242012-02-25 03:37:53 +01003760static void setup_sigcontext(struct target_sigcontext *sc, CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003761{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003762 __put_user(env->regs[0], &sc->regs.r0);
3763 __put_user(env->regs[1], &sc->regs.r1);
3764 __put_user(env->regs[2], &sc->regs.r2);
3765 __put_user(env->regs[3], &sc->regs.r3);
3766 __put_user(env->regs[4], &sc->regs.r4);
3767 __put_user(env->regs[5], &sc->regs.r5);
3768 __put_user(env->regs[6], &sc->regs.r6);
3769 __put_user(env->regs[7], &sc->regs.r7);
3770 __put_user(env->regs[8], &sc->regs.r8);
3771 __put_user(env->regs[9], &sc->regs.r9);
3772 __put_user(env->regs[10], &sc->regs.r10);
3773 __put_user(env->regs[11], &sc->regs.r11);
3774 __put_user(env->regs[12], &sc->regs.r12);
3775 __put_user(env->regs[13], &sc->regs.r13);
3776 __put_user(env->regs[14], &sc->usp);
3777 __put_user(env->regs[15], &sc->regs.acr);
3778 __put_user(env->pregs[PR_MOF], &sc->regs.mof);
3779 __put_user(env->pregs[PR_SRP], &sc->regs.srp);
3780 __put_user(env->pc, &sc->regs.erp);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003781}
edgar_igl9664d922008-03-03 22:23:53 +00003782
Andreas Färber05390242012-02-25 03:37:53 +01003783static void restore_sigcontext(struct target_sigcontext *sc, CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003784{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003785 __get_user(env->regs[0], &sc->regs.r0);
3786 __get_user(env->regs[1], &sc->regs.r1);
3787 __get_user(env->regs[2], &sc->regs.r2);
3788 __get_user(env->regs[3], &sc->regs.r3);
3789 __get_user(env->regs[4], &sc->regs.r4);
3790 __get_user(env->regs[5], &sc->regs.r5);
3791 __get_user(env->regs[6], &sc->regs.r6);
3792 __get_user(env->regs[7], &sc->regs.r7);
3793 __get_user(env->regs[8], &sc->regs.r8);
3794 __get_user(env->regs[9], &sc->regs.r9);
3795 __get_user(env->regs[10], &sc->regs.r10);
3796 __get_user(env->regs[11], &sc->regs.r11);
3797 __get_user(env->regs[12], &sc->regs.r12);
3798 __get_user(env->regs[13], &sc->regs.r13);
3799 __get_user(env->regs[14], &sc->usp);
3800 __get_user(env->regs[15], &sc->regs.acr);
3801 __get_user(env->pregs[PR_MOF], &sc->regs.mof);
3802 __get_user(env->pregs[PR_SRP], &sc->regs.srp);
3803 __get_user(env->pc, &sc->regs.erp);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003804}
3805
Andreas Färber05390242012-02-25 03:37:53 +01003806static abi_ulong get_sigframe(CPUCRISState *env, int framesize)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003807{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003808 abi_ulong sp;
3809 /* Align the stack downwards to 4. */
3810 sp = (env->regs[R_SP] & ~3);
3811 return sp - framesize;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003812}
3813
pbrook624f7972008-05-31 16:11:38 +00003814static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01003815 target_sigset_t *set, CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003816{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003817 struct target_signal_frame *frame;
3818 abi_ulong frame_addr;
3819 int i;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003820
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003821 frame_addr = get_sigframe(env, sizeof *frame);
3822 trace_user_setup_frame(env, frame_addr);
3823 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
3824 goto badframe;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003825
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003826 /*
3827 * The CRIS signal return trampoline. A real linux/CRIS kernel doesn't
3828 * use this trampoline anymore but it sets it up for GDB.
3829 * In QEMU, using the trampoline simplifies things a bit so we use it.
3830 *
3831 * This is movu.w __NR_sigreturn, r9; break 13;
3832 */
Riku Voipio1d8b5122014-04-23 10:26:05 +03003833 __put_user(0x9c5f, frame->retcode+0);
3834 __put_user(TARGET_NR_sigreturn,
3835 frame->retcode + 1);
3836 __put_user(0xe93d, frame->retcode + 2);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003837
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003838 /* Save the mask. */
Riku Voipio1d8b5122014-04-23 10:26:05 +03003839 __put_user(set->sig[0], &frame->sc.oldmask);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003840
Riku Voipio0188fad2014-04-23 13:34:15 +03003841 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
3842 __put_user(set->sig[i], &frame->extramask[i - 1]);
3843 }
edgar_iglb6d3abd2008-02-28 11:29:27 +00003844
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003845 setup_sigcontext(&frame->sc, env);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003846
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003847 /* Move the stack and setup the arguments for the handler. */
3848 env->regs[R_SP] = frame_addr;
3849 env->regs[10] = sig;
3850 env->pc = (unsigned long) ka->_sa_handler;
3851 /* Link SRP so the guest returns through the trampoline. */
3852 env->pregs[PR_SRP] = frame_addr + offsetof(typeof(*frame), retcode);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003853
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003854 unlock_user_struct(frame, frame_addr, 1);
3855 return;
3856badframe:
Peter Maydell09391662016-07-28 16:44:47 +01003857 force_sigsegv(sig);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003858}
3859
pbrook624f7972008-05-31 16:11:38 +00003860static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05003861 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01003862 target_sigset_t *set, CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003863{
3864 fprintf(stderr, "CRIS setup_rt_frame: not implemented\n");
3865}
3866
Andreas Färber05390242012-02-25 03:37:53 +01003867long do_sigreturn(CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003868{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003869 struct target_signal_frame *frame;
3870 abi_ulong frame_addr;
3871 target_sigset_t target_set;
3872 sigset_t set;
3873 int i;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003874
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003875 frame_addr = env->regs[R_SP];
3876 trace_user_do_sigreturn(env, frame_addr);
3877 /* Make sure the guest isn't playing games. */
3878 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 1)) {
3879 goto badframe;
3880 }
edgar_iglb6d3abd2008-02-28 11:29:27 +00003881
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003882 /* Restore blocked signals */
Riku Voipiof5f601a2014-04-23 13:00:17 +03003883 __get_user(target_set.sig[0], &frame->sc.oldmask);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003884 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
Riku Voipiof5f601a2014-04-23 13:00:17 +03003885 __get_user(target_set.sig[i], &frame->extramask[i - 1]);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003886 }
3887 target_to_host_sigset_internal(&set, &target_set);
Peter Maydell9eede5b2016-05-27 15:51:46 +01003888 set_sigmask(&set);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003889
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003890 restore_sigcontext(&frame->sc, env);
3891 unlock_user_struct(frame, frame_addr, 0);
Timothy E Baldwin62050862016-05-12 18:47:41 +01003892 return -TARGET_QEMU_ESIGRETURN;
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003893badframe:
3894 force_sig(TARGET_SIGSEGV);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003895}
3896
Andreas Färber05390242012-02-25 03:37:53 +01003897long do_rt_sigreturn(CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003898{
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01003899 trace_user_do_rt_sigreturn(env, 0);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003900 fprintf(stderr, "CRIS do_rt_sigreturn: not implemented\n");
3901 return -TARGET_ENOSYS;
3902}
thsc3b5bc82007-12-02 06:31:25 +00003903
Jia Liud9627832012-07-20 15:50:52 +08003904#elif defined(TARGET_OPENRISC)
3905
3906struct target_sigcontext {
3907 struct target_pt_regs regs;
3908 abi_ulong oldmask;
3909 abi_ulong usp;
3910};
3911
3912struct target_ucontext {
3913 abi_ulong tuc_flags;
3914 abi_ulong tuc_link;
3915 target_stack_t tuc_stack;
3916 struct target_sigcontext tuc_mcontext;
3917 target_sigset_t tuc_sigmask; /* mask last for extensibility */
3918};
3919
3920struct target_rt_sigframe {
3921 abi_ulong pinfo;
3922 uint64_t puc;
3923 struct target_siginfo info;
3924 struct target_sigcontext sc;
3925 struct target_ucontext uc;
3926 unsigned char retcode[16]; /* trampoline code */
3927};
3928
3929/* This is the asm-generic/ucontext.h version */
3930#if 0
3931static int restore_sigcontext(CPUOpenRISCState *regs,
3932 struct target_sigcontext *sc)
3933{
3934 unsigned int err = 0;
3935 unsigned long old_usp;
3936
3937 /* Alwys make any pending restarted system call return -EINTR */
3938 current_thread_info()->restart_block.fn = do_no_restart_syscall;
3939
3940 /* restore the regs from &sc->regs (same as sc, since regs is first)
3941 * (sc is already checked for VERIFY_READ since the sigframe was
3942 * checked in sys_sigreturn previously)
3943 */
3944
3945 if (copy_from_user(regs, &sc, sizeof(struct target_pt_regs))) {
3946 goto badframe;
3947 }
3948
3949 /* make sure the U-flag is set so user-mode cannot fool us */
3950
3951 regs->sr &= ~SR_SM;
3952
3953 /* restore the old USP as it was before we stacked the sc etc.
3954 * (we cannot just pop the sigcontext since we aligned the sp and
3955 * stuff after pushing it)
3956 */
3957
Riku Voipio1d8b5122014-04-23 10:26:05 +03003958 __get_user(old_usp, &sc->usp);
Jia Liud9627832012-07-20 15:50:52 +08003959 phx_signal("old_usp 0x%lx", old_usp);
3960
3961 __PHX__ REALLY /* ??? */
3962 wrusp(old_usp);
3963 regs->gpr[1] = old_usp;
3964
3965 /* TODO: the other ports use regs->orig_XX to disable syscall checks
3966 * after this completes, but we don't use that mechanism. maybe we can
3967 * use it now ?
3968 */
3969
3970 return err;
3971
3972badframe:
3973 return 1;
3974}
3975#endif
3976
3977/* Set up a signal frame. */
3978
Riku Voipio41ecc722014-04-23 11:01:00 +03003979static void setup_sigcontext(struct target_sigcontext *sc,
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003980 CPUOpenRISCState *regs,
3981 unsigned long mask)
Jia Liud9627832012-07-20 15:50:52 +08003982{
Jia Liud9627832012-07-20 15:50:52 +08003983 unsigned long usp = regs->gpr[1];
3984
3985 /* copy the regs. they are first in sc so we can use sc directly */
3986
Riku Voipio1d8b5122014-04-23 10:26:05 +03003987 /*copy_to_user(&sc, regs, sizeof(struct target_pt_regs));*/
Jia Liud9627832012-07-20 15:50:52 +08003988
3989 /* Set the frametype to CRIS_FRAME_NORMAL for the execution of
3990 the signal handler. The frametype will be restored to its previous
3991 value in restore_sigcontext. */
3992 /*regs->frametype = CRIS_FRAME_NORMAL;*/
3993
3994 /* then some other stuff */
Riku Voipio1d8b5122014-04-23 10:26:05 +03003995 __put_user(mask, &sc->oldmask);
Riku Voipio41ecc722014-04-23 11:01:00 +03003996 __put_user(usp, &sc->usp);
Jia Liud9627832012-07-20 15:50:52 +08003997}
3998
3999static inline unsigned long align_sigframe(unsigned long sp)
4000{
Eduardo Habkost9be38592016-06-13 18:57:58 -03004001 return sp & ~3UL;
Jia Liud9627832012-07-20 15:50:52 +08004002}
4003
4004static inline abi_ulong get_sigframe(struct target_sigaction *ka,
4005 CPUOpenRISCState *regs,
4006 size_t frame_size)
4007{
4008 unsigned long sp = regs->gpr[1];
4009 int onsigstack = on_sig_stack(sp);
4010
4011 /* redzone */
4012 /* This is the X/Open sanctioned signal stack switching. */
Riku Voipiob545f632014-07-15 17:01:55 +03004013 if ((ka->sa_flags & TARGET_SA_ONSTACK) != 0 && !onsigstack) {
Jia Liud9627832012-07-20 15:50:52 +08004014 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
4015 }
4016
4017 sp = align_sigframe(sp - frame_size);
4018
4019 /*
4020 * If we are on the alternate signal stack and would overflow it, don't.
4021 * Return an always-bogus address instead so we will die with SIGSEGV.
4022 */
4023
4024 if (onsigstack && !likely(on_sig_stack(sp))) {
4025 return -1L;
4026 }
4027
4028 return sp;
4029}
4030
Jia Liud9627832012-07-20 15:50:52 +08004031static void setup_rt_frame(int sig, struct target_sigaction *ka,
4032 target_siginfo_t *info,
4033 target_sigset_t *set, CPUOpenRISCState *env)
4034{
4035 int err = 0;
4036 abi_ulong frame_addr;
4037 unsigned long return_ip;
4038 struct target_rt_sigframe *frame;
4039 abi_ulong info_addr, uc_addr;
4040
Jia Liud9627832012-07-20 15:50:52 +08004041 frame_addr = get_sigframe(ka, env, sizeof(*frame));
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01004042 trace_user_setup_rt_frame(env, frame_addr);
Jia Liud9627832012-07-20 15:50:52 +08004043 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
4044 goto give_sigsegv;
4045 }
4046
4047 info_addr = frame_addr + offsetof(struct target_rt_sigframe, info);
Riku Voipio1d8b5122014-04-23 10:26:05 +03004048 __put_user(info_addr, &frame->pinfo);
Jia Liud9627832012-07-20 15:50:52 +08004049 uc_addr = frame_addr + offsetof(struct target_rt_sigframe, uc);
Riku Voipio1d8b5122014-04-23 10:26:05 +03004050 __put_user(uc_addr, &frame->puc);
Jia Liud9627832012-07-20 15:50:52 +08004051
4052 if (ka->sa_flags & SA_SIGINFO) {
Peter Maydellf6c7a052015-01-08 12:19:48 +00004053 tswap_siginfo(&frame->info, info);
Jia Liud9627832012-07-20 15:50:52 +08004054 }
4055
4056 /*err |= __clear_user(&frame->uc, offsetof(struct ucontext, uc_mcontext));*/
Riku Voipio1d8b5122014-04-23 10:26:05 +03004057 __put_user(0, &frame->uc.tuc_flags);
4058 __put_user(0, &frame->uc.tuc_link);
4059 __put_user(target_sigaltstack_used.ss_sp,
4060 &frame->uc.tuc_stack.ss_sp);
4061 __put_user(sas_ss_flags(env->gpr[1]), &frame->uc.tuc_stack.ss_flags);
4062 __put_user(target_sigaltstack_used.ss_size,
4063 &frame->uc.tuc_stack.ss_size);
Riku Voipio41ecc722014-04-23 11:01:00 +03004064 setup_sigcontext(&frame->sc, env, set->sig[0]);
Jia Liud9627832012-07-20 15:50:52 +08004065
4066 /*err |= copy_to_user(frame->uc.tuc_sigmask, set, sizeof(*set));*/
4067
Jia Liud9627832012-07-20 15:50:52 +08004068 /* trampoline - the desired return ip is the retcode itself */
4069 return_ip = (unsigned long)&frame->retcode;
4070 /* This is l.ori r11,r0,__NR_sigreturn, l.sys 1 */
Riku Voipio1d8b5122014-04-23 10:26:05 +03004071 __put_user(0xa960, (short *)(frame->retcode + 0));
4072 __put_user(TARGET_NR_rt_sigreturn, (short *)(frame->retcode + 2));
4073 __put_user(0x20000001, (unsigned long *)(frame->retcode + 4));
4074 __put_user(0x15000000, (unsigned long *)(frame->retcode + 8));
Jia Liud9627832012-07-20 15:50:52 +08004075
4076 if (err) {
4077 goto give_sigsegv;
4078 }
4079
4080 /* TODO what is the current->exec_domain stuff and invmap ? */
4081
4082 /* Set up registers for signal handler */
4083 env->pc = (unsigned long)ka->_sa_handler; /* what we enter NOW */
4084 env->gpr[9] = (unsigned long)return_ip; /* what we enter LATER */
4085 env->gpr[3] = (unsigned long)sig; /* arg 1: signo */
4086 env->gpr[4] = (unsigned long)&frame->info; /* arg 2: (siginfo_t*) */
4087 env->gpr[5] = (unsigned long)&frame->uc; /* arg 3: ucontext */
4088
4089 /* actually move the usp to reflect the stacked frame */
4090 env->gpr[1] = (unsigned long)frame;
4091
4092 return;
4093
4094give_sigsegv:
4095 unlock_user_struct(frame, frame_addr, 1);
Peter Maydell09391662016-07-28 16:44:47 +01004096 force_sigsegv(sig);
Jia Liud9627832012-07-20 15:50:52 +08004097}
4098
4099long do_sigreturn(CPUOpenRISCState *env)
4100{
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01004101 trace_user_do_sigreturn(env, 0);
4102 fprintf(stderr, "do_sigreturn: not implemented\n");
Jia Liud9627832012-07-20 15:50:52 +08004103 return -TARGET_ENOSYS;
4104}
4105
4106long do_rt_sigreturn(CPUOpenRISCState *env)
4107{
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01004108 trace_user_do_rt_sigreturn(env, 0);
4109 fprintf(stderr, "do_rt_sigreturn: not implemented\n");
Jia Liud9627832012-07-20 15:50:52 +08004110 return -TARGET_ENOSYS;
4111}
4112/* TARGET_OPENRISC */
4113
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004114#elif defined(TARGET_S390X)
4115
4116#define __NUM_GPRS 16
4117#define __NUM_FPRS 16
4118#define __NUM_ACRS 16
4119
4120#define S390_SYSCALL_SIZE 2
4121#define __SIGNAL_FRAMESIZE 160 /* FIXME: 31-bit mode -> 96 */
4122
4123#define _SIGCONTEXT_NSIG 64
4124#define _SIGCONTEXT_NSIG_BPW 64 /* FIXME: 31-bit mode -> 32 */
4125#define _SIGCONTEXT_NSIG_WORDS (_SIGCONTEXT_NSIG / _SIGCONTEXT_NSIG_BPW)
4126#define _SIGMASK_COPY_SIZE (sizeof(unsigned long)*_SIGCONTEXT_NSIG_WORDS)
4127#define PSW_ADDR_AMODE 0x0000000000000000UL /* 0x80000000UL for 31-bit */
4128#define S390_SYSCALL_OPCODE ((uint16_t)0x0a00)
4129
4130typedef struct {
4131 target_psw_t psw;
4132 target_ulong gprs[__NUM_GPRS];
4133 unsigned int acrs[__NUM_ACRS];
4134} target_s390_regs_common;
4135
4136typedef struct {
4137 unsigned int fpc;
4138 double fprs[__NUM_FPRS];
4139} target_s390_fp_regs;
4140
4141typedef struct {
4142 target_s390_regs_common regs;
4143 target_s390_fp_regs fpregs;
4144} target_sigregs;
4145
4146struct target_sigcontext {
4147 target_ulong oldmask[_SIGCONTEXT_NSIG_WORDS];
4148 target_sigregs *sregs;
4149};
4150
4151typedef struct {
4152 uint8_t callee_used_stack[__SIGNAL_FRAMESIZE];
4153 struct target_sigcontext sc;
4154 target_sigregs sregs;
4155 int signo;
4156 uint8_t retcode[S390_SYSCALL_SIZE];
4157} sigframe;
4158
4159struct target_ucontext {
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004160 target_ulong tuc_flags;
4161 struct target_ucontext *tuc_link;
4162 target_stack_t tuc_stack;
4163 target_sigregs tuc_mcontext;
4164 target_sigset_t tuc_sigmask; /* mask last for extensibility */
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004165};
4166
4167typedef struct {
4168 uint8_t callee_used_stack[__SIGNAL_FRAMESIZE];
4169 uint8_t retcode[S390_SYSCALL_SIZE];
4170 struct target_siginfo info;
4171 struct target_ucontext uc;
4172} rt_sigframe;
4173
4174static inline abi_ulong
Andreas Färber05390242012-02-25 03:37:53 +01004175get_sigframe(struct target_sigaction *ka, CPUS390XState *env, size_t frame_size)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004176{
4177 abi_ulong sp;
4178
4179 /* Default to using normal stack */
4180 sp = env->regs[15];
4181
4182 /* This is the X/Open sanctioned signal stack switching. */
4183 if (ka->sa_flags & TARGET_SA_ONSTACK) {
4184 if (!sas_ss_flags(sp)) {
4185 sp = target_sigaltstack_used.ss_sp +
4186 target_sigaltstack_used.ss_size;
4187 }
4188 }
4189
4190 /* This is the legacy signal stack switching. */
4191 else if (/* FIXME !user_mode(regs) */ 0 &&
4192 !(ka->sa_flags & TARGET_SA_RESTORER) &&
4193 ka->sa_restorer) {
4194 sp = (abi_ulong) ka->sa_restorer;
4195 }
4196
4197 return (sp - frame_size) & -8ul;
4198}
4199
Andreas Färber05390242012-02-25 03:37:53 +01004200static void save_sigregs(CPUS390XState *env, target_sigregs *sregs)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004201{
4202 int i;
4203 //save_access_regs(current->thread.acrs); FIXME
4204
4205 /* Copy a 'clean' PSW mask to the user to avoid leaking
4206 information about whether PER is currently on. */
4207 __put_user(env->psw.mask, &sregs->regs.psw.mask);
4208 __put_user(env->psw.addr, &sregs->regs.psw.addr);
4209 for (i = 0; i < 16; i++) {
4210 __put_user(env->regs[i], &sregs->regs.gprs[i]);
4211 }
4212 for (i = 0; i < 16; i++) {
4213 __put_user(env->aregs[i], &sregs->regs.acrs[i]);
4214 }
4215 /*
4216 * We have to store the fp registers to current->thread.fp_regs
4217 * to merge them with the emulated registers.
4218 */
4219 //save_fp_regs(&current->thread.fp_regs); FIXME
4220 for (i = 0; i < 16; i++) {
Eric Farmanc498d8e2015-05-07 14:35:44 -04004221 __put_user(get_freg(env, i)->ll, &sregs->fpregs.fprs[i]);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004222 }
4223}
4224
4225static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01004226 target_sigset_t *set, CPUS390XState *env)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004227{
4228 sigframe *frame;
4229 abi_ulong frame_addr;
4230
4231 frame_addr = get_sigframe(ka, env, sizeof(*frame));
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01004232 trace_user_setup_frame(env, frame_addr);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004233 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01004234 goto give_sigsegv;
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004235 }
4236
Riku Voipio0188fad2014-04-23 13:34:15 +03004237 __put_user(set->sig[0], &frame->sc.oldmask[0]);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004238
4239 save_sigregs(env, &frame->sregs);
4240
4241 __put_user((abi_ulong)(unsigned long)&frame->sregs,
4242 (abi_ulong *)&frame->sc.sregs);
4243
4244 /* Set up to return from userspace. If provided, use a stub
4245 already in userspace. */
4246 if (ka->sa_flags & TARGET_SA_RESTORER) {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01004247 env->regs[14] = (unsigned long)
4248 ka->sa_restorer | PSW_ADDR_AMODE;
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004249 } else {
Chen Gang5b1d59d2016-05-24 14:54:32 +03004250 env->regs[14] = (frame_addr + offsetof(sigframe, retcode))
4251 | PSW_ADDR_AMODE;
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01004252 __put_user(S390_SYSCALL_OPCODE | TARGET_NR_sigreturn,
4253 (uint16_t *)(frame->retcode));
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004254 }
4255
4256 /* Set up backchain. */
Riku Voipio0188fad2014-04-23 13:34:15 +03004257 __put_user(env->regs[15], (abi_ulong *) frame);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004258
4259 /* Set up registers for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02004260 env->regs[15] = frame_addr;
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004261 env->psw.addr = (target_ulong) ka->_sa_handler | PSW_ADDR_AMODE;
4262
4263 env->regs[2] = sig; //map_signal(sig);
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02004264 env->regs[3] = frame_addr += offsetof(typeof(*frame), sc);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004265
4266 /* We forgot to include these in the sigcontext.
4267 To avoid breaking binary compatibility, they are passed as args. */
4268 env->regs[4] = 0; // FIXME: no clue... current->thread.trap_no;
4269 env->regs[5] = 0; // FIXME: no clue... current->thread.prot_addr;
4270
4271 /* Place signal number on stack to allow backtrace from handler. */
Laurent Vivierc1bc91c2016-06-15 18:14:32 +02004272 __put_user(env->regs[2], &frame->signo);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004273 unlock_user_struct(frame, frame_addr, 1);
4274 return;
4275
4276give_sigsegv:
Peter Maydell09391662016-07-28 16:44:47 +01004277 force_sigsegv(sig);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004278}
4279
4280static void setup_rt_frame(int sig, struct target_sigaction *ka,
4281 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01004282 target_sigset_t *set, CPUS390XState *env)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004283{
4284 int i;
4285 rt_sigframe *frame;
4286 abi_ulong frame_addr;
4287
4288 frame_addr = get_sigframe(ka, env, sizeof *frame);
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01004289 trace_user_setup_rt_frame(env, frame_addr);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004290 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
4291 goto give_sigsegv;
4292 }
4293
Peter Maydellf6c7a052015-01-08 12:19:48 +00004294 tswap_siginfo(&frame->info, info);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004295
4296 /* Create the ucontext. */
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004297 __put_user(0, &frame->uc.tuc_flags);
4298 __put_user((abi_ulong)0, (abi_ulong *)&frame->uc.tuc_link);
4299 __put_user(target_sigaltstack_used.ss_sp, &frame->uc.tuc_stack.ss_sp);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004300 __put_user(sas_ss_flags(get_sp_from_cpustate(env)),
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01004301 &frame->uc.tuc_stack.ss_flags);
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004302 __put_user(target_sigaltstack_used.ss_size, &frame->uc.tuc_stack.ss_size);
4303 save_sigregs(env, &frame->uc.tuc_mcontext);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004304 for (i = 0; i < TARGET_NSIG_WORDS; i++) {
4305 __put_user((abi_ulong)set->sig[i],
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01004306 (abi_ulong *)&frame->uc.tuc_sigmask.sig[i]);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004307 }
4308
4309 /* Set up to return from userspace. If provided, use a stub
4310 already in userspace. */
4311 if (ka->sa_flags & TARGET_SA_RESTORER) {
4312 env->regs[14] = (unsigned long) ka->sa_restorer | PSW_ADDR_AMODE;
4313 } else {
4314 env->regs[14] = (unsigned long) frame->retcode | PSW_ADDR_AMODE;
Riku Voipio0188fad2014-04-23 13:34:15 +03004315 __put_user(S390_SYSCALL_OPCODE | TARGET_NR_rt_sigreturn,
4316 (uint16_t *)(frame->retcode));
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004317 }
4318
4319 /* Set up backchain. */
Riku Voipio0188fad2014-04-23 13:34:15 +03004320 __put_user(env->regs[15], (abi_ulong *) frame);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004321
4322 /* Set up registers for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02004323 env->regs[15] = frame_addr;
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004324 env->psw.addr = (target_ulong) ka->_sa_handler | PSW_ADDR_AMODE;
4325
4326 env->regs[2] = sig; //map_signal(sig);
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02004327 env->regs[3] = frame_addr + offsetof(typeof(*frame), info);
4328 env->regs[4] = frame_addr + offsetof(typeof(*frame), uc);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004329 return;
4330
4331give_sigsegv:
Peter Maydell09391662016-07-28 16:44:47 +01004332 force_sigsegv(sig);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004333}
4334
4335static int
Andreas Färber05390242012-02-25 03:37:53 +01004336restore_sigregs(CPUS390XState *env, target_sigregs *sc)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004337{
4338 int err = 0;
4339 int i;
4340
4341 for (i = 0; i < 16; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03004342 __get_user(env->regs[i], &sc->regs.gprs[i]);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004343 }
4344
Riku Voipio1d8b5122014-04-23 10:26:05 +03004345 __get_user(env->psw.mask, &sc->regs.psw.mask);
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01004346 trace_user_s390x_restore_sigregs(env, (unsigned long long)sc->regs.psw.addr,
4347 (unsigned long long)env->psw.addr);
Riku Voipio1d8b5122014-04-23 10:26:05 +03004348 __get_user(env->psw.addr, &sc->regs.psw.addr);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004349 /* FIXME: 31-bit -> | PSW_ADDR_AMODE */
4350
4351 for (i = 0; i < 16; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03004352 __get_user(env->aregs[i], &sc->regs.acrs[i]);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004353 }
4354 for (i = 0; i < 16; i++) {
Eric Farmanc498d8e2015-05-07 14:35:44 -04004355 __get_user(get_freg(env, i)->ll, &sc->fpregs.fprs[i]);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004356 }
4357
4358 return err;
4359}
4360
Andreas Färber05390242012-02-25 03:37:53 +01004361long do_sigreturn(CPUS390XState *env)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004362{
4363 sigframe *frame;
4364 abi_ulong frame_addr = env->regs[15];
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004365 target_sigset_t target_set;
4366 sigset_t set;
4367
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01004368 trace_user_do_sigreturn(env, frame_addr);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004369 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
4370 goto badframe;
4371 }
Riku Voipiof5f601a2014-04-23 13:00:17 +03004372 __get_user(target_set.sig[0], &frame->sc.oldmask[0]);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004373
4374 target_to_host_sigset_internal(&set, &target_set);
Peter Maydell9eede5b2016-05-27 15:51:46 +01004375 set_sigmask(&set); /* ~_BLOCKABLE? */
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004376
4377 if (restore_sigregs(env, &frame->sregs)) {
4378 goto badframe;
4379 }
4380
4381 unlock_user_struct(frame, frame_addr, 0);
Timothy E Baldwin47405ab2016-05-12 18:47:40 +01004382 return -TARGET_QEMU_ESIGRETURN;
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004383
4384badframe:
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004385 force_sig(TARGET_SIGSEGV);
4386 return 0;
4387}
4388
Andreas Färber05390242012-02-25 03:37:53 +01004389long do_rt_sigreturn(CPUS390XState *env)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004390{
4391 rt_sigframe *frame;
4392 abi_ulong frame_addr = env->regs[15];
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004393 sigset_t set;
4394
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01004395 trace_user_do_rt_sigreturn(env, frame_addr);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004396 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
4397 goto badframe;
4398 }
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004399 target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004400
Peter Maydell9eede5b2016-05-27 15:51:46 +01004401 set_sigmask(&set); /* ~_BLOCKABLE? */
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004402
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004403 if (restore_sigregs(env, &frame->uc.tuc_mcontext)) {
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004404 goto badframe;
4405 }
4406
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004407 if (do_sigaltstack(frame_addr + offsetof(rt_sigframe, uc.tuc_stack), 0,
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004408 get_sp_from_cpustate(env)) == -EFAULT) {
4409 goto badframe;
4410 }
4411 unlock_user_struct(frame, frame_addr, 0);
Timothy E Baldwin47405ab2016-05-12 18:47:40 +01004412 return -TARGET_QEMU_ESIGRETURN;
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004413
4414badframe:
4415 unlock_user_struct(frame, frame_addr, 0);
4416 force_sig(TARGET_SIGSEGV);
4417 return 0;
4418}
4419
Tom Musta61e75fe2014-06-30 08:13:38 -05004420#elif defined(TARGET_PPC)
Nathan Froydbcd49332009-05-12 19:13:18 -07004421
4422/* Size of dummy stack frame allocated when calling signal handler.
4423 See arch/powerpc/include/asm/ptrace.h. */
4424#if defined(TARGET_PPC64)
4425#define SIGNAL_FRAMESIZE 128
4426#else
4427#define SIGNAL_FRAMESIZE 64
4428#endif
4429
Tom Musta61e75fe2014-06-30 08:13:38 -05004430/* See arch/powerpc/include/asm/ucontext.h. Only used for 32-bit PPC;
4431 on 64-bit PPC, sigcontext and mcontext are one and the same. */
4432struct target_mcontext {
4433 target_ulong mc_gregs[48];
4434 /* Includes fpscr. */
4435 uint64_t mc_fregs[33];
4436 target_ulong mc_pad[2];
4437 /* We need to handle Altivec and SPE at the same time, which no
4438 kernel needs to do. Fortunately, the kernel defines this bit to
4439 be Altivec-register-large all the time, rather than trying to
4440 twiddle it based on the specific platform. */
4441 union {
4442 /* SPE vector registers. One extra for SPEFSCR. */
4443 uint32_t spe[33];
4444 /* Altivec vector registers. The packing of VSCR and VRSAVE
4445 varies depending on whether we're PPC64 or not: PPC64 splits
4446 them apart; PPC32 stuffs them together. */
4447#if defined(TARGET_PPC64)
4448#define QEMU_NVRREG 34
4449#else
4450#define QEMU_NVRREG 33
4451#endif
4452 ppc_avr_t altivec[QEMU_NVRREG];
4453#undef QEMU_NVRREG
4454 } mc_vregs __attribute__((__aligned__(16)));
4455};
4456
Nathan Froydbcd49332009-05-12 19:13:18 -07004457/* See arch/powerpc/include/asm/sigcontext.h. */
4458struct target_sigcontext {
4459 target_ulong _unused[4];
4460 int32_t signal;
4461#if defined(TARGET_PPC64)
4462 int32_t pad0;
4463#endif
4464 target_ulong handler;
4465 target_ulong oldmask;
4466 target_ulong regs; /* struct pt_regs __user * */
Tom Musta61e75fe2014-06-30 08:13:38 -05004467#if defined(TARGET_PPC64)
4468 struct target_mcontext mcontext;
4469#endif
Nathan Froydbcd49332009-05-12 19:13:18 -07004470};
4471
4472/* Indices for target_mcontext.mc_gregs, below.
4473 See arch/powerpc/include/asm/ptrace.h for details. */
4474enum {
4475 TARGET_PT_R0 = 0,
4476 TARGET_PT_R1 = 1,
4477 TARGET_PT_R2 = 2,
4478 TARGET_PT_R3 = 3,
4479 TARGET_PT_R4 = 4,
4480 TARGET_PT_R5 = 5,
4481 TARGET_PT_R6 = 6,
4482 TARGET_PT_R7 = 7,
4483 TARGET_PT_R8 = 8,
4484 TARGET_PT_R9 = 9,
4485 TARGET_PT_R10 = 10,
4486 TARGET_PT_R11 = 11,
4487 TARGET_PT_R12 = 12,
4488 TARGET_PT_R13 = 13,
4489 TARGET_PT_R14 = 14,
4490 TARGET_PT_R15 = 15,
4491 TARGET_PT_R16 = 16,
4492 TARGET_PT_R17 = 17,
4493 TARGET_PT_R18 = 18,
4494 TARGET_PT_R19 = 19,
4495 TARGET_PT_R20 = 20,
4496 TARGET_PT_R21 = 21,
4497 TARGET_PT_R22 = 22,
4498 TARGET_PT_R23 = 23,
4499 TARGET_PT_R24 = 24,
4500 TARGET_PT_R25 = 25,
4501 TARGET_PT_R26 = 26,
4502 TARGET_PT_R27 = 27,
4503 TARGET_PT_R28 = 28,
4504 TARGET_PT_R29 = 29,
4505 TARGET_PT_R30 = 30,
4506 TARGET_PT_R31 = 31,
4507 TARGET_PT_NIP = 32,
4508 TARGET_PT_MSR = 33,
4509 TARGET_PT_ORIG_R3 = 34,
4510 TARGET_PT_CTR = 35,
4511 TARGET_PT_LNK = 36,
4512 TARGET_PT_XER = 37,
4513 TARGET_PT_CCR = 38,
4514 /* Yes, there are two registers with #39. One is 64-bit only. */
4515 TARGET_PT_MQ = 39,
4516 TARGET_PT_SOFTE = 39,
4517 TARGET_PT_TRAP = 40,
4518 TARGET_PT_DAR = 41,
4519 TARGET_PT_DSISR = 42,
4520 TARGET_PT_RESULT = 43,
4521 TARGET_PT_REGS_COUNT = 44
4522};
4523
Nathan Froydbcd49332009-05-12 19:13:18 -07004524
4525struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02004526 target_ulong tuc_flags;
4527 target_ulong tuc_link; /* struct ucontext __user * */
4528 struct target_sigaltstack tuc_stack;
Nathan Froydbcd49332009-05-12 19:13:18 -07004529#if !defined(TARGET_PPC64)
Aurelien Jarno60e99242010-03-29 02:12:51 +02004530 int32_t tuc_pad[7];
4531 target_ulong tuc_regs; /* struct mcontext __user *
Nathan Froydbcd49332009-05-12 19:13:18 -07004532 points to uc_mcontext field */
4533#endif
Aurelien Jarno60e99242010-03-29 02:12:51 +02004534 target_sigset_t tuc_sigmask;
Nathan Froydbcd49332009-05-12 19:13:18 -07004535#if defined(TARGET_PPC64)
Anthony Liguoric227f092009-10-01 16:12:16 -05004536 target_sigset_t unused[15]; /* Allow for uc_sigmask growth */
Tom Musta61e75fe2014-06-30 08:13:38 -05004537 struct target_sigcontext tuc_sigcontext;
Nathan Froydbcd49332009-05-12 19:13:18 -07004538#else
Aurelien Jarno60e99242010-03-29 02:12:51 +02004539 int32_t tuc_maskext[30];
4540 int32_t tuc_pad2[3];
4541 struct target_mcontext tuc_mcontext;
Nathan Froydbcd49332009-05-12 19:13:18 -07004542#endif
4543};
4544
4545/* See arch/powerpc/kernel/signal_32.c. */
4546struct target_sigframe {
4547 struct target_sigcontext sctx;
4548 struct target_mcontext mctx;
4549 int32_t abigap[56];
4550};
4551
Tom Musta61e75fe2014-06-30 08:13:38 -05004552#if defined(TARGET_PPC64)
4553
4554#define TARGET_TRAMP_SIZE 6
4555
4556struct target_rt_sigframe {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01004557 /* sys_rt_sigreturn requires the ucontext be the first field */
4558 struct target_ucontext uc;
4559 target_ulong _unused[2];
4560 uint32_t trampoline[TARGET_TRAMP_SIZE];
4561 target_ulong pinfo; /* struct siginfo __user * */
4562 target_ulong puc; /* void __user * */
4563 struct target_siginfo info;
4564 /* 64 bit ABI allows for 288 bytes below sp before decrementing it. */
4565 char abigap[288];
Tom Musta61e75fe2014-06-30 08:13:38 -05004566} __attribute__((aligned(16)));
4567
4568#else
4569
Nathan Froydbcd49332009-05-12 19:13:18 -07004570struct target_rt_sigframe {
4571 struct target_siginfo info;
4572 struct target_ucontext uc;
4573 int32_t abigap[56];
4574};
4575
Tom Musta61e75fe2014-06-30 08:13:38 -05004576#endif
4577
Tom Musta8d6ab332014-06-30 08:13:39 -05004578#if defined(TARGET_PPC64)
4579
4580struct target_func_ptr {
4581 target_ulong entry;
4582 target_ulong toc;
4583};
4584
4585#endif
4586
Nathan Froydbcd49332009-05-12 19:13:18 -07004587/* We use the mc_pad field for the signal return trampoline. */
4588#define tramp mc_pad
4589
4590/* See arch/powerpc/kernel/signal.c. */
4591static target_ulong get_sigframe(struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01004592 CPUPPCState *env,
Nathan Froydbcd49332009-05-12 19:13:18 -07004593 int frame_size)
4594{
Eduardo Habkost9be38592016-06-13 18:57:58 -03004595 target_ulong oldsp;
Nathan Froydbcd49332009-05-12 19:13:18 -07004596
4597 oldsp = env->gpr[1];
4598
4599 if ((ka->sa_flags & TARGET_SA_ONSTACK) &&
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01004600 (sas_ss_flags(oldsp) == 0)) {
Nathan Froydbcd49332009-05-12 19:13:18 -07004601 oldsp = (target_sigaltstack_used.ss_sp
4602 + target_sigaltstack_used.ss_size);
4603 }
4604
Eduardo Habkost9be38592016-06-13 18:57:58 -03004605 return (oldsp - frame_size) & ~0xFUL;
Nathan Froydbcd49332009-05-12 19:13:18 -07004606}
4607
Tom Musta76781082014-06-30 08:13:37 -05004608static void save_user_regs(CPUPPCState *env, struct target_mcontext *frame)
Nathan Froydbcd49332009-05-12 19:13:18 -07004609{
4610 target_ulong msr = env->msr;
4611 int i;
4612 target_ulong ccr = 0;
4613
4614 /* In general, the kernel attempts to be intelligent about what it
4615 needs to save for Altivec/FP/SPE registers. We don't care that
4616 much, so we just go ahead and save everything. */
4617
4618 /* Save general registers. */
4619 for (i = 0; i < ARRAY_SIZE(env->gpr); i++) {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01004620 __put_user(env->gpr[i], &frame->mc_gregs[i]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004621 }
Riku Voipioc650c002014-04-23 13:53:45 +03004622 __put_user(env->nip, &frame->mc_gregs[TARGET_PT_NIP]);
4623 __put_user(env->ctr, &frame->mc_gregs[TARGET_PT_CTR]);
4624 __put_user(env->lr, &frame->mc_gregs[TARGET_PT_LNK]);
4625 __put_user(env->xer, &frame->mc_gregs[TARGET_PT_XER]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004626
4627 for (i = 0; i < ARRAY_SIZE(env->crf); i++) {
4628 ccr |= env->crf[i] << (32 - ((i + 1) * 4));
4629 }
Riku Voipioc650c002014-04-23 13:53:45 +03004630 __put_user(ccr, &frame->mc_gregs[TARGET_PT_CCR]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004631
4632 /* Save Altivec registers if necessary. */
4633 if (env->insns_flags & PPC_ALTIVEC) {
4634 for (i = 0; i < ARRAY_SIZE(env->avr); i++) {
Anthony Liguoric227f092009-10-01 16:12:16 -05004635 ppc_avr_t *avr = &env->avr[i];
4636 ppc_avr_t *vreg = &frame->mc_vregs.altivec[i];
Nathan Froydbcd49332009-05-12 19:13:18 -07004637
Riku Voipioc650c002014-04-23 13:53:45 +03004638 __put_user(avr->u64[0], &vreg->u64[0]);
4639 __put_user(avr->u64[1], &vreg->u64[1]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004640 }
4641 /* Set MSR_VR in the saved MSR value to indicate that
4642 frame->mc_vregs contains valid data. */
4643 msr |= MSR_VR;
Riku Voipioc650c002014-04-23 13:53:45 +03004644 __put_user((uint32_t)env->spr[SPR_VRSAVE],
4645 &frame->mc_vregs.altivec[32].u32[3]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004646 }
4647
4648 /* Save floating point registers. */
4649 if (env->insns_flags & PPC_FLOAT) {
4650 for (i = 0; i < ARRAY_SIZE(env->fpr); i++) {
Riku Voipioc650c002014-04-23 13:53:45 +03004651 __put_user(env->fpr[i], &frame->mc_fregs[i]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004652 }
Riku Voipioc650c002014-04-23 13:53:45 +03004653 __put_user((uint64_t) env->fpscr, &frame->mc_fregs[32]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004654 }
4655
4656 /* Save SPE registers. The kernel only saves the high half. */
4657 if (env->insns_flags & PPC_SPE) {
4658#if defined(TARGET_PPC64)
4659 for (i = 0; i < ARRAY_SIZE(env->gpr); i++) {
Riku Voipioc650c002014-04-23 13:53:45 +03004660 __put_user(env->gpr[i] >> 32, &frame->mc_vregs.spe[i]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004661 }
4662#else
4663 for (i = 0; i < ARRAY_SIZE(env->gprh); i++) {
Riku Voipioc650c002014-04-23 13:53:45 +03004664 __put_user(env->gprh[i], &frame->mc_vregs.spe[i]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004665 }
4666#endif
4667 /* Set MSR_SPE in the saved MSR value to indicate that
4668 frame->mc_vregs contains valid data. */
4669 msr |= MSR_SPE;
Riku Voipioc650c002014-04-23 13:53:45 +03004670 __put_user(env->spe_fscr, &frame->mc_vregs.spe[32]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004671 }
4672
4673 /* Store MSR. */
Riku Voipioc650c002014-04-23 13:53:45 +03004674 __put_user(msr, &frame->mc_gregs[TARGET_PT_MSR]);
Tom Musta76781082014-06-30 08:13:37 -05004675}
Nathan Froydbcd49332009-05-12 19:13:18 -07004676
Tom Musta76781082014-06-30 08:13:37 -05004677static void encode_trampoline(int sigret, uint32_t *tramp)
4678{
Nathan Froydbcd49332009-05-12 19:13:18 -07004679 /* Set up the sigreturn trampoline: li r0,sigret; sc. */
4680 if (sigret) {
Tom Musta76781082014-06-30 08:13:37 -05004681 __put_user(0x38000000 | sigret, &tramp[0]);
4682 __put_user(0x44000002, &tramp[1]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004683 }
Nathan Froydbcd49332009-05-12 19:13:18 -07004684}
4685
Riku Voipioc650c002014-04-23 13:53:45 +03004686static void restore_user_regs(CPUPPCState *env,
4687 struct target_mcontext *frame, int sig)
Nathan Froydbcd49332009-05-12 19:13:18 -07004688{
4689 target_ulong save_r2 = 0;
4690 target_ulong msr;
4691 target_ulong ccr;
4692
4693 int i;
4694
4695 if (!sig) {
4696 save_r2 = env->gpr[2];
4697 }
4698
4699 /* Restore general registers. */
4700 for (i = 0; i < ARRAY_SIZE(env->gpr); i++) {
Riku Voipioc650c002014-04-23 13:53:45 +03004701 __get_user(env->gpr[i], &frame->mc_gregs[i]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004702 }
Riku Voipioc650c002014-04-23 13:53:45 +03004703 __get_user(env->nip, &frame->mc_gregs[TARGET_PT_NIP]);
4704 __get_user(env->ctr, &frame->mc_gregs[TARGET_PT_CTR]);
4705 __get_user(env->lr, &frame->mc_gregs[TARGET_PT_LNK]);
4706 __get_user(env->xer, &frame->mc_gregs[TARGET_PT_XER]);
4707 __get_user(ccr, &frame->mc_gregs[TARGET_PT_CCR]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004708
4709 for (i = 0; i < ARRAY_SIZE(env->crf); i++) {
4710 env->crf[i] = (ccr >> (32 - ((i + 1) * 4))) & 0xf;
4711 }
4712
4713 if (!sig) {
4714 env->gpr[2] = save_r2;
4715 }
4716 /* Restore MSR. */
Riku Voipioc650c002014-04-23 13:53:45 +03004717 __get_user(msr, &frame->mc_gregs[TARGET_PT_MSR]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004718
4719 /* If doing signal return, restore the previous little-endian mode. */
4720 if (sig)
Laurent Vivier49e55cb2016-03-30 18:36:51 +02004721 env->msr = (env->msr & ~(1ull << MSR_LE)) | (msr & (1ull << MSR_LE));
Nathan Froydbcd49332009-05-12 19:13:18 -07004722
4723 /* Restore Altivec registers if necessary. */
4724 if (env->insns_flags & PPC_ALTIVEC) {
4725 for (i = 0; i < ARRAY_SIZE(env->avr); i++) {
Anthony Liguoric227f092009-10-01 16:12:16 -05004726 ppc_avr_t *avr = &env->avr[i];
4727 ppc_avr_t *vreg = &frame->mc_vregs.altivec[i];
Nathan Froydbcd49332009-05-12 19:13:18 -07004728
Riku Voipioc650c002014-04-23 13:53:45 +03004729 __get_user(avr->u64[0], &vreg->u64[0]);
4730 __get_user(avr->u64[1], &vreg->u64[1]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004731 }
4732 /* Set MSR_VEC in the saved MSR value to indicate that
4733 frame->mc_vregs contains valid data. */
Riku Voipioc650c002014-04-23 13:53:45 +03004734 __get_user(env->spr[SPR_VRSAVE],
4735 (target_ulong *)(&frame->mc_vregs.altivec[32].u32[3]));
Nathan Froydbcd49332009-05-12 19:13:18 -07004736 }
4737
4738 /* Restore floating point registers. */
4739 if (env->insns_flags & PPC_FLOAT) {
4740 uint64_t fpscr;
4741 for (i = 0; i < ARRAY_SIZE(env->fpr); i++) {
Riku Voipioc650c002014-04-23 13:53:45 +03004742 __get_user(env->fpr[i], &frame->mc_fregs[i]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004743 }
Riku Voipioc650c002014-04-23 13:53:45 +03004744 __get_user(fpscr, &frame->mc_fregs[32]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004745 env->fpscr = (uint32_t) fpscr;
4746 }
4747
4748 /* Save SPE registers. The kernel only saves the high half. */
4749 if (env->insns_flags & PPC_SPE) {
4750#if defined(TARGET_PPC64)
4751 for (i = 0; i < ARRAY_SIZE(env->gpr); i++) {
4752 uint32_t hi;
4753
Riku Voipioc650c002014-04-23 13:53:45 +03004754 __get_user(hi, &frame->mc_vregs.spe[i]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004755 env->gpr[i] = ((uint64_t)hi << 32) | ((uint32_t) env->gpr[i]);
4756 }
4757#else
4758 for (i = 0; i < ARRAY_SIZE(env->gprh); i++) {
Riku Voipioc650c002014-04-23 13:53:45 +03004759 __get_user(env->gprh[i], &frame->mc_vregs.spe[i]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004760 }
4761#endif
Riku Voipioc650c002014-04-23 13:53:45 +03004762 __get_user(env->spe_fscr, &frame->mc_vregs.spe[32]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004763 }
Nathan Froydbcd49332009-05-12 19:13:18 -07004764}
4765
4766static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01004767 target_sigset_t *set, CPUPPCState *env)
Nathan Froydbcd49332009-05-12 19:13:18 -07004768{
4769 struct target_sigframe *frame;
4770 struct target_sigcontext *sc;
4771 target_ulong frame_addr, newsp;
4772 int err = 0;
Tom Musta14585582014-06-30 08:13:42 -05004773#if defined(TARGET_PPC64)
4774 struct image_info *image = ((TaskState *)thread_cpu->opaque)->info;
4775#endif
Nathan Froydbcd49332009-05-12 19:13:18 -07004776
4777 frame_addr = get_sigframe(ka, env, sizeof(*frame));
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01004778 trace_user_setup_frame(env, frame_addr);
Nathan Froydbcd49332009-05-12 19:13:18 -07004779 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 1))
4780 goto sigsegv;
4781 sc = &frame->sctx;
4782
Riku Voipio1d8b5122014-04-23 10:26:05 +03004783 __put_user(ka->_sa_handler, &sc->handler);
4784 __put_user(set->sig[0], &sc->oldmask);
Tom Musta61e75fe2014-06-30 08:13:38 -05004785#if TARGET_ABI_BITS == 64
Riku Voipio1d8b5122014-04-23 10:26:05 +03004786 __put_user(set->sig[0] >> 32, &sc->_unused[3]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004787#else
Riku Voipio1d8b5122014-04-23 10:26:05 +03004788 __put_user(set->sig[1], &sc->_unused[3]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004789#endif
Riku Voipio1d8b5122014-04-23 10:26:05 +03004790 __put_user(h2g(&frame->mctx), &sc->regs);
4791 __put_user(sig, &sc->signal);
Nathan Froydbcd49332009-05-12 19:13:18 -07004792
4793 /* Save user regs. */
Tom Musta76781082014-06-30 08:13:37 -05004794 save_user_regs(env, &frame->mctx);
4795
4796 /* Construct the trampoline code on the stack. */
4797 encode_trampoline(TARGET_NR_sigreturn, (uint32_t *)&frame->mctx.tramp);
Nathan Froydbcd49332009-05-12 19:13:18 -07004798
4799 /* The kernel checks for the presence of a VDSO here. We don't
4800 emulate a vdso, so use a sigreturn system call. */
4801 env->lr = (target_ulong) h2g(frame->mctx.tramp);
4802
4803 /* Turn off all fp exceptions. */
4804 env->fpscr = 0;
4805
4806 /* Create a stack frame for the caller of the handler. */
4807 newsp = frame_addr - SIGNAL_FRAMESIZE;
Samuel Seaybeb526b2013-01-02 10:53:46 +00004808 err |= put_user(env->gpr[1], newsp, target_ulong);
Nathan Froydbcd49332009-05-12 19:13:18 -07004809
4810 if (err)
4811 goto sigsegv;
4812
4813 /* Set up registers for signal handler. */
4814 env->gpr[1] = newsp;
Peter Maydellb6e2c932015-01-08 12:19:43 +00004815 env->gpr[3] = sig;
Samuel Seay61993a62013-01-04 14:35:48 +00004816 env->gpr[4] = frame_addr + offsetof(struct target_sigframe, sctx);
Tom Musta8d6ab332014-06-30 08:13:39 -05004817
4818#if defined(TARGET_PPC64)
Tom Musta14585582014-06-30 08:13:42 -05004819 if (get_ppc64_abi(image) < 2) {
4820 /* ELFv1 PPC64 function pointers are pointers to OPD entries. */
4821 struct target_func_ptr *handler =
4822 (struct target_func_ptr *)g2h(ka->_sa_handler);
4823 env->nip = tswapl(handler->entry);
4824 env->gpr[2] = tswapl(handler->toc);
4825 } else {
4826 /* ELFv2 PPC64 function pointers are entry points, but R12
4827 * must also be set */
4828 env->nip = tswapl((target_ulong) ka->_sa_handler);
4829 env->gpr[12] = env->nip;
4830 }
Tom Musta8d6ab332014-06-30 08:13:39 -05004831#else
Nathan Froydbcd49332009-05-12 19:13:18 -07004832 env->nip = (target_ulong) ka->_sa_handler;
Tom Musta8d6ab332014-06-30 08:13:39 -05004833#endif
4834
Nathan Froydbcd49332009-05-12 19:13:18 -07004835 /* Signal handlers are entered in big-endian mode. */
Laurent Vivier49e55cb2016-03-30 18:36:51 +02004836 env->msr &= ~(1ull << MSR_LE);
Nathan Froydbcd49332009-05-12 19:13:18 -07004837
4838 unlock_user_struct(frame, frame_addr, 1);
4839 return;
4840
4841sigsegv:
4842 unlock_user_struct(frame, frame_addr, 1);
Peter Maydell09391662016-07-28 16:44:47 +01004843 force_sigsegv(sig);
Nathan Froydbcd49332009-05-12 19:13:18 -07004844}
4845
4846static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05004847 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01004848 target_sigset_t *set, CPUPPCState *env)
Nathan Froydbcd49332009-05-12 19:13:18 -07004849{
4850 struct target_rt_sigframe *rt_sf;
Tom Musta61e75fe2014-06-30 08:13:38 -05004851 uint32_t *trampptr = 0;
4852 struct target_mcontext *mctx = 0;
Nathan Froydbcd49332009-05-12 19:13:18 -07004853 target_ulong rt_sf_addr, newsp = 0;
4854 int i, err = 0;
Tom Musta14585582014-06-30 08:13:42 -05004855#if defined(TARGET_PPC64)
4856 struct image_info *image = ((TaskState *)thread_cpu->opaque)->info;
4857#endif
Nathan Froydbcd49332009-05-12 19:13:18 -07004858
4859 rt_sf_addr = get_sigframe(ka, env, sizeof(*rt_sf));
4860 if (!lock_user_struct(VERIFY_WRITE, rt_sf, rt_sf_addr, 1))
4861 goto sigsegv;
4862
Peter Maydellf6c7a052015-01-08 12:19:48 +00004863 tswap_siginfo(&rt_sf->info, info);
Nathan Froydbcd49332009-05-12 19:13:18 -07004864
Riku Voipio1d8b5122014-04-23 10:26:05 +03004865 __put_user(0, &rt_sf->uc.tuc_flags);
4866 __put_user(0, &rt_sf->uc.tuc_link);
4867 __put_user((target_ulong)target_sigaltstack_used.ss_sp,
4868 &rt_sf->uc.tuc_stack.ss_sp);
4869 __put_user(sas_ss_flags(env->gpr[1]),
4870 &rt_sf->uc.tuc_stack.ss_flags);
4871 __put_user(target_sigaltstack_used.ss_size,
4872 &rt_sf->uc.tuc_stack.ss_size);
Tom Musta61e75fe2014-06-30 08:13:38 -05004873#if !defined(TARGET_PPC64)
Riku Voipio1d8b5122014-04-23 10:26:05 +03004874 __put_user(h2g (&rt_sf->uc.tuc_mcontext),
4875 &rt_sf->uc.tuc_regs);
Tom Musta61e75fe2014-06-30 08:13:38 -05004876#endif
Nathan Froydbcd49332009-05-12 19:13:18 -07004877 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03004878 __put_user(set->sig[i], &rt_sf->uc.tuc_sigmask.sig[i]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004879 }
4880
Tom Musta61e75fe2014-06-30 08:13:38 -05004881#if defined(TARGET_PPC64)
4882 mctx = &rt_sf->uc.tuc_sigcontext.mcontext;
4883 trampptr = &rt_sf->trampoline[0];
4884#else
4885 mctx = &rt_sf->uc.tuc_mcontext;
4886 trampptr = (uint32_t *)&rt_sf->uc.tuc_mcontext.tramp;
4887#endif
4888
4889 save_user_regs(env, mctx);
4890 encode_trampoline(TARGET_NR_rt_sigreturn, trampptr);
Nathan Froydbcd49332009-05-12 19:13:18 -07004891
4892 /* The kernel checks for the presence of a VDSO here. We don't
4893 emulate a vdso, so use a sigreturn system call. */
Tom Musta61e75fe2014-06-30 08:13:38 -05004894 env->lr = (target_ulong) h2g(trampptr);
Nathan Froydbcd49332009-05-12 19:13:18 -07004895
4896 /* Turn off all fp exceptions. */
4897 env->fpscr = 0;
4898
4899 /* Create a stack frame for the caller of the handler. */
4900 newsp = rt_sf_addr - (SIGNAL_FRAMESIZE + 16);
Tom Mustafbdc2002014-06-30 08:13:36 -05004901 err |= put_user(env->gpr[1], newsp, target_ulong);
Nathan Froydbcd49332009-05-12 19:13:18 -07004902
4903 if (err)
4904 goto sigsegv;
4905
4906 /* Set up registers for signal handler. */
4907 env->gpr[1] = newsp;
Peter Maydellb6e2c932015-01-08 12:19:43 +00004908 env->gpr[3] = (target_ulong) sig;
Nathan Froydbcd49332009-05-12 19:13:18 -07004909 env->gpr[4] = (target_ulong) h2g(&rt_sf->info);
4910 env->gpr[5] = (target_ulong) h2g(&rt_sf->uc);
4911 env->gpr[6] = (target_ulong) h2g(rt_sf);
Tom Musta8d6ab332014-06-30 08:13:39 -05004912
4913#if defined(TARGET_PPC64)
Tom Musta14585582014-06-30 08:13:42 -05004914 if (get_ppc64_abi(image) < 2) {
4915 /* ELFv1 PPC64 function pointers are pointers to OPD entries. */
4916 struct target_func_ptr *handler =
4917 (struct target_func_ptr *)g2h(ka->_sa_handler);
4918 env->nip = tswapl(handler->entry);
4919 env->gpr[2] = tswapl(handler->toc);
4920 } else {
4921 /* ELFv2 PPC64 function pointers are entry points, but R12
4922 * must also be set */
4923 env->nip = tswapl((target_ulong) ka->_sa_handler);
4924 env->gpr[12] = env->nip;
4925 }
Tom Musta8d6ab332014-06-30 08:13:39 -05004926#else
Nathan Froydbcd49332009-05-12 19:13:18 -07004927 env->nip = (target_ulong) ka->_sa_handler;
Tom Musta8d6ab332014-06-30 08:13:39 -05004928#endif
4929
Nathan Froydbcd49332009-05-12 19:13:18 -07004930 /* Signal handlers are entered in big-endian mode. */
Laurent Vivier49e55cb2016-03-30 18:36:51 +02004931 env->msr &= ~(1ull << MSR_LE);
Nathan Froydbcd49332009-05-12 19:13:18 -07004932
4933 unlock_user_struct(rt_sf, rt_sf_addr, 1);
4934 return;
4935
4936sigsegv:
4937 unlock_user_struct(rt_sf, rt_sf_addr, 1);
Peter Maydell09391662016-07-28 16:44:47 +01004938 force_sigsegv(sig);
Nathan Froydbcd49332009-05-12 19:13:18 -07004939
4940}
4941
Andreas Färber05390242012-02-25 03:37:53 +01004942long do_sigreturn(CPUPPCState *env)
Nathan Froydbcd49332009-05-12 19:13:18 -07004943{
4944 struct target_sigcontext *sc = NULL;
4945 struct target_mcontext *sr = NULL;
Peter Maydellb04636f2013-07-29 12:00:31 +01004946 target_ulong sr_addr = 0, sc_addr;
Nathan Froydbcd49332009-05-12 19:13:18 -07004947 sigset_t blocked;
Anthony Liguoric227f092009-10-01 16:12:16 -05004948 target_sigset_t set;
Nathan Froydbcd49332009-05-12 19:13:18 -07004949
4950 sc_addr = env->gpr[1] + SIGNAL_FRAMESIZE;
4951 if (!lock_user_struct(VERIFY_READ, sc, sc_addr, 1))
4952 goto sigsegv;
4953
4954#if defined(TARGET_PPC64)
Tom Musta61e75fe2014-06-30 08:13:38 -05004955 set.sig[0] = sc->oldmask + ((uint64_t)(sc->_unused[3]) << 32);
Nathan Froydbcd49332009-05-12 19:13:18 -07004956#else
Riku Voipiof5f601a2014-04-23 13:00:17 +03004957 __get_user(set.sig[0], &sc->oldmask);
4958 __get_user(set.sig[1], &sc->_unused[3]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004959#endif
4960 target_to_host_sigset_internal(&blocked, &set);
Peter Maydell9eede5b2016-05-27 15:51:46 +01004961 set_sigmask(&blocked);
Nathan Froydbcd49332009-05-12 19:13:18 -07004962
Riku Voipiof5f601a2014-04-23 13:00:17 +03004963 __get_user(sr_addr, &sc->regs);
Nathan Froydbcd49332009-05-12 19:13:18 -07004964 if (!lock_user_struct(VERIFY_READ, sr, sr_addr, 1))
4965 goto sigsegv;
Riku Voipioc650c002014-04-23 13:53:45 +03004966 restore_user_regs(env, sr, 1);
Nathan Froydbcd49332009-05-12 19:13:18 -07004967
4968 unlock_user_struct(sr, sr_addr, 1);
4969 unlock_user_struct(sc, sc_addr, 1);
4970 return -TARGET_QEMU_ESIGRETURN;
4971
4972sigsegv:
4973 unlock_user_struct(sr, sr_addr, 1);
4974 unlock_user_struct(sc, sc_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02004975 force_sig(TARGET_SIGSEGV);
Nathan Froydbcd49332009-05-12 19:13:18 -07004976 return 0;
4977}
4978
4979/* See arch/powerpc/kernel/signal_32.c. */
Andreas Färber05390242012-02-25 03:37:53 +01004980static int do_setcontext(struct target_ucontext *ucp, CPUPPCState *env, int sig)
Nathan Froydbcd49332009-05-12 19:13:18 -07004981{
4982 struct target_mcontext *mcp;
4983 target_ulong mcp_addr;
4984 sigset_t blocked;
Anthony Liguoric227f092009-10-01 16:12:16 -05004985 target_sigset_t set;
Nathan Froydbcd49332009-05-12 19:13:18 -07004986
Aurelien Jarno60e99242010-03-29 02:12:51 +02004987 if (copy_from_user(&set, h2g(ucp) + offsetof(struct target_ucontext, tuc_sigmask),
Nathan Froydbcd49332009-05-12 19:13:18 -07004988 sizeof (set)))
4989 return 1;
4990
Tom Musta19774ec2014-06-30 08:13:40 -05004991#if defined(TARGET_PPC64)
4992 mcp_addr = h2g(ucp) +
4993 offsetof(struct target_ucontext, tuc_sigcontext.mcontext);
4994#else
Riku Voipio9e918dc2014-04-23 14:05:09 +03004995 __get_user(mcp_addr, &ucp->tuc_regs);
Tom Musta19774ec2014-06-30 08:13:40 -05004996#endif
Nathan Froydbcd49332009-05-12 19:13:18 -07004997
4998 if (!lock_user_struct(VERIFY_READ, mcp, mcp_addr, 1))
4999 return 1;
5000
5001 target_to_host_sigset_internal(&blocked, &set);
Peter Maydell9eede5b2016-05-27 15:51:46 +01005002 set_sigmask(&blocked);
Riku Voipioc650c002014-04-23 13:53:45 +03005003 restore_user_regs(env, mcp, sig);
Nathan Froydbcd49332009-05-12 19:13:18 -07005004
5005 unlock_user_struct(mcp, mcp_addr, 1);
5006 return 0;
Nathan Froydbcd49332009-05-12 19:13:18 -07005007}
5008
Andreas Färber05390242012-02-25 03:37:53 +01005009long do_rt_sigreturn(CPUPPCState *env)
Nathan Froydbcd49332009-05-12 19:13:18 -07005010{
5011 struct target_rt_sigframe *rt_sf = NULL;
5012 target_ulong rt_sf_addr;
5013
5014 rt_sf_addr = env->gpr[1] + SIGNAL_FRAMESIZE + 16;
5015 if (!lock_user_struct(VERIFY_READ, rt_sf, rt_sf_addr, 1))
5016 goto sigsegv;
5017
5018 if (do_setcontext(&rt_sf->uc, env, 1))
5019 goto sigsegv;
5020
5021 do_sigaltstack(rt_sf_addr
Aurelien Jarno60e99242010-03-29 02:12:51 +02005022 + offsetof(struct target_rt_sigframe, uc.tuc_stack),
Nathan Froydbcd49332009-05-12 19:13:18 -07005023 0, env->gpr[1]);
5024
5025 unlock_user_struct(rt_sf, rt_sf_addr, 1);
5026 return -TARGET_QEMU_ESIGRETURN;
5027
5028sigsegv:
5029 unlock_user_struct(rt_sf, rt_sf_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02005030 force_sig(TARGET_SIGSEGV);
Nathan Froydbcd49332009-05-12 19:13:18 -07005031 return 0;
5032}
5033
Laurent Vivier492a8742009-08-03 16:12:17 +02005034#elif defined(TARGET_M68K)
5035
5036struct target_sigcontext {
5037 abi_ulong sc_mask;
5038 abi_ulong sc_usp;
5039 abi_ulong sc_d0;
5040 abi_ulong sc_d1;
5041 abi_ulong sc_a0;
5042 abi_ulong sc_a1;
5043 unsigned short sc_sr;
5044 abi_ulong sc_pc;
5045};
5046
5047struct target_sigframe
5048{
5049 abi_ulong pretcode;
5050 int sig;
5051 int code;
5052 abi_ulong psc;
5053 char retcode[8];
5054 abi_ulong extramask[TARGET_NSIG_WORDS-1];
5055 struct target_sigcontext sc;
5056};
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01005057
Anthony Liguoric227f092009-10-01 16:12:16 -05005058typedef int target_greg_t;
Laurent Vivier71811552009-08-03 16:12:18 +02005059#define TARGET_NGREG 18
Anthony Liguoric227f092009-10-01 16:12:16 -05005060typedef target_greg_t target_gregset_t[TARGET_NGREG];
Laurent Vivier71811552009-08-03 16:12:18 +02005061
5062typedef struct target_fpregset {
5063 int f_fpcntl[3];
5064 int f_fpregs[8*3];
Anthony Liguoric227f092009-10-01 16:12:16 -05005065} target_fpregset_t;
Laurent Vivier71811552009-08-03 16:12:18 +02005066
5067struct target_mcontext {
5068 int version;
Anthony Liguoric227f092009-10-01 16:12:16 -05005069 target_gregset_t gregs;
5070 target_fpregset_t fpregs;
Laurent Vivier71811552009-08-03 16:12:18 +02005071};
5072
5073#define TARGET_MCONTEXT_VERSION 2
5074
5075struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02005076 abi_ulong tuc_flags;
5077 abi_ulong tuc_link;
5078 target_stack_t tuc_stack;
5079 struct target_mcontext tuc_mcontext;
5080 abi_long tuc_filler[80];
5081 target_sigset_t tuc_sigmask;
Laurent Vivier71811552009-08-03 16:12:18 +02005082};
5083
5084struct target_rt_sigframe
5085{
5086 abi_ulong pretcode;
5087 int sig;
5088 abi_ulong pinfo;
5089 abi_ulong puc;
5090 char retcode[8];
5091 struct target_siginfo info;
5092 struct target_ucontext uc;
5093};
Laurent Vivier492a8742009-08-03 16:12:17 +02005094
Riku Voipio41ecc722014-04-23 11:01:00 +03005095static void setup_sigcontext(struct target_sigcontext *sc, CPUM68KState *env,
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01005096 abi_ulong mask)
Laurent Vivier492a8742009-08-03 16:12:17 +02005097{
Riku Voipio1d8b5122014-04-23 10:26:05 +03005098 __put_user(mask, &sc->sc_mask);
5099 __put_user(env->aregs[7], &sc->sc_usp);
5100 __put_user(env->dregs[0], &sc->sc_d0);
5101 __put_user(env->dregs[1], &sc->sc_d1);
5102 __put_user(env->aregs[0], &sc->sc_a0);
5103 __put_user(env->aregs[1], &sc->sc_a1);
5104 __put_user(env->sr, &sc->sc_sr);
5105 __put_user(env->pc, &sc->sc_pc);
Laurent Vivier492a8742009-08-03 16:12:17 +02005106}
5107
Riku Voipio016d2e12014-04-23 11:19:48 +03005108static void
Timothy E Baldwin7ccb84a2016-05-12 18:47:39 +01005109restore_sigcontext(CPUM68KState *env, struct target_sigcontext *sc)
Laurent Vivier492a8742009-08-03 16:12:17 +02005110{
Laurent Vivier492a8742009-08-03 16:12:17 +02005111 int temp;
5112
Riku Voipio1d8b5122014-04-23 10:26:05 +03005113 __get_user(env->aregs[7], &sc->sc_usp);
Timothy E Baldwin7ccb84a2016-05-12 18:47:39 +01005114 __get_user(env->dregs[0], &sc->sc_d0);
Riku Voipio1d8b5122014-04-23 10:26:05 +03005115 __get_user(env->dregs[1], &sc->sc_d1);
5116 __get_user(env->aregs[0], &sc->sc_a0);
5117 __get_user(env->aregs[1], &sc->sc_a1);
5118 __get_user(env->pc, &sc->sc_pc);
5119 __get_user(temp, &sc->sc_sr);
Laurent Vivier492a8742009-08-03 16:12:17 +02005120 env->sr = (env->sr & 0xff00) | (temp & 0xff);
Laurent Vivier492a8742009-08-03 16:12:17 +02005121}
5122
5123/*
5124 * Determine which stack to use..
5125 */
5126static inline abi_ulong
Andreas Färber05390242012-02-25 03:37:53 +01005127get_sigframe(struct target_sigaction *ka, CPUM68KState *regs,
5128 size_t frame_size)
Laurent Vivier492a8742009-08-03 16:12:17 +02005129{
5130 unsigned long sp;
5131
5132 sp = regs->aregs[7];
5133
5134 /* This is the X/Open sanctioned signal stack switching. */
5135 if ((ka->sa_flags & TARGET_SA_ONSTACK) && (sas_ss_flags (sp) == 0)) {
5136 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
5137 }
5138
5139 return ((sp - frame_size) & -8UL);
5140}
5141
5142static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01005143 target_sigset_t *set, CPUM68KState *env)
Laurent Vivier492a8742009-08-03 16:12:17 +02005144{
5145 struct target_sigframe *frame;
5146 abi_ulong frame_addr;
5147 abi_ulong retcode_addr;
5148 abi_ulong sc_addr;
Laurent Vivier492a8742009-08-03 16:12:17 +02005149 int i;
5150
5151 frame_addr = get_sigframe(ka, env, sizeof *frame);
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01005152 trace_user_setup_frame(env, frame_addr);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01005153 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
5154 goto give_sigsegv;
5155 }
Laurent Vivier492a8742009-08-03 16:12:17 +02005156
Riku Voipio1d8b5122014-04-23 10:26:05 +03005157 __put_user(sig, &frame->sig);
Laurent Vivier492a8742009-08-03 16:12:17 +02005158
5159 sc_addr = frame_addr + offsetof(struct target_sigframe, sc);
Riku Voipio1d8b5122014-04-23 10:26:05 +03005160 __put_user(sc_addr, &frame->psc);
Laurent Vivier492a8742009-08-03 16:12:17 +02005161
Riku Voipio41ecc722014-04-23 11:01:00 +03005162 setup_sigcontext(&frame->sc, env, set->sig[0]);
Laurent Vivier492a8742009-08-03 16:12:17 +02005163
5164 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
Riku Voipio0188fad2014-04-23 13:34:15 +03005165 __put_user(set->sig[i], &frame->extramask[i - 1]);
Laurent Vivier492a8742009-08-03 16:12:17 +02005166 }
5167
5168 /* Set up to return from userspace. */
5169
5170 retcode_addr = frame_addr + offsetof(struct target_sigframe, retcode);
Riku Voipio1d8b5122014-04-23 10:26:05 +03005171 __put_user(retcode_addr, &frame->pretcode);
Laurent Vivier492a8742009-08-03 16:12:17 +02005172
5173 /* moveq #,d0; trap #0 */
5174
Riku Voipio1d8b5122014-04-23 10:26:05 +03005175 __put_user(0x70004e40 + (TARGET_NR_sigreturn << 16),
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01005176 (uint32_t *)(frame->retcode));
Laurent Vivier492a8742009-08-03 16:12:17 +02005177
Laurent Vivier492a8742009-08-03 16:12:17 +02005178 /* Set up to return from userspace */
5179
5180 env->aregs[7] = frame_addr;
5181 env->pc = ka->_sa_handler;
5182
5183 unlock_user_struct(frame, frame_addr, 1);
5184 return;
5185
5186give_sigsegv:
Peter Maydell09391662016-07-28 16:44:47 +01005187 force_sigsegv(sig);
Laurent Vivier492a8742009-08-03 16:12:17 +02005188}
5189
Laurent Vivier71811552009-08-03 16:12:18 +02005190static inline int target_rt_setup_ucontext(struct target_ucontext *uc,
Andreas Färber05390242012-02-25 03:37:53 +01005191 CPUM68KState *env)
Laurent Vivier71811552009-08-03 16:12:18 +02005192{
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 __put_user(TARGET_MCONTEXT_VERSION, &uc->tuc_mcontext.version);
5196 __put_user(env->dregs[0], &gregs[0]);
5197 __put_user(env->dregs[1], &gregs[1]);
5198 __put_user(env->dregs[2], &gregs[2]);
5199 __put_user(env->dregs[3], &gregs[3]);
5200 __put_user(env->dregs[4], &gregs[4]);
5201 __put_user(env->dregs[5], &gregs[5]);
5202 __put_user(env->dregs[6], &gregs[6]);
5203 __put_user(env->dregs[7], &gregs[7]);
5204 __put_user(env->aregs[0], &gregs[8]);
5205 __put_user(env->aregs[1], &gregs[9]);
5206 __put_user(env->aregs[2], &gregs[10]);
5207 __put_user(env->aregs[3], &gregs[11]);
5208 __put_user(env->aregs[4], &gregs[12]);
5209 __put_user(env->aregs[5], &gregs[13]);
5210 __put_user(env->aregs[6], &gregs[14]);
5211 __put_user(env->aregs[7], &gregs[15]);
5212 __put_user(env->pc, &gregs[16]);
5213 __put_user(env->sr, &gregs[17]);
Laurent Vivier71811552009-08-03 16:12:18 +02005214
Riku Voipio1d8b5122014-04-23 10:26:05 +03005215 return 0;
Laurent Vivier71811552009-08-03 16:12:18 +02005216}
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01005217
Andreas Färber05390242012-02-25 03:37:53 +01005218static inline int target_rt_restore_ucontext(CPUM68KState *env,
Timothy E Baldwin7ccb84a2016-05-12 18:47:39 +01005219 struct target_ucontext *uc)
Laurent Vivier71811552009-08-03 16:12:18 +02005220{
5221 int temp;
Aurelien Jarno60e99242010-03-29 02:12:51 +02005222 target_greg_t *gregs = uc->tuc_mcontext.gregs;
Laurent Vivier71811552009-08-03 16:12:18 +02005223
Riku Voipio1d8b5122014-04-23 10:26:05 +03005224 __get_user(temp, &uc->tuc_mcontext.version);
Laurent Vivier71811552009-08-03 16:12:18 +02005225 if (temp != TARGET_MCONTEXT_VERSION)
5226 goto badframe;
5227
5228 /* restore passed registers */
Riku Voipio1d8b5122014-04-23 10:26:05 +03005229 __get_user(env->dregs[0], &gregs[0]);
5230 __get_user(env->dregs[1], &gregs[1]);
5231 __get_user(env->dregs[2], &gregs[2]);
5232 __get_user(env->dregs[3], &gregs[3]);
5233 __get_user(env->dregs[4], &gregs[4]);
5234 __get_user(env->dregs[5], &gregs[5]);
5235 __get_user(env->dregs[6], &gregs[6]);
5236 __get_user(env->dregs[7], &gregs[7]);
5237 __get_user(env->aregs[0], &gregs[8]);
5238 __get_user(env->aregs[1], &gregs[9]);
5239 __get_user(env->aregs[2], &gregs[10]);
5240 __get_user(env->aregs[3], &gregs[11]);
5241 __get_user(env->aregs[4], &gregs[12]);
5242 __get_user(env->aregs[5], &gregs[13]);
5243 __get_user(env->aregs[6], &gregs[14]);
5244 __get_user(env->aregs[7], &gregs[15]);
5245 __get_user(env->pc, &gregs[16]);
5246 __get_user(temp, &gregs[17]);
Laurent Vivier71811552009-08-03 16:12:18 +02005247 env->sr = (env->sr & 0xff00) | (temp & 0xff);
5248
Riku Voipio1d8b5122014-04-23 10:26:05 +03005249 return 0;
Laurent Vivier71811552009-08-03 16:12:18 +02005250
5251badframe:
5252 return 1;
5253}
5254
Laurent Vivier492a8742009-08-03 16:12:17 +02005255static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05005256 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01005257 target_sigset_t *set, CPUM68KState *env)
Laurent Vivier492a8742009-08-03 16:12:17 +02005258{
Laurent Vivier71811552009-08-03 16:12:18 +02005259 struct target_rt_sigframe *frame;
5260 abi_ulong frame_addr;
5261 abi_ulong retcode_addr;
5262 abi_ulong info_addr;
5263 abi_ulong uc_addr;
5264 int err = 0;
5265 int i;
5266
5267 frame_addr = get_sigframe(ka, env, sizeof *frame);
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01005268 trace_user_setup_rt_frame(env, frame_addr);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01005269 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
5270 goto give_sigsegv;
5271 }
Laurent Vivier71811552009-08-03 16:12:18 +02005272
Riku Voipio1d8b5122014-04-23 10:26:05 +03005273 __put_user(sig, &frame->sig);
Laurent Vivier71811552009-08-03 16:12:18 +02005274
5275 info_addr = frame_addr + offsetof(struct target_rt_sigframe, info);
Riku Voipio1d8b5122014-04-23 10:26:05 +03005276 __put_user(info_addr, &frame->pinfo);
Laurent Vivier71811552009-08-03 16:12:18 +02005277
5278 uc_addr = frame_addr + offsetof(struct target_rt_sigframe, uc);
Riku Voipio1d8b5122014-04-23 10:26:05 +03005279 __put_user(uc_addr, &frame->puc);
Laurent Vivier71811552009-08-03 16:12:18 +02005280
Peter Maydellf6c7a052015-01-08 12:19:48 +00005281 tswap_siginfo(&frame->info, info);
Laurent Vivier71811552009-08-03 16:12:18 +02005282
5283 /* Create the ucontext */
5284
Riku Voipio1d8b5122014-04-23 10:26:05 +03005285 __put_user(0, &frame->uc.tuc_flags);
5286 __put_user(0, &frame->uc.tuc_link);
5287 __put_user(target_sigaltstack_used.ss_sp,
5288 &frame->uc.tuc_stack.ss_sp);
5289 __put_user(sas_ss_flags(env->aregs[7]),
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01005290 &frame->uc.tuc_stack.ss_flags);
Riku Voipio1d8b5122014-04-23 10:26:05 +03005291 __put_user(target_sigaltstack_used.ss_size,
5292 &frame->uc.tuc_stack.ss_size);
Laurent Vivier71811552009-08-03 16:12:18 +02005293 err |= target_rt_setup_ucontext(&frame->uc, env);
5294
5295 if (err)
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01005296 goto give_sigsegv;
Laurent Vivier71811552009-08-03 16:12:18 +02005297
5298 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
Riku Voipio0188fad2014-04-23 13:34:15 +03005299 __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
Laurent Vivier71811552009-08-03 16:12:18 +02005300 }
5301
5302 /* Set up to return from userspace. */
5303
5304 retcode_addr = frame_addr + offsetof(struct target_sigframe, retcode);
Riku Voipio1d8b5122014-04-23 10:26:05 +03005305 __put_user(retcode_addr, &frame->pretcode);
Laurent Vivier71811552009-08-03 16:12:18 +02005306
5307 /* moveq #,d0; notb d0; trap #0 */
5308
Riku Voipio1d8b5122014-04-23 10:26:05 +03005309 __put_user(0x70004600 + ((TARGET_NR_rt_sigreturn ^ 0xff) << 16),
Peter Maydell1669add2014-12-22 17:47:00 +00005310 (uint32_t *)(frame->retcode + 0));
5311 __put_user(0x4e40, (uint16_t *)(frame->retcode + 4));
Laurent Vivier71811552009-08-03 16:12:18 +02005312
5313 if (err)
5314 goto give_sigsegv;
5315
5316 /* Set up to return from userspace */
5317
5318 env->aregs[7] = frame_addr;
5319 env->pc = ka->_sa_handler;
5320
5321 unlock_user_struct(frame, frame_addr, 1);
5322 return;
5323
5324give_sigsegv:
5325 unlock_user_struct(frame, frame_addr, 1);
Peter Maydell09391662016-07-28 16:44:47 +01005326 force_sigsegv(sig);
Laurent Vivier492a8742009-08-03 16:12:17 +02005327}
5328
Andreas Färber05390242012-02-25 03:37:53 +01005329long do_sigreturn(CPUM68KState *env)
Laurent Vivier492a8742009-08-03 16:12:17 +02005330{
5331 struct target_sigframe *frame;
5332 abi_ulong frame_addr = env->aregs[7] - 4;
Anthony Liguoric227f092009-10-01 16:12:16 -05005333 target_sigset_t target_set;
Laurent Vivier492a8742009-08-03 16:12:17 +02005334 sigset_t set;
Timothy E Baldwin7ccb84a2016-05-12 18:47:39 +01005335 int i;
Laurent Vivier492a8742009-08-03 16:12:17 +02005336
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01005337 trace_user_do_sigreturn(env, frame_addr);
Laurent Vivier492a8742009-08-03 16:12:17 +02005338 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
5339 goto badframe;
5340
5341 /* set blocked signals */
5342
Riku Voipiof5f601a2014-04-23 13:00:17 +03005343 __get_user(target_set.sig[0], &frame->sc.sc_mask);
Laurent Vivier492a8742009-08-03 16:12:17 +02005344
5345 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
Riku Voipiof5f601a2014-04-23 13:00:17 +03005346 __get_user(target_set.sig[i], &frame->extramask[i - 1]);
Laurent Vivier492a8742009-08-03 16:12:17 +02005347 }
5348
5349 target_to_host_sigset_internal(&set, &target_set);
Peter Maydell9eede5b2016-05-27 15:51:46 +01005350 set_sigmask(&set);
Laurent Vivier492a8742009-08-03 16:12:17 +02005351
5352 /* restore registers */
5353
Timothy E Baldwin7ccb84a2016-05-12 18:47:39 +01005354 restore_sigcontext(env, &frame->sc);
Laurent Vivier492a8742009-08-03 16:12:17 +02005355
5356 unlock_user_struct(frame, frame_addr, 0);
Timothy E Baldwin7ccb84a2016-05-12 18:47:39 +01005357 return -TARGET_QEMU_ESIGRETURN;
Laurent Vivier492a8742009-08-03 16:12:17 +02005358
5359badframe:
Laurent Vivier492a8742009-08-03 16:12:17 +02005360 force_sig(TARGET_SIGSEGV);
5361 return 0;
5362}
5363
Andreas Färber05390242012-02-25 03:37:53 +01005364long do_rt_sigreturn(CPUM68KState *env)
Laurent Vivier492a8742009-08-03 16:12:17 +02005365{
Laurent Vivier71811552009-08-03 16:12:18 +02005366 struct target_rt_sigframe *frame;
5367 abi_ulong frame_addr = env->aregs[7] - 4;
Anthony Liguoric227f092009-10-01 16:12:16 -05005368 target_sigset_t target_set;
Laurent Vivier71811552009-08-03 16:12:18 +02005369 sigset_t set;
Laurent Vivier71811552009-08-03 16:12:18 +02005370
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01005371 trace_user_do_rt_sigreturn(env, frame_addr);
Laurent Vivier71811552009-08-03 16:12:18 +02005372 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
5373 goto badframe;
5374
5375 target_to_host_sigset_internal(&set, &target_set);
Peter Maydell9eede5b2016-05-27 15:51:46 +01005376 set_sigmask(&set);
Laurent Vivier71811552009-08-03 16:12:18 +02005377
5378 /* restore registers */
5379
Timothy E Baldwin7ccb84a2016-05-12 18:47:39 +01005380 if (target_rt_restore_ucontext(env, &frame->uc))
Laurent Vivier71811552009-08-03 16:12:18 +02005381 goto badframe;
5382
5383 if (do_sigaltstack(frame_addr +
Aurelien Jarno60e99242010-03-29 02:12:51 +02005384 offsetof(struct target_rt_sigframe, uc.tuc_stack),
Laurent Vivier71811552009-08-03 16:12:18 +02005385 0, get_sp_from_cpustate(env)) == -EFAULT)
5386 goto badframe;
5387
5388 unlock_user_struct(frame, frame_addr, 0);
Timothy E Baldwin7ccb84a2016-05-12 18:47:39 +01005389 return -TARGET_QEMU_ESIGRETURN;
Laurent Vivier71811552009-08-03 16:12:18 +02005390
5391badframe:
5392 unlock_user_struct(frame, frame_addr, 0);
5393 force_sig(TARGET_SIGSEGV);
5394 return 0;
Laurent Vivier492a8742009-08-03 16:12:17 +02005395}
5396
Richard Henderson6049f4f2009-12-27 18:30:03 -08005397#elif defined(TARGET_ALPHA)
5398
5399struct target_sigcontext {
5400 abi_long sc_onstack;
5401 abi_long sc_mask;
5402 abi_long sc_pc;
5403 abi_long sc_ps;
5404 abi_long sc_regs[32];
5405 abi_long sc_ownedfp;
5406 abi_long sc_fpregs[32];
5407 abi_ulong sc_fpcr;
5408 abi_ulong sc_fp_control;
5409 abi_ulong sc_reserved1;
5410 abi_ulong sc_reserved2;
5411 abi_ulong sc_ssize;
5412 abi_ulong sc_sbase;
5413 abi_ulong sc_traparg_a0;
5414 abi_ulong sc_traparg_a1;
5415 abi_ulong sc_traparg_a2;
5416 abi_ulong sc_fp_trap_pc;
5417 abi_ulong sc_fp_trigger_sum;
5418 abi_ulong sc_fp_trigger_inst;
5419};
5420
5421struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02005422 abi_ulong tuc_flags;
5423 abi_ulong tuc_link;
5424 abi_ulong tuc_osf_sigmask;
5425 target_stack_t tuc_stack;
5426 struct target_sigcontext tuc_mcontext;
5427 target_sigset_t tuc_sigmask;
Richard Henderson6049f4f2009-12-27 18:30:03 -08005428};
5429
5430struct target_sigframe {
5431 struct target_sigcontext sc;
5432 unsigned int retcode[3];
5433};
5434
5435struct target_rt_sigframe {
5436 target_siginfo_t info;
5437 struct target_ucontext uc;
5438 unsigned int retcode[3];
5439};
5440
5441#define INSN_MOV_R30_R16 0x47fe0410
5442#define INSN_LDI_R0 0x201f0000
5443#define INSN_CALLSYS 0x00000083
5444
Riku Voipio41ecc722014-04-23 11:01:00 +03005445static void setup_sigcontext(struct target_sigcontext *sc, CPUAlphaState *env,
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01005446 abi_ulong frame_addr, target_sigset_t *set)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005447{
Riku Voipio41ecc722014-04-23 11:01:00 +03005448 int i;
Richard Henderson6049f4f2009-12-27 18:30:03 -08005449
Riku Voipio1d8b5122014-04-23 10:26:05 +03005450 __put_user(on_sig_stack(frame_addr), &sc->sc_onstack);
5451 __put_user(set->sig[0], &sc->sc_mask);
5452 __put_user(env->pc, &sc->sc_pc);
5453 __put_user(8, &sc->sc_ps);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005454
5455 for (i = 0; i < 31; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03005456 __put_user(env->ir[i], &sc->sc_regs[i]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005457 }
Riku Voipio1d8b5122014-04-23 10:26:05 +03005458 __put_user(0, &sc->sc_regs[31]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005459
5460 for (i = 0; i < 31; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03005461 __put_user(env->fir[i], &sc->sc_fpregs[i]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005462 }
Riku Voipio1d8b5122014-04-23 10:26:05 +03005463 __put_user(0, &sc->sc_fpregs[31]);
5464 __put_user(cpu_alpha_load_fpcr(env), &sc->sc_fpcr);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005465
Riku Voipio1d8b5122014-04-23 10:26:05 +03005466 __put_user(0, &sc->sc_traparg_a0); /* FIXME */
5467 __put_user(0, &sc->sc_traparg_a1); /* FIXME */
5468 __put_user(0, &sc->sc_traparg_a2); /* FIXME */
Richard Henderson6049f4f2009-12-27 18:30:03 -08005469}
5470
Riku Voipio016d2e12014-04-23 11:19:48 +03005471static void restore_sigcontext(CPUAlphaState *env,
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01005472 struct target_sigcontext *sc)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005473{
5474 uint64_t fpcr;
Riku Voipio016d2e12014-04-23 11:19:48 +03005475 int i;
Richard Henderson6049f4f2009-12-27 18:30:03 -08005476
Riku Voipio1d8b5122014-04-23 10:26:05 +03005477 __get_user(env->pc, &sc->sc_pc);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005478
5479 for (i = 0; i < 31; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03005480 __get_user(env->ir[i], &sc->sc_regs[i]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005481 }
5482 for (i = 0; i < 31; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03005483 __get_user(env->fir[i], &sc->sc_fpregs[i]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005484 }
5485
Riku Voipio1d8b5122014-04-23 10:26:05 +03005486 __get_user(fpcr, &sc->sc_fpcr);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005487 cpu_alpha_store_fpcr(env, fpcr);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005488}
5489
5490static inline abi_ulong get_sigframe(struct target_sigaction *sa,
Andreas Färber05390242012-02-25 03:37:53 +01005491 CPUAlphaState *env,
5492 unsigned long framesize)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005493{
5494 abi_ulong sp = env->ir[IR_SP];
5495
5496 /* This is the X/Open sanctioned signal stack switching. */
5497 if ((sa->sa_flags & TARGET_SA_ONSTACK) != 0 && !sas_ss_flags(sp)) {
5498 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
5499 }
5500 return (sp - framesize) & -32;
5501}
5502
5503static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01005504 target_sigset_t *set, CPUAlphaState *env)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005505{
5506 abi_ulong frame_addr, r26;
5507 struct target_sigframe *frame;
5508 int err = 0;
5509
5510 frame_addr = get_sigframe(ka, env, sizeof(*frame));
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01005511 trace_user_setup_frame(env, frame_addr);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005512 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
5513 goto give_sigsegv;
5514 }
5515
Riku Voipio41ecc722014-04-23 11:01:00 +03005516 setup_sigcontext(&frame->sc, env, frame_addr, set);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005517
5518 if (ka->sa_restorer) {
5519 r26 = ka->sa_restorer;
5520 } else {
Riku Voipio1d8b5122014-04-23 10:26:05 +03005521 __put_user(INSN_MOV_R30_R16, &frame->retcode[0]);
5522 __put_user(INSN_LDI_R0 + TARGET_NR_sigreturn,
5523 &frame->retcode[1]);
5524 __put_user(INSN_CALLSYS, &frame->retcode[2]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005525 /* imb() */
5526 r26 = frame_addr;
5527 }
5528
5529 unlock_user_struct(frame, frame_addr, 1);
5530
5531 if (err) {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01005532give_sigsegv:
Peter Maydell09391662016-07-28 16:44:47 +01005533 force_sigsegv(sig);
5534 return;
Richard Henderson6049f4f2009-12-27 18:30:03 -08005535 }
5536
5537 env->ir[IR_RA] = r26;
5538 env->ir[IR_PV] = env->pc = ka->_sa_handler;
5539 env->ir[IR_A0] = sig;
5540 env->ir[IR_A1] = 0;
5541 env->ir[IR_A2] = frame_addr + offsetof(struct target_sigframe, sc);
5542 env->ir[IR_SP] = frame_addr;
5543}
5544
5545static void setup_rt_frame(int sig, struct target_sigaction *ka,
5546 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01005547 target_sigset_t *set, CPUAlphaState *env)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005548{
5549 abi_ulong frame_addr, r26;
5550 struct target_rt_sigframe *frame;
5551 int i, err = 0;
5552
5553 frame_addr = get_sigframe(ka, env, sizeof(*frame));
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01005554 trace_user_setup_rt_frame(env, frame_addr);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005555 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
5556 goto give_sigsegv;
5557 }
5558
Peter Maydellf6c7a052015-01-08 12:19:48 +00005559 tswap_siginfo(&frame->info, info);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005560
Riku Voipio1d8b5122014-04-23 10:26:05 +03005561 __put_user(0, &frame->uc.tuc_flags);
5562 __put_user(0, &frame->uc.tuc_link);
5563 __put_user(set->sig[0], &frame->uc.tuc_osf_sigmask);
5564 __put_user(target_sigaltstack_used.ss_sp,
5565 &frame->uc.tuc_stack.ss_sp);
5566 __put_user(sas_ss_flags(env->ir[IR_SP]),
5567 &frame->uc.tuc_stack.ss_flags);
5568 __put_user(target_sigaltstack_used.ss_size,
5569 &frame->uc.tuc_stack.ss_size);
Riku Voipio41ecc722014-04-23 11:01:00 +03005570 setup_sigcontext(&frame->uc.tuc_mcontext, env, frame_addr, set);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005571 for (i = 0; i < TARGET_NSIG_WORDS; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03005572 __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005573 }
5574
5575 if (ka->sa_restorer) {
5576 r26 = ka->sa_restorer;
5577 } else {
Riku Voipio1d8b5122014-04-23 10:26:05 +03005578 __put_user(INSN_MOV_R30_R16, &frame->retcode[0]);
5579 __put_user(INSN_LDI_R0 + TARGET_NR_rt_sigreturn,
5580 &frame->retcode[1]);
5581 __put_user(INSN_CALLSYS, &frame->retcode[2]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005582 /* imb(); */
5583 r26 = frame_addr;
5584 }
5585
5586 if (err) {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01005587give_sigsegv:
Peter Maydell09391662016-07-28 16:44:47 +01005588 force_sigsegv(sig);
5589 return;
Richard Henderson6049f4f2009-12-27 18:30:03 -08005590 }
5591
5592 env->ir[IR_RA] = r26;
5593 env->ir[IR_PV] = env->pc = ka->_sa_handler;
5594 env->ir[IR_A0] = sig;
5595 env->ir[IR_A1] = frame_addr + offsetof(struct target_rt_sigframe, info);
5596 env->ir[IR_A2] = frame_addr + offsetof(struct target_rt_sigframe, uc);
5597 env->ir[IR_SP] = frame_addr;
5598}
5599
Andreas Färber05390242012-02-25 03:37:53 +01005600long do_sigreturn(CPUAlphaState *env)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005601{
5602 struct target_sigcontext *sc;
5603 abi_ulong sc_addr = env->ir[IR_A0];
5604 target_sigset_t target_set;
5605 sigset_t set;
5606
5607 if (!lock_user_struct(VERIFY_READ, sc, sc_addr, 1)) {
5608 goto badframe;
5609 }
5610
5611 target_sigemptyset(&target_set);
Riku Voipiof5f601a2014-04-23 13:00:17 +03005612 __get_user(target_set.sig[0], &sc->sc_mask);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005613
5614 target_to_host_sigset_internal(&set, &target_set);
Peter Maydell9eede5b2016-05-27 15:51:46 +01005615 set_sigmask(&set);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005616
Riku Voipio016d2e12014-04-23 11:19:48 +03005617 restore_sigcontext(env, sc);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005618 unlock_user_struct(sc, sc_addr, 0);
Timothy E Baldwin338c8582016-05-12 18:47:36 +01005619 return -TARGET_QEMU_ESIGRETURN;
Richard Henderson6049f4f2009-12-27 18:30:03 -08005620
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01005621badframe:
Richard Henderson6049f4f2009-12-27 18:30:03 -08005622 force_sig(TARGET_SIGSEGV);
5623}
5624
Andreas Färber05390242012-02-25 03:37:53 +01005625long do_rt_sigreturn(CPUAlphaState *env)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005626{
5627 abi_ulong frame_addr = env->ir[IR_A0];
5628 struct target_rt_sigframe *frame;
5629 sigset_t set;
5630
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01005631 trace_user_do_rt_sigreturn(env, frame_addr);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005632 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
5633 goto badframe;
5634 }
Aurelien Jarno60e99242010-03-29 02:12:51 +02005635 target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
Peter Maydell9eede5b2016-05-27 15:51:46 +01005636 set_sigmask(&set);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005637
Riku Voipio016d2e12014-04-23 11:19:48 +03005638 restore_sigcontext(env, &frame->uc.tuc_mcontext);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005639 if (do_sigaltstack(frame_addr + offsetof(struct target_rt_sigframe,
Aurelien Jarno60e99242010-03-29 02:12:51 +02005640 uc.tuc_stack),
Richard Henderson6049f4f2009-12-27 18:30:03 -08005641 0, env->ir[IR_SP]) == -EFAULT) {
5642 goto badframe;
5643 }
5644
5645 unlock_user_struct(frame, frame_addr, 0);
Timothy E Baldwin338c8582016-05-12 18:47:36 +01005646 return -TARGET_QEMU_ESIGRETURN;
Richard Henderson6049f4f2009-12-27 18:30:03 -08005647
5648
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01005649badframe:
Richard Henderson6049f4f2009-12-27 18:30:03 -08005650 unlock_user_struct(frame, frame_addr, 0);
5651 force_sig(TARGET_SIGSEGV);
5652}
5653
Chen Gangbf0f60a2015-09-27 08:10:18 +08005654#elif defined(TARGET_TILEGX)
5655
5656struct target_sigcontext {
5657 union {
5658 /* General-purpose registers. */
5659 abi_ulong gregs[56];
5660 struct {
5661 abi_ulong __gregs[53];
5662 abi_ulong tp; /* Aliases gregs[TREG_TP]. */
5663 abi_ulong sp; /* Aliases gregs[TREG_SP]. */
5664 abi_ulong lr; /* Aliases gregs[TREG_LR]. */
5665 };
5666 };
5667 abi_ulong pc; /* Program counter. */
5668 abi_ulong ics; /* In Interrupt Critical Section? */
5669 abi_ulong faultnum; /* Fault number. */
5670 abi_ulong pad[5];
5671};
5672
5673struct target_ucontext {
5674 abi_ulong tuc_flags;
5675 abi_ulong tuc_link;
5676 target_stack_t tuc_stack;
5677 struct target_sigcontext tuc_mcontext;
5678 target_sigset_t tuc_sigmask; /* mask last for extensibility */
5679};
5680
5681struct target_rt_sigframe {
5682 unsigned char save_area[16]; /* caller save area */
5683 struct target_siginfo info;
5684 struct target_ucontext uc;
Chen Gangf1d9d102016-03-29 21:53:49 +08005685 abi_ulong retcode[2];
Chen Gangbf0f60a2015-09-27 08:10:18 +08005686};
5687
Chen Gangf1d9d102016-03-29 21:53:49 +08005688#define INSN_MOVELI_R10_139 0x00045fe551483000ULL /* { moveli r10, 139 } */
5689#define INSN_SWINT1 0x286b180051485000ULL /* { swint1 } */
5690
5691
Chen Gangbf0f60a2015-09-27 08:10:18 +08005692static void setup_sigcontext(struct target_sigcontext *sc,
5693 CPUArchState *env, int signo)
5694{
5695 int i;
5696
5697 for (i = 0; i < TILEGX_R_COUNT; ++i) {
5698 __put_user(env->regs[i], &sc->gregs[i]);
5699 }
5700
5701 __put_user(env->pc, &sc->pc);
5702 __put_user(0, &sc->ics);
5703 __put_user(signo, &sc->faultnum);
5704}
5705
5706static void restore_sigcontext(CPUTLGState *env, struct target_sigcontext *sc)
5707{
5708 int i;
5709
5710 for (i = 0; i < TILEGX_R_COUNT; ++i) {
5711 __get_user(env->regs[i], &sc->gregs[i]);
5712 }
5713
5714 __get_user(env->pc, &sc->pc);
5715}
5716
5717static abi_ulong get_sigframe(struct target_sigaction *ka, CPUArchState *env,
5718 size_t frame_size)
5719{
5720 unsigned long sp = env->regs[TILEGX_R_SP];
5721
5722 if (on_sig_stack(sp) && !likely(on_sig_stack(sp - frame_size))) {
5723 return -1UL;
5724 }
5725
5726 if ((ka->sa_flags & SA_ONSTACK) && !sas_ss_flags(sp)) {
5727 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
5728 }
5729
5730 sp -= frame_size;
5731 sp &= -16UL;
5732 return sp;
5733}
5734
5735static void setup_rt_frame(int sig, struct target_sigaction *ka,
5736 target_siginfo_t *info,
5737 target_sigset_t *set, CPUArchState *env)
5738{
5739 abi_ulong frame_addr;
5740 struct target_rt_sigframe *frame;
5741 unsigned long restorer;
5742
5743 frame_addr = get_sigframe(ka, env, sizeof(*frame));
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01005744 trace_user_setup_rt_frame(env, frame_addr);
Chen Gangbf0f60a2015-09-27 08:10:18 +08005745 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
5746 goto give_sigsegv;
5747 }
5748
5749 /* Always write at least the signal number for the stack backtracer. */
5750 if (ka->sa_flags & TARGET_SA_SIGINFO) {
5751 /* At sigreturn time, restore the callee-save registers too. */
5752 tswap_siginfo(&frame->info, info);
5753 /* regs->flags |= PT_FLAGS_RESTORE_REGS; FIXME: we can skip it? */
5754 } else {
5755 __put_user(info->si_signo, &frame->info.si_signo);
5756 }
5757
5758 /* Create the ucontext. */
5759 __put_user(0, &frame->uc.tuc_flags);
5760 __put_user(0, &frame->uc.tuc_link);
5761 __put_user(target_sigaltstack_used.ss_sp, &frame->uc.tuc_stack.ss_sp);
5762 __put_user(sas_ss_flags(env->regs[TILEGX_R_SP]),
5763 &frame->uc.tuc_stack.ss_flags);
5764 __put_user(target_sigaltstack_used.ss_size, &frame->uc.tuc_stack.ss_size);
5765 setup_sigcontext(&frame->uc.tuc_mcontext, env, info->si_signo);
5766
Chen Gangbf0f60a2015-09-27 08:10:18 +08005767 if (ka->sa_flags & TARGET_SA_RESTORER) {
Chen Gangf1d9d102016-03-29 21:53:49 +08005768 restorer = (unsigned long) ka->sa_restorer;
5769 } else {
5770 __put_user(INSN_MOVELI_R10_139, &frame->retcode[0]);
5771 __put_user(INSN_SWINT1, &frame->retcode[1]);
5772 restorer = frame_addr + offsetof(struct target_rt_sigframe, retcode);
Chen Gangbf0f60a2015-09-27 08:10:18 +08005773 }
5774 env->pc = (unsigned long) ka->_sa_handler;
5775 env->regs[TILEGX_R_SP] = (unsigned long) frame;
5776 env->regs[TILEGX_R_LR] = restorer;
5777 env->regs[0] = (unsigned long) sig;
5778 env->regs[1] = (unsigned long) &frame->info;
5779 env->regs[2] = (unsigned long) &frame->uc;
5780 /* regs->flags |= PT_FLAGS_CALLER_SAVES; FIXME: we can skip it? */
5781
5782 unlock_user_struct(frame, frame_addr, 1);
5783 return;
5784
5785give_sigsegv:
Peter Maydell09391662016-07-28 16:44:47 +01005786 force_sigsegv(sig);
Chen Gangbf0f60a2015-09-27 08:10:18 +08005787}
5788
5789long do_rt_sigreturn(CPUTLGState *env)
5790{
5791 abi_ulong frame_addr = env->regs[TILEGX_R_SP];
5792 struct target_rt_sigframe *frame;
5793 sigset_t set;
5794
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01005795 trace_user_do_rt_sigreturn(env, frame_addr);
Chen Gangbf0f60a2015-09-27 08:10:18 +08005796 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
5797 goto badframe;
5798 }
5799 target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
Peter Maydell9eede5b2016-05-27 15:51:46 +01005800 set_sigmask(&set);
Chen Gangbf0f60a2015-09-27 08:10:18 +08005801
5802 restore_sigcontext(env, &frame->uc.tuc_mcontext);
5803 if (do_sigaltstack(frame_addr + offsetof(struct target_rt_sigframe,
5804 uc.tuc_stack),
5805 0, env->regs[TILEGX_R_SP]) == -EFAULT) {
5806 goto badframe;
5807 }
5808
5809 unlock_user_struct(frame, frame_addr, 0);
Peter Maydella9175162016-05-12 18:47:42 +01005810 return -TARGET_QEMU_ESIGRETURN;
Chen Gangbf0f60a2015-09-27 08:10:18 +08005811
5812
5813 badframe:
5814 unlock_user_struct(frame, frame_addr, 0);
5815 force_sig(TARGET_SIGSEGV);
5816}
5817
bellardb346ff42003-06-15 20:05:50 +00005818#else
5819
pbrook624f7972008-05-31 16:11:38 +00005820static void setup_frame(int sig, struct target_sigaction *ka,
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01005821 target_sigset_t *set, CPUArchState *env)
bellardb346ff42003-06-15 20:05:50 +00005822{
5823 fprintf(stderr, "setup_frame: not implemented\n");
5824}
5825
pbrook624f7972008-05-31 16:11:38 +00005826static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05005827 target_siginfo_t *info,
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01005828 target_sigset_t *set, CPUArchState *env)
bellardb346ff42003-06-15 20:05:50 +00005829{
5830 fprintf(stderr, "setup_rt_frame: not implemented\n");
5831}
5832
Andreas Färber9349b4f2012-03-14 01:38:32 +01005833long do_sigreturn(CPUArchState *env)
bellardb346ff42003-06-15 20:05:50 +00005834{
5835 fprintf(stderr, "do_sigreturn: not implemented\n");
bellardf8b0aa22007-11-11 23:03:42 +00005836 return -TARGET_ENOSYS;
bellardb346ff42003-06-15 20:05:50 +00005837}
5838
Andreas Färber9349b4f2012-03-14 01:38:32 +01005839long do_rt_sigreturn(CPUArchState *env)
bellardb346ff42003-06-15 20:05:50 +00005840{
5841 fprintf(stderr, "do_rt_sigreturn: not implemented\n");
bellardf8b0aa22007-11-11 23:03:42 +00005842 return -TARGET_ENOSYS;
bellardb346ff42003-06-15 20:05:50 +00005843}
5844
bellard66fb9762003-03-23 01:06:05 +00005845#endif
5846
Peter Maydell31efaef2016-07-06 15:09:29 +01005847static void handle_pending_signal(CPUArchState *cpu_env, int sig,
5848 struct emulated_sigtable *k)
Peter Maydelleb552502016-05-27 15:51:43 +01005849{
5850 CPUState *cpu = ENV_GET_CPU(cpu_env);
5851 abi_ulong handler;
Peter Maydell3d3efba2016-05-27 15:51:49 +01005852 sigset_t set;
Peter Maydelleb552502016-05-27 15:51:43 +01005853 target_sigset_t target_old_set;
5854 struct target_sigaction *sa;
Peter Maydelleb552502016-05-27 15:51:43 +01005855 TaskState *ts = cpu->opaque;
Peter Maydelleb552502016-05-27 15:51:43 +01005856
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01005857 trace_user_handle_signal(cpu_env, sig);
bellard66fb9762003-03-23 01:06:05 +00005858 /* dequeue signal */
Timothy E Baldwin907f5fd2016-05-27 15:51:52 +01005859 k->pending = 0;
ths3b46e622007-09-17 08:09:54 +00005860
Andreas Färberdb6b81d2013-06-27 19:49:31 +02005861 sig = gdb_handlesig(cpu, sig);
bellard1fddef42005-04-17 19:16:13 +00005862 if (!sig) {
aurel32ca587a82008-12-18 22:44:13 +00005863 sa = NULL;
5864 handler = TARGET_SIG_IGN;
5865 } else {
5866 sa = &sigact_table[sig - 1];
5867 handler = sa->_sa_handler;
bellard1fddef42005-04-17 19:16:13 +00005868 }
bellard66fb9762003-03-23 01:06:05 +00005869
Peter Maydell0cb581d2016-07-18 18:12:24 +01005870 if (do_strace) {
5871 print_taken_signal(sig, &k->info);
5872 }
5873
bellard66fb9762003-03-23 01:06:05 +00005874 if (handler == TARGET_SIG_DFL) {
aurel32ca587a82008-12-18 22:44:13 +00005875 /* default handler : ignore some signal. The other are job control or fatal */
5876 if (sig == TARGET_SIGTSTP || sig == TARGET_SIGTTIN || sig == TARGET_SIGTTOU) {
5877 kill(getpid(),SIGSTOP);
5878 } else if (sig != TARGET_SIGCHLD &&
5879 sig != TARGET_SIGURG &&
5880 sig != TARGET_SIGWINCH &&
5881 sig != TARGET_SIGCONT) {
bellard66fb9762003-03-23 01:06:05 +00005882 force_sig(sig);
5883 }
5884 } else if (handler == TARGET_SIG_IGN) {
5885 /* ignore sig */
5886 } else if (handler == TARGET_SIG_ERR) {
5887 force_sig(sig);
5888 } else {
bellard9de5e442003-03-23 16:49:39 +00005889 /* compute the blocked signals during the handler execution */
Peter Maydell3d3efba2016-05-27 15:51:49 +01005890 sigset_t *blocked_set;
5891
pbrook624f7972008-05-31 16:11:38 +00005892 target_to_host_sigset(&set, &sa->sa_mask);
bellard9de5e442003-03-23 16:49:39 +00005893 /* SA_NODEFER indicates that the current signal should not be
5894 blocked during the handler */
pbrook624f7972008-05-31 16:11:38 +00005895 if (!(sa->sa_flags & TARGET_SA_NODEFER))
bellard9de5e442003-03-23 16:49:39 +00005896 sigaddset(&set, target_to_host_signal(sig));
ths3b46e622007-09-17 08:09:54 +00005897
bellard9de5e442003-03-23 16:49:39 +00005898 /* save the previous blocked signal state to restore it at the
5899 end of the signal execution (see do_sigreturn) */
Peter Maydell3d3efba2016-05-27 15:51:49 +01005900 host_to_target_sigset_internal(&target_old_set, &ts->signal_mask);
5901
5902 /* block signals in the handler */
5903 blocked_set = ts->in_sigsuspend ?
5904 &ts->sigsuspend_mask : &ts->signal_mask;
5905 sigorset(&ts->signal_mask, blocked_set, &set);
5906 ts->in_sigsuspend = 0;
bellard9de5e442003-03-23 16:49:39 +00005907
bellardbc8a22c2003-03-30 21:02:40 +00005908 /* if the CPU is in VM86 mode, we restore the 32 bit values */
j_mayer84409dd2007-04-06 08:56:50 +00005909#if defined(TARGET_I386) && !defined(TARGET_X86_64)
bellardbc8a22c2003-03-30 21:02:40 +00005910 {
5911 CPUX86State *env = cpu_env;
5912 if (env->eflags & VM_MASK)
5913 save_v86_state(env);
5914 }
5915#endif
bellard9de5e442003-03-23 16:49:39 +00005916 /* prepare the stack frame of the virtual CPU */
Chen Gangd0924a22015-09-12 23:32:30 +08005917#if defined(TARGET_ABI_MIPSN32) || defined(TARGET_ABI_MIPSN64) \
Chen Gangbf0f60a2015-09-27 08:10:18 +08005918 || defined(TARGET_OPENRISC) || defined(TARGET_TILEGX)
Richard Hendersonff970902013-02-10 10:30:42 -08005919 /* These targets do not have traditional signals. */
Timothy E Baldwin907f5fd2016-05-27 15:51:52 +01005920 setup_rt_frame(sig, sa, &k->info, &target_old_set, cpu_env);
Richard Hendersonff970902013-02-10 10:30:42 -08005921#else
pbrook624f7972008-05-31 16:11:38 +00005922 if (sa->sa_flags & TARGET_SA_SIGINFO)
Timothy E Baldwin907f5fd2016-05-27 15:51:52 +01005923 setup_rt_frame(sig, sa, &k->info, &target_old_set, cpu_env);
bellard66fb9762003-03-23 01:06:05 +00005924 else
pbrook624f7972008-05-31 16:11:38 +00005925 setup_frame(sig, sa, &target_old_set, cpu_env);
Richard Hendersonff970902013-02-10 10:30:42 -08005926#endif
Peter Maydell7ec87e02016-05-27 15:51:45 +01005927 if (sa->sa_flags & TARGET_SA_RESETHAND) {
pbrook624f7972008-05-31 16:11:38 +00005928 sa->_sa_handler = TARGET_SIG_DFL;
Peter Maydell7ec87e02016-05-27 15:51:45 +01005929 }
bellard31e31b82003-02-18 22:55:36 +00005930 }
bellard31e31b82003-02-18 22:55:36 +00005931}
Peter Maydelle902d582016-05-27 15:51:44 +01005932
5933void process_pending_signals(CPUArchState *cpu_env)
5934{
5935 CPUState *cpu = ENV_GET_CPU(cpu_env);
5936 int sig;
5937 TaskState *ts = cpu->opaque;
Peter Maydell3d3efba2016-05-27 15:51:49 +01005938 sigset_t set;
5939 sigset_t *blocked_set;
Peter Maydelle902d582016-05-27 15:51:44 +01005940
Peter Maydell3d3efba2016-05-27 15:51:49 +01005941 while (atomic_read(&ts->signal_pending)) {
5942 /* FIXME: This is not threadsafe. */
5943 sigfillset(&set);
5944 sigprocmask(SIG_SETMASK, &set, 0);
Peter Maydelle902d582016-05-27 15:51:44 +01005945
Peter Maydell8bd37732016-07-28 16:44:45 +01005946 restart_scan:
Timothy E Baldwin655ed672016-05-27 15:51:53 +01005947 sig = ts->sync_signal.pending;
5948 if (sig) {
5949 /* Synchronous signals are forced,
5950 * see force_sig_info() and callers in Linux
5951 * Note that not all of our queue_signal() calls in QEMU correspond
5952 * to force_sig_info() calls in Linux (some are send_sig_info()).
5953 * However it seems like a kernel bug to me to allow the process
5954 * to block a synchronous signal since it could then just end up
5955 * looping round and round indefinitely.
5956 */
5957 if (sigismember(&ts->signal_mask, target_to_host_signal_table[sig])
5958 || sigact_table[sig - 1]._sa_handler == TARGET_SIG_IGN) {
5959 sigdelset(&ts->signal_mask, target_to_host_signal_table[sig]);
5960 sigact_table[sig - 1]._sa_handler = TARGET_SIG_DFL;
5961 }
5962
Peter Maydell31efaef2016-07-06 15:09:29 +01005963 handle_pending_signal(cpu_env, sig, &ts->sync_signal);
Timothy E Baldwin655ed672016-05-27 15:51:53 +01005964 }
5965
Peter Maydell3d3efba2016-05-27 15:51:49 +01005966 for (sig = 1; sig <= TARGET_NSIG; sig++) {
5967 blocked_set = ts->in_sigsuspend ?
5968 &ts->sigsuspend_mask : &ts->signal_mask;
5969
5970 if (ts->sigtab[sig - 1].pending &&
5971 (!sigismember(blocked_set,
Timothy E Baldwin655ed672016-05-27 15:51:53 +01005972 target_to_host_signal_table[sig]))) {
Peter Maydell31efaef2016-07-06 15:09:29 +01005973 handle_pending_signal(cpu_env, sig, &ts->sigtab[sig - 1]);
Peter Maydell8bd37732016-07-28 16:44:45 +01005974 /* Restart scan from the beginning, as handle_pending_signal
5975 * might have resulted in a new synchronous signal (eg SIGSEGV).
5976 */
5977 goto restart_scan;
Peter Maydell3d3efba2016-05-27 15:51:49 +01005978 }
Peter Maydelle902d582016-05-27 15:51:44 +01005979 }
Peter Maydell3d3efba2016-05-27 15:51:49 +01005980
5981 /* if no signal is pending, unblock signals and recheck (the act
5982 * of unblocking might cause us to take another host signal which
5983 * will set signal_pending again).
5984 */
5985 atomic_set(&ts->signal_pending, 0);
5986 ts->in_sigsuspend = 0;
5987 set = ts->signal_mask;
5988 sigdelset(&set, SIGSEGV);
5989 sigdelset(&set, SIGBUS);
5990 sigprocmask(SIG_SETMASK, &set, 0);
Peter Maydelle902d582016-05-27 15:51:44 +01005991 }
Peter Maydell3d3efba2016-05-27 15:51:49 +01005992 ts->in_sigsuspend = 0;
Peter Maydelle902d582016-05-27 15:51:44 +01005993}