blob: 04c21d0ccd9e0ef9320b091edae1937cace41389 [file] [log] [blame]
bellard31e31b82003-02-18 22:55:36 +00001/*
bellard66fb9762003-03-23 01:06:05 +00002 * Emulation of Linux signals
ths5fafdf22007-09-16 21:08:06 +00003 *
bellard31e31b82003-02-18 22:55:36 +00004 * Copyright (c) 2003 Fabrice Bellard
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
Blue Swirl8167ee82009-07-16 20:47:01 +000017 * along with this program; if not, see <http://www.gnu.org/licenses/>.
bellard31e31b82003-02-18 22:55:36 +000018 */
Peter Maydelld39594e2016-01-26 18:17:02 +000019#include "qemu/osdep.h"
bellard31e31b82003-02-18 22:55:36 +000020#include <sys/ucontext.h>
Mika Westerbergedf8e2a2009-04-07 09:57:11 +030021#include <sys/resource.h>
bellard31e31b82003-02-18 22:55:36 +000022
bellard3ef693a2003-03-23 20:17:16 +000023#include "qemu.h"
blueswir17d99a002009-01-14 19:00:36 +000024#include "qemu-common.h"
blueswir1992f48a2007-10-14 16:27:31 +000025#include "target_signal.h"
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +010026#include "trace.h"
bellard66fb9762003-03-23 01:06:05 +000027
blueswir1249c4c32008-10-05 11:09:37 +000028static struct target_sigaltstack target_sigaltstack_used = {
thsa04e1342007-09-27 13:57:58 +000029 .ss_sp = 0,
30 .ss_size = 0,
31 .ss_flags = TARGET_SS_DISABLE,
32};
33
pbrook624f7972008-05-31 16:11:38 +000034static struct target_sigaction sigact_table[TARGET_NSIG];
bellard31e31b82003-02-18 22:55:36 +000035
ths5fafdf22007-09-16 21:08:06 +000036static void host_signal_handler(int host_signum, siginfo_t *info,
bellard66fb9762003-03-23 01:06:05 +000037 void *puc);
38
Arnaud Patard3ca05582009-03-30 01:18:20 +020039static uint8_t host_to_target_signal_table[_NSIG] = {
bellard9e5f5282003-07-13 17:33:54 +000040 [SIGHUP] = TARGET_SIGHUP,
41 [SIGINT] = TARGET_SIGINT,
42 [SIGQUIT] = TARGET_SIGQUIT,
43 [SIGILL] = TARGET_SIGILL,
44 [SIGTRAP] = TARGET_SIGTRAP,
45 [SIGABRT] = TARGET_SIGABRT,
bellard01e3b762003-09-30 21:10:14 +000046/* [SIGIOT] = TARGET_SIGIOT,*/
bellard9e5f5282003-07-13 17:33:54 +000047 [SIGBUS] = TARGET_SIGBUS,
48 [SIGFPE] = TARGET_SIGFPE,
49 [SIGKILL] = TARGET_SIGKILL,
50 [SIGUSR1] = TARGET_SIGUSR1,
51 [SIGSEGV] = TARGET_SIGSEGV,
52 [SIGUSR2] = TARGET_SIGUSR2,
53 [SIGPIPE] = TARGET_SIGPIPE,
54 [SIGALRM] = TARGET_SIGALRM,
55 [SIGTERM] = TARGET_SIGTERM,
56#ifdef SIGSTKFLT
57 [SIGSTKFLT] = TARGET_SIGSTKFLT,
58#endif
59 [SIGCHLD] = TARGET_SIGCHLD,
60 [SIGCONT] = TARGET_SIGCONT,
61 [SIGSTOP] = TARGET_SIGSTOP,
62 [SIGTSTP] = TARGET_SIGTSTP,
63 [SIGTTIN] = TARGET_SIGTTIN,
64 [SIGTTOU] = TARGET_SIGTTOU,
65 [SIGURG] = TARGET_SIGURG,
66 [SIGXCPU] = TARGET_SIGXCPU,
67 [SIGXFSZ] = TARGET_SIGXFSZ,
68 [SIGVTALRM] = TARGET_SIGVTALRM,
69 [SIGPROF] = TARGET_SIGPROF,
70 [SIGWINCH] = TARGET_SIGWINCH,
71 [SIGIO] = TARGET_SIGIO,
72 [SIGPWR] = TARGET_SIGPWR,
73 [SIGSYS] = TARGET_SIGSYS,
74 /* next signals stay the same */
pbrook624f7972008-05-31 16:11:38 +000075 /* Nasty hack: Reverse SIGRTMIN and SIGRTMAX to avoid overlap with
Dong Xu Wangb4916d72011-11-22 18:06:17 +080076 host libpthread signals. This assumes no one actually uses SIGRTMAX :-/
pbrook624f7972008-05-31 16:11:38 +000077 To fix this properly we need to do manual signal delivery multiplexed
78 over a single host signal. */
79 [__SIGRTMIN] = __SIGRTMAX,
80 [__SIGRTMAX] = __SIGRTMIN,
bellard9e5f5282003-07-13 17:33:54 +000081};
Arnaud Patard3ca05582009-03-30 01:18:20 +020082static uint8_t target_to_host_signal_table[_NSIG];
bellard9e5f5282003-07-13 17:33:54 +000083
thsa04e1342007-09-27 13:57:58 +000084static inline int on_sig_stack(unsigned long sp)
85{
86 return (sp - target_sigaltstack_used.ss_sp
87 < target_sigaltstack_used.ss_size);
88}
89
90static inline int sas_ss_flags(unsigned long sp)
91{
92 return (target_sigaltstack_used.ss_size == 0 ? SS_DISABLE
93 : on_sig_stack(sp) ? SS_ONSTACK : 0);
94}
95
pbrook1d9d8b52009-04-16 15:17:02 +000096int host_to_target_signal(int sig)
bellard31e31b82003-02-18 22:55:36 +000097{
Andreas Schwab167c50d2013-07-02 14:04:12 +010098 if (sig < 0 || sig >= _NSIG)
pbrook4cb05962008-05-30 18:05:19 +000099 return sig;
bellard9e5f5282003-07-13 17:33:54 +0000100 return host_to_target_signal_table[sig];
bellard31e31b82003-02-18 22:55:36 +0000101}
102
pbrook4cb05962008-05-30 18:05:19 +0000103int target_to_host_signal(int sig)
bellard31e31b82003-02-18 22:55:36 +0000104{
Andreas Schwab167c50d2013-07-02 14:04:12 +0100105 if (sig < 0 || sig >= _NSIG)
pbrook4cb05962008-05-30 18:05:19 +0000106 return sig;
bellard9e5f5282003-07-13 17:33:54 +0000107 return target_to_host_signal_table[sig];
bellard31e31b82003-02-18 22:55:36 +0000108}
109
Anthony Liguoric227f092009-10-01 16:12:16 -0500110static inline void target_sigemptyset(target_sigset_t *set)
pbrookf5545b52008-05-30 22:37:07 +0000111{
112 memset(set, 0, sizeof(*set));
113}
114
Anthony Liguoric227f092009-10-01 16:12:16 -0500115static inline void target_sigaddset(target_sigset_t *set, int signum)
pbrookf5545b52008-05-30 22:37:07 +0000116{
117 signum--;
118 abi_ulong mask = (abi_ulong)1 << (signum % TARGET_NSIG_BPW);
119 set->sig[signum / TARGET_NSIG_BPW] |= mask;
120}
121
Anthony Liguoric227f092009-10-01 16:12:16 -0500122static inline int target_sigismember(const target_sigset_t *set, int signum)
pbrookf5545b52008-05-30 22:37:07 +0000123{
124 signum--;
125 abi_ulong mask = (abi_ulong)1 << (signum % TARGET_NSIG_BPW);
126 return ((set->sig[signum / TARGET_NSIG_BPW] & mask) != 0);
127}
128
Anthony Liguoric227f092009-10-01 16:12:16 -0500129static void host_to_target_sigset_internal(target_sigset_t *d,
bellard92319442004-06-19 16:58:13 +0000130 const sigset_t *s)
bellard66fb9762003-03-23 01:06:05 +0000131{
132 int i;
pbrookf5545b52008-05-30 22:37:07 +0000133 target_sigemptyset(d);
134 for (i = 1; i <= TARGET_NSIG; i++) {
135 if (sigismember(s, i)) {
136 target_sigaddset(d, host_to_target_signal(i));
137 }
bellard9e5f5282003-07-13 17:33:54 +0000138 }
bellard66fb9762003-03-23 01:06:05 +0000139}
140
Anthony Liguoric227f092009-10-01 16:12:16 -0500141void host_to_target_sigset(target_sigset_t *d, const sigset_t *s)
bellard92319442004-06-19 16:58:13 +0000142{
Anthony Liguoric227f092009-10-01 16:12:16 -0500143 target_sigset_t d1;
bellard92319442004-06-19 16:58:13 +0000144 int i;
145
146 host_to_target_sigset_internal(&d1, s);
147 for(i = 0;i < TARGET_NSIG_WORDS; i++)
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200148 d->sig[i] = tswapal(d1.sig[i]);
bellard92319442004-06-19 16:58:13 +0000149}
150
blueswir18fcd3692008-08-17 20:26:25 +0000151static void target_to_host_sigset_internal(sigset_t *d,
Anthony Liguoric227f092009-10-01 16:12:16 -0500152 const target_sigset_t *s)
bellard66fb9762003-03-23 01:06:05 +0000153{
154 int i;
pbrookf5545b52008-05-30 22:37:07 +0000155 sigemptyset(d);
156 for (i = 1; i <= TARGET_NSIG; i++) {
157 if (target_sigismember(s, i)) {
158 sigaddset(d, target_to_host_signal(i));
159 }
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100160 }
bellard66fb9762003-03-23 01:06:05 +0000161}
162
Anthony Liguoric227f092009-10-01 16:12:16 -0500163void target_to_host_sigset(sigset_t *d, const target_sigset_t *s)
bellard92319442004-06-19 16:58:13 +0000164{
Anthony Liguoric227f092009-10-01 16:12:16 -0500165 target_sigset_t s1;
bellard92319442004-06-19 16:58:13 +0000166 int i;
167
168 for(i = 0;i < TARGET_NSIG_WORDS; i++)
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200169 s1.sig[i] = tswapal(s->sig[i]);
bellard92319442004-06-19 16:58:13 +0000170 target_to_host_sigset_internal(d, &s1);
171}
ths3b46e622007-09-17 08:09:54 +0000172
blueswir1992f48a2007-10-14 16:27:31 +0000173void host_to_target_old_sigset(abi_ulong *old_sigset,
bellard66fb9762003-03-23 01:06:05 +0000174 const sigset_t *sigset)
175{
Anthony Liguoric227f092009-10-01 16:12:16 -0500176 target_sigset_t d;
bellard9e5f5282003-07-13 17:33:54 +0000177 host_to_target_sigset(&d, sigset);
178 *old_sigset = d.sig[0];
bellard66fb9762003-03-23 01:06:05 +0000179}
180
ths5fafdf22007-09-16 21:08:06 +0000181void target_to_host_old_sigset(sigset_t *sigset,
blueswir1992f48a2007-10-14 16:27:31 +0000182 const abi_ulong *old_sigset)
bellard66fb9762003-03-23 01:06:05 +0000183{
Anthony Liguoric227f092009-10-01 16:12:16 -0500184 target_sigset_t d;
bellard9e5f5282003-07-13 17:33:54 +0000185 int i;
186
187 d.sig[0] = *old_sigset;
188 for(i = 1;i < TARGET_NSIG_WORDS; i++)
189 d.sig[i] = 0;
190 target_to_host_sigset(sigset, &d);
bellard66fb9762003-03-23 01:06:05 +0000191}
192
Alex Barcelo1c275922014-03-14 14:36:55 +0000193/* Wrapper for sigprocmask function
194 * Emulates a sigprocmask in a safe way for the guest. Note that set and oldset
195 * are host signal set, not guest ones. This wraps the sigprocmask host calls
196 * that should be protected (calls originated from guest)
197 */
198int do_sigprocmask(int how, const sigset_t *set, sigset_t *oldset)
199{
Peter Maydella7ec0f92014-03-14 14:36:56 +0000200 int ret;
201 sigset_t val;
202 sigset_t *temp = NULL;
203 CPUState *cpu = thread_cpu;
204 TaskState *ts = (TaskState *)cpu->opaque;
205 bool segv_was_blocked = ts->sigsegv_blocked;
206
207 if (set) {
208 bool has_sigsegv = sigismember(set, SIGSEGV);
209 val = *set;
210 temp = &val;
211
212 sigdelset(temp, SIGSEGV);
213
214 switch (how) {
215 case SIG_BLOCK:
216 if (has_sigsegv) {
217 ts->sigsegv_blocked = true;
218 }
219 break;
220 case SIG_UNBLOCK:
221 if (has_sigsegv) {
222 ts->sigsegv_blocked = false;
223 }
224 break;
225 case SIG_SETMASK:
226 ts->sigsegv_blocked = has_sigsegv;
227 break;
228 default:
229 g_assert_not_reached();
230 }
231 }
232
233 ret = sigprocmask(how, temp, oldset);
234
235 if (oldset && segv_was_blocked) {
236 sigaddset(oldset, SIGSEGV);
237 }
238
239 return ret;
Alex Barcelo1c275922014-03-14 14:36:55 +0000240}
241
bellard9de5e442003-03-23 16:49:39 +0000242/* siginfo conversion */
243
Anthony Liguoric227f092009-10-01 16:12:16 -0500244static inline void host_to_target_siginfo_noswap(target_siginfo_t *tinfo,
bellard9de5e442003-03-23 16:49:39 +0000245 const siginfo_t *info)
bellard66fb9762003-03-23 01:06:05 +0000246{
Richard Hendersona05c6402012-09-15 11:34:20 -0700247 int sig = host_to_target_signal(info->si_signo);
bellard9de5e442003-03-23 16:49:39 +0000248 tinfo->si_signo = sig;
249 tinfo->si_errno = 0;
pbrookafd7cd92008-05-31 12:14:21 +0000250 tinfo->si_code = info->si_code;
Richard Hendersona05c6402012-09-15 11:34:20 -0700251
252 if (sig == TARGET_SIGILL || sig == TARGET_SIGFPE || sig == TARGET_SIGSEGV
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100253 || sig == TARGET_SIGBUS || sig == TARGET_SIGTRAP) {
Richard Hendersona05c6402012-09-15 11:34:20 -0700254 /* Should never come here, but who knows. The information for
255 the target is irrelevant. */
bellard9de5e442003-03-23 16:49:39 +0000256 tinfo->_sifields._sigfault._addr = 0;
Richard Hendersona05c6402012-09-15 11:34:20 -0700257 } else if (sig == TARGET_SIGIO) {
258 tinfo->_sifields._sigpoll._band = info->si_band;
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100259 tinfo->_sifields._sigpoll._fd = info->si_fd;
Richard Hendersona05c6402012-09-15 11:34:20 -0700260 } else if (sig == TARGET_SIGCHLD) {
261 tinfo->_sifields._sigchld._pid = info->si_pid;
262 tinfo->_sifields._sigchld._uid = info->si_uid;
263 tinfo->_sifields._sigchld._status
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100264 = host_to_target_waitstatus(info->si_status);
Richard Hendersona05c6402012-09-15 11:34:20 -0700265 tinfo->_sifields._sigchld._utime = info->si_utime;
266 tinfo->_sifields._sigchld._stime = info->si_stime;
bellard9de5e442003-03-23 16:49:39 +0000267 } else if (sig >= TARGET_SIGRTMIN) {
268 tinfo->_sifields._rt._pid = info->si_pid;
269 tinfo->_sifields._rt._uid = info->si_uid;
270 /* XXX: potential problem if 64 bit */
Richard Hendersona05c6402012-09-15 11:34:20 -0700271 tinfo->_sifields._rt._sigval.sival_ptr
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100272 = (abi_ulong)(unsigned long)info->si_value.sival_ptr;
bellard9de5e442003-03-23 16:49:39 +0000273 }
bellard66fb9762003-03-23 01:06:05 +0000274}
275
Anthony Liguoric227f092009-10-01 16:12:16 -0500276static void tswap_siginfo(target_siginfo_t *tinfo,
277 const target_siginfo_t *info)
bellard9de5e442003-03-23 16:49:39 +0000278{
Richard Hendersona05c6402012-09-15 11:34:20 -0700279 int sig = info->si_signo;
bellard9de5e442003-03-23 16:49:39 +0000280 tinfo->si_signo = tswap32(sig);
281 tinfo->si_errno = tswap32(info->si_errno);
282 tinfo->si_code = tswap32(info->si_code);
Richard Hendersona05c6402012-09-15 11:34:20 -0700283
284 if (sig == TARGET_SIGILL || sig == TARGET_SIGFPE || sig == TARGET_SIGSEGV
285 || sig == TARGET_SIGBUS || sig == TARGET_SIGTRAP) {
286 tinfo->_sifields._sigfault._addr
287 = tswapal(info->_sifields._sigfault._addr);
288 } else if (sig == TARGET_SIGIO) {
289 tinfo->_sifields._sigpoll._band
290 = tswap32(info->_sifields._sigpoll._band);
291 tinfo->_sifields._sigpoll._fd = tswap32(info->_sifields._sigpoll._fd);
292 } else if (sig == TARGET_SIGCHLD) {
293 tinfo->_sifields._sigchld._pid
294 = tswap32(info->_sifields._sigchld._pid);
295 tinfo->_sifields._sigchld._uid
296 = tswap32(info->_sifields._sigchld._uid);
297 tinfo->_sifields._sigchld._status
298 = tswap32(info->_sifields._sigchld._status);
299 tinfo->_sifields._sigchld._utime
300 = tswapal(info->_sifields._sigchld._utime);
301 tinfo->_sifields._sigchld._stime
302 = tswapal(info->_sifields._sigchld._stime);
bellard9de5e442003-03-23 16:49:39 +0000303 } else if (sig >= TARGET_SIGRTMIN) {
304 tinfo->_sifields._rt._pid = tswap32(info->_sifields._rt._pid);
305 tinfo->_sifields._rt._uid = tswap32(info->_sifields._rt._uid);
Richard Hendersona05c6402012-09-15 11:34:20 -0700306 tinfo->_sifields._rt._sigval.sival_ptr
307 = tswapal(info->_sifields._rt._sigval.sival_ptr);
bellard9de5e442003-03-23 16:49:39 +0000308 }
309}
310
311
Anthony Liguoric227f092009-10-01 16:12:16 -0500312void host_to_target_siginfo(target_siginfo_t *tinfo, const siginfo_t *info)
bellard9de5e442003-03-23 16:49:39 +0000313{
314 host_to_target_siginfo_noswap(tinfo, info);
315 tswap_siginfo(tinfo, tinfo);
316}
317
318/* XXX: we support only POSIX RT signals are used. */
thsaa1f17c2007-07-11 22:48:58 +0000319/* XXX: find a solution for 64 bit (additional malloced data is needed) */
Anthony Liguoric227f092009-10-01 16:12:16 -0500320void target_to_host_siginfo(siginfo_t *info, const target_siginfo_t *tinfo)
bellard66fb9762003-03-23 01:06:05 +0000321{
322 info->si_signo = tswap32(tinfo->si_signo);
323 info->si_errno = tswap32(tinfo->si_errno);
324 info->si_code = tswap32(tinfo->si_code);
bellard9de5e442003-03-23 16:49:39 +0000325 info->si_pid = tswap32(tinfo->_sifields._rt._pid);
326 info->si_uid = tswap32(tinfo->_sifields._rt._uid);
ths5fafdf22007-09-16 21:08:06 +0000327 info->si_value.sival_ptr =
Matthias Brauncbb21ee2011-08-12 19:57:41 +0200328 (void *)(long)tswapal(tinfo->_sifields._rt._sigval.sival_ptr);
bellard66fb9762003-03-23 01:06:05 +0000329}
330
aurel32ca587a82008-12-18 22:44:13 +0000331static int fatal_signal (int sig)
332{
333 switch (sig) {
334 case TARGET_SIGCHLD:
335 case TARGET_SIGURG:
336 case TARGET_SIGWINCH:
337 /* Ignored by default. */
338 return 0;
339 case TARGET_SIGCONT:
340 case TARGET_SIGSTOP:
341 case TARGET_SIGTSTP:
342 case TARGET_SIGTTIN:
343 case TARGET_SIGTTOU:
344 /* Job control signals. */
345 return 0;
346 default:
347 return 1;
348 }
349}
350
Mika Westerbergedf8e2a2009-04-07 09:57:11 +0300351/* returns 1 if given signal should dump core if not handled */
352static int core_dump_signal(int sig)
353{
354 switch (sig) {
355 case TARGET_SIGABRT:
356 case TARGET_SIGFPE:
357 case TARGET_SIGILL:
358 case TARGET_SIGQUIT:
359 case TARGET_SIGSEGV:
360 case TARGET_SIGTRAP:
361 case TARGET_SIGBUS:
362 return (1);
363 default:
364 return (0);
365 }
366}
367
bellard31e31b82003-02-18 22:55:36 +0000368void signal_init(void)
369{
370 struct sigaction act;
pbrook624f7972008-05-31 16:11:38 +0000371 struct sigaction oact;
bellard9e5f5282003-07-13 17:33:54 +0000372 int i, j;
pbrook624f7972008-05-31 16:11:38 +0000373 int host_sig;
bellard31e31b82003-02-18 22:55:36 +0000374
bellard9e5f5282003-07-13 17:33:54 +0000375 /* generate signal conversion tables */
Arnaud Patard3ca05582009-03-30 01:18:20 +0200376 for(i = 1; i < _NSIG; i++) {
bellard9e5f5282003-07-13 17:33:54 +0000377 if (host_to_target_signal_table[i] == 0)
378 host_to_target_signal_table[i] = i;
379 }
Arnaud Patard3ca05582009-03-30 01:18:20 +0200380 for(i = 1; i < _NSIG; i++) {
bellard9e5f5282003-07-13 17:33:54 +0000381 j = host_to_target_signal_table[i];
382 target_to_host_signal_table[j] = i;
383 }
ths3b46e622007-09-17 08:09:54 +0000384
bellard9de5e442003-03-23 16:49:39 +0000385 /* set all host signal handlers. ALL signals are blocked during
386 the handlers to serialize them. */
pbrook624f7972008-05-31 16:11:38 +0000387 memset(sigact_table, 0, sizeof(sigact_table));
388
bellard9de5e442003-03-23 16:49:39 +0000389 sigfillset(&act.sa_mask);
bellard31e31b82003-02-18 22:55:36 +0000390 act.sa_flags = SA_SIGINFO;
391 act.sa_sigaction = host_signal_handler;
pbrook624f7972008-05-31 16:11:38 +0000392 for(i = 1; i <= TARGET_NSIG; i++) {
393 host_sig = target_to_host_signal(i);
394 sigaction(host_sig, NULL, &oact);
395 if (oact.sa_sigaction == (void *)SIG_IGN) {
396 sigact_table[i - 1]._sa_handler = TARGET_SIG_IGN;
397 } else if (oact.sa_sigaction == (void *)SIG_DFL) {
398 sigact_table[i - 1]._sa_handler = TARGET_SIG_DFL;
399 }
400 /* If there's already a handler installed then something has
401 gone horribly wrong, so don't even try to handle that case. */
aurel32ca587a82008-12-18 22:44:13 +0000402 /* Install some handlers for our own use. We need at least
403 SIGSEGV and SIGBUS, to detect exceptions. We can not just
404 trap all signals because it affects syscall interrupt
405 behavior. But do trap all default-fatal signals. */
406 if (fatal_signal (i))
pbrook624f7972008-05-31 16:11:38 +0000407 sigaction(host_sig, &act, NULL);
bellard31e31b82003-02-18 22:55:36 +0000408 }
bellard31e31b82003-02-18 22:55:36 +0000409}
410
bellard66fb9762003-03-23 01:06:05 +0000411/* signal queue handling */
412
Andreas Färber9349b4f2012-03-14 01:38:32 +0100413static inline struct sigqueue *alloc_sigqueue(CPUArchState *env)
bellard66fb9762003-03-23 01:06:05 +0000414{
Andreas Färber0429a972013-08-26 18:14:44 +0200415 CPUState *cpu = ENV_GET_CPU(env);
416 TaskState *ts = cpu->opaque;
pbrook624f7972008-05-31 16:11:38 +0000417 struct sigqueue *q = ts->first_free;
bellard66fb9762003-03-23 01:06:05 +0000418 if (!q)
419 return NULL;
pbrook624f7972008-05-31 16:11:38 +0000420 ts->first_free = q->next;
bellard66fb9762003-03-23 01:06:05 +0000421 return q;
422}
423
Andreas Färber9349b4f2012-03-14 01:38:32 +0100424static inline void free_sigqueue(CPUArchState *env, struct sigqueue *q)
bellard66fb9762003-03-23 01:06:05 +0000425{
Andreas Färber0429a972013-08-26 18:14:44 +0200426 CPUState *cpu = ENV_GET_CPU(env);
427 TaskState *ts = cpu->opaque;
428
pbrook624f7972008-05-31 16:11:38 +0000429 q->next = ts->first_free;
430 ts->first_free = q;
bellard66fb9762003-03-23 01:06:05 +0000431}
432
bellard9de5e442003-03-23 16:49:39 +0000433/* abort execution with signal */
Riku Voipio66393fb2009-12-04 15:16:32 +0200434static void QEMU_NORETURN force_sig(int target_sig)
bellard66fb9762003-03-23 01:06:05 +0000435{
Andreas Färber0429a972013-08-26 18:14:44 +0200436 CPUState *cpu = thread_cpu;
437 CPUArchState *env = cpu->env_ptr;
438 TaskState *ts = (TaskState *)cpu->opaque;
Mika Westerbergedf8e2a2009-04-07 09:57:11 +0300439 int host_sig, core_dumped = 0;
aurel32603e4fd2009-04-15 16:18:38 +0000440 struct sigaction act;
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +0100441
Riku Voipio66393fb2009-12-04 15:16:32 +0200442 host_sig = target_to_host_signal(target_sig);
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +0100443 trace_user_force_sig(env, target_sig, host_sig);
Andreas Färbera2247f82013-06-09 19:47:04 +0200444 gdb_signalled(env, target_sig);
aurel32603e4fd2009-04-15 16:18:38 +0000445
Mika Westerbergedf8e2a2009-04-07 09:57:11 +0300446 /* dump core if supported by target binary format */
Riku Voipio66393fb2009-12-04 15:16:32 +0200447 if (core_dump_signal(target_sig) && (ts->bprm->core_dump != NULL)) {
Mika Westerbergedf8e2a2009-04-07 09:57:11 +0300448 stop_all_tasks();
449 core_dumped =
Andreas Färbera2247f82013-06-09 19:47:04 +0200450 ((*ts->bprm->core_dump)(target_sig, env) == 0);
Mika Westerbergedf8e2a2009-04-07 09:57:11 +0300451 }
452 if (core_dumped) {
453 /* we already dumped the core of target process, we don't want
454 * a coredump of qemu itself */
455 struct rlimit nodump;
456 getrlimit(RLIMIT_CORE, &nodump);
457 nodump.rlim_cur=0;
458 setrlimit(RLIMIT_CORE, &nodump);
459 (void) fprintf(stderr, "qemu: uncaught target signal %d (%s) - %s\n",
Riku Voipio66393fb2009-12-04 15:16:32 +0200460 target_sig, strsignal(host_sig), "core dumped" );
Mika Westerbergedf8e2a2009-04-07 09:57:11 +0300461 }
462
Stefan Weil0c587512011-04-28 17:20:32 +0200463 /* The proper exit code for dying from an uncaught signal is
aurel32603e4fd2009-04-15 16:18:38 +0000464 * -<signal>. The kernel doesn't allow exit() or _exit() to pass
465 * a negative value. To get the proper exit code we need to
466 * actually die from an uncaught signal. Here the default signal
467 * handler is installed, we send ourself a signal and we wait for
468 * it to arrive. */
469 sigfillset(&act.sa_mask);
470 act.sa_handler = SIG_DFL;
Peter Maydell3a5d30b2014-02-17 18:55:32 +0000471 act.sa_flags = 0;
aurel32603e4fd2009-04-15 16:18:38 +0000472 sigaction(host_sig, &act, NULL);
473
474 /* For some reason raise(host_sig) doesn't send the signal when
475 * statically linked on x86-64. */
476 kill(getpid(), host_sig);
477
478 /* Make sure the signal isn't masked (just reuse the mask inside
479 of act) */
480 sigdelset(&act.sa_mask, host_sig);
481 sigsuspend(&act.sa_mask);
482
483 /* unreachable */
Blue Swirla6c6f762010-03-13 14:18:50 +0000484 abort();
bellard66fb9762003-03-23 01:06:05 +0000485}
486
bellard9de5e442003-03-23 16:49:39 +0000487/* queue a signal so that it will be send to the virtual CPU as soon
488 as possible */
Andreas Färber9349b4f2012-03-14 01:38:32 +0100489int queue_signal(CPUArchState *env, int sig, target_siginfo_t *info)
bellard31e31b82003-02-18 22:55:36 +0000490{
Andreas Färber0429a972013-08-26 18:14:44 +0200491 CPUState *cpu = ENV_GET_CPU(env);
492 TaskState *ts = cpu->opaque;
pbrook624f7972008-05-31 16:11:38 +0000493 struct emulated_sigtable *k;
bellard9de5e442003-03-23 16:49:39 +0000494 struct sigqueue *q, **pq;
blueswir1992f48a2007-10-14 16:27:31 +0000495 abi_ulong handler;
aurel32ca587a82008-12-18 22:44:13 +0000496 int queue;
bellard66fb9762003-03-23 01:06:05 +0000497
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +0100498 trace_user_queue_signal(env, sig);
pbrook624f7972008-05-31 16:11:38 +0000499 k = &ts->sigtab[sig - 1];
aurel32ca587a82008-12-18 22:44:13 +0000500 queue = gdb_queuesig ();
pbrook624f7972008-05-31 16:11:38 +0000501 handler = sigact_table[sig - 1]._sa_handler;
Peter Maydella7ec0f92014-03-14 14:36:56 +0000502
503 if (ts->sigsegv_blocked && sig == TARGET_SIGSEGV) {
504 /* Guest has blocked SIGSEGV but we got one anyway. Assume this
505 * is a forced SIGSEGV (ie one the kernel handles via force_sig_info
506 * because it got a real MMU fault). A blocked SIGSEGV in that
507 * situation is treated as if using the default handler. This is
508 * not correct if some other process has randomly sent us a SIGSEGV
509 * via kill(), but that is not easy to distinguish at this point,
510 * so we assume it doesn't happen.
511 */
512 handler = TARGET_SIG_DFL;
513 }
514
aurel32ca587a82008-12-18 22:44:13 +0000515 if (!queue && handler == TARGET_SIG_DFL) {
ths60b19692008-11-27 15:47:15 +0000516 if (sig == TARGET_SIGTSTP || sig == TARGET_SIGTTIN || sig == TARGET_SIGTTOU) {
517 kill(getpid(),SIGSTOP);
518 return 0;
519 } else
bellard66fb9762003-03-23 01:06:05 +0000520 /* default handler : ignore some signal. The other are fatal */
ths5fafdf22007-09-16 21:08:06 +0000521 if (sig != TARGET_SIGCHLD &&
522 sig != TARGET_SIGURG &&
ths60b19692008-11-27 15:47:15 +0000523 sig != TARGET_SIGWINCH &&
524 sig != TARGET_SIGCONT) {
bellard66fb9762003-03-23 01:06:05 +0000525 force_sig(sig);
bellard9de5e442003-03-23 16:49:39 +0000526 } else {
527 return 0; /* indicate ignored */
bellard66fb9762003-03-23 01:06:05 +0000528 }
aurel32ca587a82008-12-18 22:44:13 +0000529 } else if (!queue && handler == TARGET_SIG_IGN) {
bellard66fb9762003-03-23 01:06:05 +0000530 /* ignore signal */
bellard9de5e442003-03-23 16:49:39 +0000531 return 0;
aurel32ca587a82008-12-18 22:44:13 +0000532 } else if (!queue && handler == TARGET_SIG_ERR) {
bellard66fb9762003-03-23 01:06:05 +0000533 force_sig(sig);
534 } else {
bellard9de5e442003-03-23 16:49:39 +0000535 pq = &k->first;
536 if (sig < TARGET_SIGRTMIN) {
537 /* if non real time signal, we queue exactly one signal */
538 if (!k->pending)
539 q = &k->info;
540 else
541 return 0;
542 } else {
543 if (!k->pending) {
544 /* first signal */
545 q = &k->info;
546 } else {
pbrook624f7972008-05-31 16:11:38 +0000547 q = alloc_sigqueue(env);
bellard9de5e442003-03-23 16:49:39 +0000548 if (!q)
549 return -EAGAIN;
550 while (*pq != NULL)
551 pq = &(*pq)->next;
552 }
553 }
554 *pq = q;
555 q->info = *info;
556 q->next = NULL;
557 k->pending = 1;
558 /* signal that a new signal is pending */
pbrook624f7972008-05-31 16:11:38 +0000559 ts->signal_pending = 1;
bellard9de5e442003-03-23 16:49:39 +0000560 return 1; /* indicates that the signal was queued */
561 }
562}
563
ths5fafdf22007-09-16 21:08:06 +0000564static void host_signal_handler(int host_signum, siginfo_t *info,
bellard9de5e442003-03-23 16:49:39 +0000565 void *puc)
566{
Andreas Färbera2247f82013-06-09 19:47:04 +0200567 CPUArchState *env = thread_cpu->env_ptr;
bellard9de5e442003-03-23 16:49:39 +0000568 int sig;
Anthony Liguoric227f092009-10-01 16:12:16 -0500569 target_siginfo_t tinfo;
bellard9de5e442003-03-23 16:49:39 +0000570
571 /* the CPU emulator uses some host signals to detect exceptions,
aurel32eaa449b2009-01-03 13:14:52 +0000572 we forward to it some signals */
aurel32ca587a82008-12-18 22:44:13 +0000573 if ((host_signum == SIGSEGV || host_signum == SIGBUS)
aurel32eaa449b2009-01-03 13:14:52 +0000574 && info->si_code > 0) {
bellardb346ff42003-06-15 20:05:50 +0000575 if (cpu_signal_handler(host_signum, info, puc))
bellard9de5e442003-03-23 16:49:39 +0000576 return;
577 }
578
579 /* get target signal number */
580 sig = host_to_target_signal(host_signum);
581 if (sig < 1 || sig > TARGET_NSIG)
582 return;
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +0100583 trace_user_host_signal(env, host_signum, sig);
bellard9de5e442003-03-23 16:49:39 +0000584 host_to_target_siginfo_noswap(&tinfo, info);
Andreas Färbera2247f82013-06-09 19:47:04 +0200585 if (queue_signal(env, sig, &tinfo) == 1) {
bellard9de5e442003-03-23 16:49:39 +0000586 /* interrupt the virtual CPU as soon as possible */
Andreas Färbera2247f82013-06-09 19:47:04 +0200587 cpu_exit(thread_cpu);
bellard66fb9762003-03-23 01:06:05 +0000588 }
bellard31e31b82003-02-18 22:55:36 +0000589}
590
ths0da46a62007-10-20 20:23:07 +0000591/* do_sigaltstack() returns target values and errnos. */
bellard579a97f2007-11-11 14:26:47 +0000592/* compare linux/kernel/signal.c:do_sigaltstack() */
593abi_long do_sigaltstack(abi_ulong uss_addr, abi_ulong uoss_addr, abi_ulong sp)
thsa04e1342007-09-27 13:57:58 +0000594{
595 int ret;
596 struct target_sigaltstack oss;
597
598 /* XXX: test errors */
bellard579a97f2007-11-11 14:26:47 +0000599 if(uoss_addr)
thsa04e1342007-09-27 13:57:58 +0000600 {
601 __put_user(target_sigaltstack_used.ss_sp, &oss.ss_sp);
602 __put_user(target_sigaltstack_used.ss_size, &oss.ss_size);
603 __put_user(sas_ss_flags(sp), &oss.ss_flags);
604 }
605
bellard579a97f2007-11-11 14:26:47 +0000606 if(uss_addr)
thsa04e1342007-09-27 13:57:58 +0000607 {
bellard579a97f2007-11-11 14:26:47 +0000608 struct target_sigaltstack *uss;
609 struct target_sigaltstack ss;
Tom Musta0903c8b2014-08-12 13:53:40 -0500610 size_t minstacksize = TARGET_MINSIGSTKSZ;
611
612#if defined(TARGET_PPC64)
613 /* ELF V2 for PPC64 has a 4K minimum stack size for signal handlers */
614 struct image_info *image = ((TaskState *)thread_cpu->opaque)->info;
615 if (get_ppc64_abi(image) > 1) {
616 minstacksize = 4096;
617 }
618#endif
thsa04e1342007-09-27 13:57:58 +0000619
ths0da46a62007-10-20 20:23:07 +0000620 ret = -TARGET_EFAULT;
Riku Voipio9eeb8302014-04-23 11:26:34 +0300621 if (!lock_user_struct(VERIFY_READ, uss, uss_addr, 1)) {
thsa04e1342007-09-27 13:57:58 +0000622 goto out;
Riku Voipio9eeb8302014-04-23 11:26:34 +0300623 }
624 __get_user(ss.ss_sp, &uss->ss_sp);
625 __get_user(ss.ss_size, &uss->ss_size);
626 __get_user(ss.ss_flags, &uss->ss_flags);
bellard579a97f2007-11-11 14:26:47 +0000627 unlock_user_struct(uss, uss_addr, 0);
thsa04e1342007-09-27 13:57:58 +0000628
ths0da46a62007-10-20 20:23:07 +0000629 ret = -TARGET_EPERM;
thsa04e1342007-09-27 13:57:58 +0000630 if (on_sig_stack(sp))
631 goto out;
632
ths0da46a62007-10-20 20:23:07 +0000633 ret = -TARGET_EINVAL;
thsa04e1342007-09-27 13:57:58 +0000634 if (ss.ss_flags != TARGET_SS_DISABLE
635 && ss.ss_flags != TARGET_SS_ONSTACK
636 && ss.ss_flags != 0)
637 goto out;
638
639 if (ss.ss_flags == TARGET_SS_DISABLE) {
640 ss.ss_size = 0;
641 ss.ss_sp = 0;
642 } else {
ths0da46a62007-10-20 20:23:07 +0000643 ret = -TARGET_ENOMEM;
Tom Musta0903c8b2014-08-12 13:53:40 -0500644 if (ss.ss_size < minstacksize) {
thsa04e1342007-09-27 13:57:58 +0000645 goto out;
Tom Musta0903c8b2014-08-12 13:53:40 -0500646 }
thsa04e1342007-09-27 13:57:58 +0000647 }
648
649 target_sigaltstack_used.ss_sp = ss.ss_sp;
650 target_sigaltstack_used.ss_size = ss.ss_size;
651 }
652
bellard579a97f2007-11-11 14:26:47 +0000653 if (uoss_addr) {
ths0da46a62007-10-20 20:23:07 +0000654 ret = -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +0000655 if (copy_to_user(uoss_addr, &oss, sizeof(oss)))
thsa04e1342007-09-27 13:57:58 +0000656 goto out;
thsa04e1342007-09-27 13:57:58 +0000657 }
658
659 ret = 0;
660out:
661 return ret;
662}
663
ths0da46a62007-10-20 20:23:07 +0000664/* do_sigaction() return host values and errnos */
bellard66fb9762003-03-23 01:06:05 +0000665int do_sigaction(int sig, const struct target_sigaction *act,
666 struct target_sigaction *oact)
bellard31e31b82003-02-18 22:55:36 +0000667{
pbrook624f7972008-05-31 16:11:38 +0000668 struct target_sigaction *k;
bellard773b93e2004-01-04 17:15:59 +0000669 struct sigaction act1;
670 int host_sig;
ths0da46a62007-10-20 20:23:07 +0000671 int ret = 0;
bellard31e31b82003-02-18 22:55:36 +0000672
ths2a913eb2008-11-27 15:46:25 +0000673 if (sig < 1 || sig > TARGET_NSIG || sig == TARGET_SIGKILL || sig == TARGET_SIGSTOP)
bellard66fb9762003-03-23 01:06:05 +0000674 return -EINVAL;
675 k = &sigact_table[sig - 1];
bellard66fb9762003-03-23 01:06:05 +0000676 if (oact) {
Richard Hendersond2565872013-01-04 16:39:32 -0800677 __put_user(k->_sa_handler, &oact->_sa_handler);
678 __put_user(k->sa_flags, &oact->sa_flags);
ths388bb212007-05-13 13:58:00 +0000679#if !defined(TARGET_MIPS)
Richard Hendersond2565872013-01-04 16:39:32 -0800680 __put_user(k->sa_restorer, &oact->sa_restorer);
ths388bb212007-05-13 13:58:00 +0000681#endif
Richard Hendersond2565872013-01-04 16:39:32 -0800682 /* Not swapped. */
pbrook624f7972008-05-31 16:11:38 +0000683 oact->sa_mask = k->sa_mask;
bellard66fb9762003-03-23 01:06:05 +0000684 }
685 if (act) {
pbrook624f7972008-05-31 16:11:38 +0000686 /* FIXME: This is not threadsafe. */
Richard Hendersond2565872013-01-04 16:39:32 -0800687 __get_user(k->_sa_handler, &act->_sa_handler);
688 __get_user(k->sa_flags, &act->sa_flags);
ths388bb212007-05-13 13:58:00 +0000689#if !defined(TARGET_MIPS)
Richard Hendersond2565872013-01-04 16:39:32 -0800690 __get_user(k->sa_restorer, &act->sa_restorer);
ths388bb212007-05-13 13:58:00 +0000691#endif
Richard Hendersond2565872013-01-04 16:39:32 -0800692 /* To be swapped in target_to_host_sigset. */
pbrook624f7972008-05-31 16:11:38 +0000693 k->sa_mask = act->sa_mask;
bellard773b93e2004-01-04 17:15:59 +0000694
695 /* we update the host linux signal state */
696 host_sig = target_to_host_signal(sig);
697 if (host_sig != SIGSEGV && host_sig != SIGBUS) {
698 sigfillset(&act1.sa_mask);
699 act1.sa_flags = SA_SIGINFO;
pbrook624f7972008-05-31 16:11:38 +0000700 if (k->sa_flags & TARGET_SA_RESTART)
bellard773b93e2004-01-04 17:15:59 +0000701 act1.sa_flags |= SA_RESTART;
702 /* NOTE: it is important to update the host kernel signal
703 ignore state to avoid getting unexpected interrupted
704 syscalls */
pbrook624f7972008-05-31 16:11:38 +0000705 if (k->_sa_handler == TARGET_SIG_IGN) {
bellard773b93e2004-01-04 17:15:59 +0000706 act1.sa_sigaction = (void *)SIG_IGN;
pbrook624f7972008-05-31 16:11:38 +0000707 } else if (k->_sa_handler == TARGET_SIG_DFL) {
aurel32ca587a82008-12-18 22:44:13 +0000708 if (fatal_signal (sig))
709 act1.sa_sigaction = host_signal_handler;
710 else
711 act1.sa_sigaction = (void *)SIG_DFL;
bellard773b93e2004-01-04 17:15:59 +0000712 } else {
713 act1.sa_sigaction = host_signal_handler;
714 }
ths0da46a62007-10-20 20:23:07 +0000715 ret = sigaction(host_sig, &act1, NULL);
bellard773b93e2004-01-04 17:15:59 +0000716 }
bellard66fb9762003-03-23 01:06:05 +0000717 }
ths0da46a62007-10-20 20:23:07 +0000718 return ret;
bellard66fb9762003-03-23 01:06:05 +0000719}
bellard31e31b82003-02-18 22:55:36 +0000720
bellard459a4012007-11-11 19:45:10 +0000721#if defined(TARGET_I386) && TARGET_ABI_BITS == 32
bellard66fb9762003-03-23 01:06:05 +0000722
723/* from the Linux kernel */
724
725struct target_fpreg {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100726 uint16_t significand[4];
727 uint16_t exponent;
bellard66fb9762003-03-23 01:06:05 +0000728};
729
730struct target_fpxreg {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100731 uint16_t significand[4];
732 uint16_t exponent;
733 uint16_t padding[3];
bellard66fb9762003-03-23 01:06:05 +0000734};
735
736struct target_xmmreg {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100737 abi_ulong element[4];
bellard66fb9762003-03-23 01:06:05 +0000738};
739
740struct target_fpstate {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100741 /* Regular FPU environment */
742 abi_ulong cw;
743 abi_ulong sw;
744 abi_ulong tag;
745 abi_ulong ipoff;
746 abi_ulong cssel;
747 abi_ulong dataoff;
748 abi_ulong datasel;
749 struct target_fpreg _st[8];
750 uint16_t status;
751 uint16_t magic; /* 0xffff = regular FPU data only */
bellard66fb9762003-03-23 01:06:05 +0000752
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100753 /* FXSR FPU environment */
754 abi_ulong _fxsr_env[6]; /* FXSR FPU env is ignored */
755 abi_ulong mxcsr;
756 abi_ulong reserved;
757 struct target_fpxreg _fxsr_st[8]; /* FXSR FPU reg data is ignored */
758 struct target_xmmreg _xmm[8];
759 abi_ulong padding[56];
bellard66fb9762003-03-23 01:06:05 +0000760};
761
762#define X86_FXSR_MAGIC 0x0000
763
764struct target_sigcontext {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100765 uint16_t gs, __gsh;
766 uint16_t fs, __fsh;
767 uint16_t es, __esh;
768 uint16_t ds, __dsh;
769 abi_ulong edi;
770 abi_ulong esi;
771 abi_ulong ebp;
772 abi_ulong esp;
773 abi_ulong ebx;
774 abi_ulong edx;
775 abi_ulong ecx;
776 abi_ulong eax;
777 abi_ulong trapno;
778 abi_ulong err;
779 abi_ulong eip;
780 uint16_t cs, __csh;
781 abi_ulong eflags;
782 abi_ulong esp_at_signal;
783 uint16_t ss, __ssh;
784 abi_ulong fpstate; /* pointer */
785 abi_ulong oldmask;
786 abi_ulong cr2;
bellard66fb9762003-03-23 01:06:05 +0000787};
788
bellard66fb9762003-03-23 01:06:05 +0000789struct target_ucontext {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100790 abi_ulong tuc_flags;
791 abi_ulong tuc_link;
792 target_stack_t tuc_stack;
793 struct target_sigcontext tuc_mcontext;
794 target_sigset_t tuc_sigmask; /* mask last for extensibility */
bellard66fb9762003-03-23 01:06:05 +0000795};
796
797struct sigframe
798{
blueswir1992f48a2007-10-14 16:27:31 +0000799 abi_ulong pretcode;
bellard66fb9762003-03-23 01:06:05 +0000800 int sig;
801 struct target_sigcontext sc;
802 struct target_fpstate fpstate;
blueswir1992f48a2007-10-14 16:27:31 +0000803 abi_ulong extramask[TARGET_NSIG_WORDS-1];
bellard66fb9762003-03-23 01:06:05 +0000804 char retcode[8];
805};
806
807struct rt_sigframe
808{
blueswir1992f48a2007-10-14 16:27:31 +0000809 abi_ulong pretcode;
bellard66fb9762003-03-23 01:06:05 +0000810 int sig;
blueswir1992f48a2007-10-14 16:27:31 +0000811 abi_ulong pinfo;
812 abi_ulong puc;
bellard66fb9762003-03-23 01:06:05 +0000813 struct target_siginfo info;
814 struct target_ucontext uc;
815 struct target_fpstate fpstate;
816 char retcode[8];
817};
818
819/*
820 * Set up a signal frame.
821 */
822
bellard66fb9762003-03-23 01:06:05 +0000823/* XXX: save x87 state */
Riku Voipio41ecc722014-04-23 11:01:00 +0300824static void setup_sigcontext(struct target_sigcontext *sc,
825 struct target_fpstate *fpstate, CPUX86State *env, abi_ulong mask,
826 abi_ulong fpstate_addr)
bellard66fb9762003-03-23 01:06:05 +0000827{
Andreas Färber27103422013-08-26 08:31:06 +0200828 CPUState *cs = CPU(x86_env_get_cpu(env));
Andreas Färber27103422013-08-26 08:31:06 +0200829 uint16_t magic;
bellard66fb9762003-03-23 01:06:05 +0000830
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100831 /* already locked in setup_frame() */
Riku Voipio1d8b5122014-04-23 10:26:05 +0300832 __put_user(env->segs[R_GS].selector, (unsigned int *)&sc->gs);
833 __put_user(env->segs[R_FS].selector, (unsigned int *)&sc->fs);
834 __put_user(env->segs[R_ES].selector, (unsigned int *)&sc->es);
835 __put_user(env->segs[R_DS].selector, (unsigned int *)&sc->ds);
836 __put_user(env->regs[R_EDI], &sc->edi);
837 __put_user(env->regs[R_ESI], &sc->esi);
838 __put_user(env->regs[R_EBP], &sc->ebp);
839 __put_user(env->regs[R_ESP], &sc->esp);
840 __put_user(env->regs[R_EBX], &sc->ebx);
841 __put_user(env->regs[R_EDX], &sc->edx);
842 __put_user(env->regs[R_ECX], &sc->ecx);
843 __put_user(env->regs[R_EAX], &sc->eax);
844 __put_user(cs->exception_index, &sc->trapno);
845 __put_user(env->error_code, &sc->err);
846 __put_user(env->eip, &sc->eip);
847 __put_user(env->segs[R_CS].selector, (unsigned int *)&sc->cs);
848 __put_user(env->eflags, &sc->eflags);
849 __put_user(env->regs[R_ESP], &sc->esp_at_signal);
850 __put_user(env->segs[R_SS].selector, (unsigned int *)&sc->ss);
bellarded2dcdf2003-05-29 20:06:27 +0000851
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100852 cpu_x86_fsave(env, fpstate_addr, 1);
853 fpstate->status = fpstate->sw;
854 magic = 0xffff;
Riku Voipio1d8b5122014-04-23 10:26:05 +0300855 __put_user(magic, &fpstate->magic);
856 __put_user(fpstate_addr, &sc->fpstate);
bellarded2dcdf2003-05-29 20:06:27 +0000857
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100858 /* non-iBCS2 extensions.. */
Riku Voipio1d8b5122014-04-23 10:26:05 +0300859 __put_user(mask, &sc->oldmask);
860 __put_user(env->cr[2], &sc->cr2);
bellard66fb9762003-03-23 01:06:05 +0000861}
862
863/*
864 * Determine which stack to use..
865 */
866
bellard579a97f2007-11-11 14:26:47 +0000867static inline abi_ulong
pbrook624f7972008-05-31 16:11:38 +0000868get_sigframe(struct target_sigaction *ka, CPUX86State *env, size_t frame_size)
bellard66fb9762003-03-23 01:06:05 +0000869{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100870 unsigned long esp;
bellard66fb9762003-03-23 01:06:05 +0000871
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100872 /* Default to using normal stack */
873 esp = env->regs[R_ESP];
874 /* This is the X/Open sanctioned signal stack switching. */
875 if (ka->sa_flags & TARGET_SA_ONSTACK) {
876 if (sas_ss_flags(esp) == 0) {
877 esp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
thsa04e1342007-09-27 13:57:58 +0000878 }
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100879 } else {
bellard66fb9762003-03-23 01:06:05 +0000880
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100881 /* This is the legacy signal stack switching. */
bellarda52c7572003-06-21 13:14:12 +0000882 if ((env->segs[R_SS].selector & 0xffff) != __USER_DS &&
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100883 !(ka->sa_flags & TARGET_SA_RESTORER) &&
884 ka->sa_restorer) {
pbrook624f7972008-05-31 16:11:38 +0000885 esp = (unsigned long) ka->sa_restorer;
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100886 }
887 }
888 return (esp - frame_size) & -8ul;
bellard66fb9762003-03-23 01:06:05 +0000889}
890
bellard579a97f2007-11-11 14:26:47 +0000891/* compare linux/arch/i386/kernel/signal.c:setup_frame() */
pbrook624f7972008-05-31 16:11:38 +0000892static void setup_frame(int sig, struct target_sigaction *ka,
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100893 target_sigset_t *set, CPUX86State *env)
bellard66fb9762003-03-23 01:06:05 +0000894{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100895 abi_ulong frame_addr;
896 struct sigframe *frame;
897 int i;
bellard66fb9762003-03-23 01:06:05 +0000898
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100899 frame_addr = get_sigframe(ka, env, sizeof(*frame));
900 trace_user_setup_frame(env, frame_addr);
bellard66fb9762003-03-23 01:06:05 +0000901
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100902 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
903 goto give_sigsegv;
bellard579a97f2007-11-11 14:26:47 +0000904
Peter Maydellb6e2c932015-01-08 12:19:43 +0000905 __put_user(sig, &frame->sig);
bellard66fb9762003-03-23 01:06:05 +0000906
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100907 setup_sigcontext(&frame->sc, &frame->fpstate, env, set->sig[0],
908 frame_addr + offsetof(struct sigframe, fpstate));
bellard66fb9762003-03-23 01:06:05 +0000909
Riku Voipio7df2fa32014-04-23 10:34:53 +0300910 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
911 __put_user(set->sig[i], &frame->extramask[i - 1]);
912 }
bellard66fb9762003-03-23 01:06:05 +0000913
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100914 /* Set up to return from userspace. If provided, use a stub
915 already in userspace. */
916 if (ka->sa_flags & TARGET_SA_RESTORER) {
Riku Voipio1d8b5122014-04-23 10:26:05 +0300917 __put_user(ka->sa_restorer, &frame->pretcode);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100918 } else {
919 uint16_t val16;
920 abi_ulong retcode_addr;
921 retcode_addr = frame_addr + offsetof(struct sigframe, retcode);
Riku Voipio1d8b5122014-04-23 10:26:05 +0300922 __put_user(retcode_addr, &frame->pretcode);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100923 /* This is popl %eax ; movl $,%eax ; int $0x80 */
924 val16 = 0xb858;
Riku Voipio1d8b5122014-04-23 10:26:05 +0300925 __put_user(val16, (uint16_t *)(frame->retcode+0));
926 __put_user(TARGET_NR_sigreturn, (int *)(frame->retcode+2));
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100927 val16 = 0x80cd;
Riku Voipio1d8b5122014-04-23 10:26:05 +0300928 __put_user(val16, (uint16_t *)(frame->retcode+6));
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100929 }
bellard66fb9762003-03-23 01:06:05 +0000930
bellard66fb9762003-03-23 01:06:05 +0000931
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100932 /* Set up registers for signal handler */
933 env->regs[R_ESP] = frame_addr;
934 env->eip = ka->_sa_handler;
bellard66fb9762003-03-23 01:06:05 +0000935
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100936 cpu_x86_load_seg(env, R_DS, __USER_DS);
937 cpu_x86_load_seg(env, R_ES, __USER_DS);
938 cpu_x86_load_seg(env, R_SS, __USER_DS);
939 cpu_x86_load_seg(env, R_CS, __USER_CS);
940 env->eflags &= ~TF_MASK;
bellard66fb9762003-03-23 01:06:05 +0000941
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100942 unlock_user_struct(frame, frame_addr, 1);
bellard579a97f2007-11-11 14:26:47 +0000943
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100944 return;
bellard66fb9762003-03-23 01:06:05 +0000945
946give_sigsegv:
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100947 if (sig == TARGET_SIGSEGV) {
948 ka->_sa_handler = TARGET_SIG_DFL;
949 }
950 force_sig(TARGET_SIGSEGV /* , current */);
bellard66fb9762003-03-23 01:06:05 +0000951}
952
bellard579a97f2007-11-11 14:26:47 +0000953/* compare linux/arch/i386/kernel/signal.c:setup_rt_frame() */
pbrook624f7972008-05-31 16:11:38 +0000954static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -0500955 target_siginfo_t *info,
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100956 target_sigset_t *set, CPUX86State *env)
bellard66fb9762003-03-23 01:06:05 +0000957{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100958 abi_ulong frame_addr, addr;
959 struct rt_sigframe *frame;
960 int i;
bellard66fb9762003-03-23 01:06:05 +0000961
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100962 frame_addr = get_sigframe(ka, env, sizeof(*frame));
963 trace_user_setup_rt_frame(env, frame_addr);
bellard66fb9762003-03-23 01:06:05 +0000964
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100965 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
966 goto give_sigsegv;
bellard66fb9762003-03-23 01:06:05 +0000967
Peter Maydellb6e2c932015-01-08 12:19:43 +0000968 __put_user(sig, &frame->sig);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100969 addr = frame_addr + offsetof(struct rt_sigframe, info);
Riku Voipio1d8b5122014-04-23 10:26:05 +0300970 __put_user(addr, &frame->pinfo);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100971 addr = frame_addr + offsetof(struct rt_sigframe, uc);
Riku Voipio1d8b5122014-04-23 10:26:05 +0300972 __put_user(addr, &frame->puc);
Peter Maydellf6c7a052015-01-08 12:19:48 +0000973 tswap_siginfo(&frame->info, info);
bellard66fb9762003-03-23 01:06:05 +0000974
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100975 /* Create the ucontext. */
Riku Voipio1d8b5122014-04-23 10:26:05 +0300976 __put_user(0, &frame->uc.tuc_flags);
977 __put_user(0, &frame->uc.tuc_link);
978 __put_user(target_sigaltstack_used.ss_sp, &frame->uc.tuc_stack.ss_sp);
979 __put_user(sas_ss_flags(get_sp_from_cpustate(env)),
980 &frame->uc.tuc_stack.ss_flags);
981 __put_user(target_sigaltstack_used.ss_size,
982 &frame->uc.tuc_stack.ss_size);
Riku Voipio41ecc722014-04-23 11:01:00 +0300983 setup_sigcontext(&frame->uc.tuc_mcontext, &frame->fpstate, env,
984 set->sig[0], frame_addr + offsetof(struct rt_sigframe, fpstate));
985
Riku Voipio0188fad2014-04-23 13:34:15 +0300986 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
987 __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
988 }
bellard66fb9762003-03-23 01:06:05 +0000989
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100990 /* Set up to return from userspace. If provided, use a stub
991 already in userspace. */
992 if (ka->sa_flags & TARGET_SA_RESTORER) {
Riku Voipio1d8b5122014-04-23 10:26:05 +0300993 __put_user(ka->sa_restorer, &frame->pretcode);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100994 } else {
995 uint16_t val16;
996 addr = frame_addr + offsetof(struct rt_sigframe, retcode);
Riku Voipio1d8b5122014-04-23 10:26:05 +0300997 __put_user(addr, &frame->pretcode);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +0100998 /* This is movl $,%eax ; int $0x80 */
Riku Voipio1d8b5122014-04-23 10:26:05 +0300999 __put_user(0xb8, (char *)(frame->retcode+0));
1000 __put_user(TARGET_NR_rt_sigreturn, (int *)(frame->retcode+1));
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001001 val16 = 0x80cd;
Riku Voipio1d8b5122014-04-23 10:26:05 +03001002 __put_user(val16, (uint16_t *)(frame->retcode+5));
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001003 }
bellard66fb9762003-03-23 01:06:05 +00001004
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001005 /* Set up registers for signal handler */
1006 env->regs[R_ESP] = frame_addr;
1007 env->eip = ka->_sa_handler;
bellard66fb9762003-03-23 01:06:05 +00001008
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001009 cpu_x86_load_seg(env, R_DS, __USER_DS);
1010 cpu_x86_load_seg(env, R_ES, __USER_DS);
1011 cpu_x86_load_seg(env, R_SS, __USER_DS);
1012 cpu_x86_load_seg(env, R_CS, __USER_CS);
1013 env->eflags &= ~TF_MASK;
bellard66fb9762003-03-23 01:06:05 +00001014
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001015 unlock_user_struct(frame, frame_addr, 1);
bellard579a97f2007-11-11 14:26:47 +00001016
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001017 return;
bellard66fb9762003-03-23 01:06:05 +00001018
1019give_sigsegv:
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001020 if (sig == TARGET_SIGSEGV) {
1021 ka->_sa_handler = TARGET_SIG_DFL;
1022 }
1023 force_sig(TARGET_SIGSEGV /* , current */);
bellard66fb9762003-03-23 01:06:05 +00001024}
1025
1026static int
1027restore_sigcontext(CPUX86State *env, struct target_sigcontext *sc, int *peax)
1028{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001029 unsigned int err = 0;
1030 abi_ulong fpstate_addr;
1031 unsigned int tmpflags;
bellard66fb9762003-03-23 01:06:05 +00001032
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001033 cpu_x86_load_seg(env, R_GS, tswap16(sc->gs));
1034 cpu_x86_load_seg(env, R_FS, tswap16(sc->fs));
1035 cpu_x86_load_seg(env, R_ES, tswap16(sc->es));
1036 cpu_x86_load_seg(env, R_DS, tswap16(sc->ds));
bellard66fb9762003-03-23 01:06:05 +00001037
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001038 env->regs[R_EDI] = tswapl(sc->edi);
1039 env->regs[R_ESI] = tswapl(sc->esi);
1040 env->regs[R_EBP] = tswapl(sc->ebp);
1041 env->regs[R_ESP] = tswapl(sc->esp);
1042 env->regs[R_EBX] = tswapl(sc->ebx);
1043 env->regs[R_EDX] = tswapl(sc->edx);
1044 env->regs[R_ECX] = tswapl(sc->ecx);
1045 env->eip = tswapl(sc->eip);
bellard66fb9762003-03-23 01:06:05 +00001046
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001047 cpu_x86_load_seg(env, R_CS, lduw_p(&sc->cs) | 3);
1048 cpu_x86_load_seg(env, R_SS, lduw_p(&sc->ss) | 3);
ths5fafdf22007-09-16 21:08:06 +00001049
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001050 tmpflags = tswapl(sc->eflags);
1051 env->eflags = (env->eflags & ~0x40DD5) | (tmpflags & 0x40DD5);
1052 // regs->orig_eax = -1; /* disable syscall checks */
bellard28be6232007-11-11 22:23:38 +00001053
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001054 fpstate_addr = tswapl(sc->fpstate);
1055 if (fpstate_addr != 0) {
1056 if (!access_ok(VERIFY_READ, fpstate_addr,
1057 sizeof(struct target_fpstate)))
1058 goto badframe;
1059 cpu_x86_frstor(env, fpstate_addr, 1);
1060 }
bellard66fb9762003-03-23 01:06:05 +00001061
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001062 *peax = tswapl(sc->eax);
1063 return err;
bellard66fb9762003-03-23 01:06:05 +00001064badframe:
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001065 return 1;
bellard66fb9762003-03-23 01:06:05 +00001066}
1067
1068long do_sigreturn(CPUX86State *env)
1069{
bellard579a97f2007-11-11 14:26:47 +00001070 struct sigframe *frame;
1071 abi_ulong frame_addr = env->regs[R_ESP] - 8;
Anthony Liguoric227f092009-10-01 16:12:16 -05001072 target_sigset_t target_set;
bellard66fb9762003-03-23 01:06:05 +00001073 sigset_t set;
1074 int eax, i;
1075
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01001076 trace_user_do_sigreturn(env, frame_addr);
bellard579a97f2007-11-11 14:26:47 +00001077 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
1078 goto badframe;
bellard66fb9762003-03-23 01:06:05 +00001079 /* set blocked signals */
Riku Voipiof5f601a2014-04-23 13:00:17 +03001080 __get_user(target_set.sig[0], &frame->sc.oldmask);
bellard92319442004-06-19 16:58:13 +00001081 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
Riku Voipiof5f601a2014-04-23 13:00:17 +03001082 __get_user(target_set.sig[i], &frame->extramask[i - 1]);
bellard92319442004-06-19 16:58:13 +00001083 }
bellard66fb9762003-03-23 01:06:05 +00001084
bellard92319442004-06-19 16:58:13 +00001085 target_to_host_sigset_internal(&set, &target_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00001086 do_sigprocmask(SIG_SETMASK, &set, NULL);
ths3b46e622007-09-17 08:09:54 +00001087
bellard66fb9762003-03-23 01:06:05 +00001088 /* restore registers */
1089 if (restore_sigcontext(env, &frame->sc, &eax))
1090 goto badframe;
bellard579a97f2007-11-11 14:26:47 +00001091 unlock_user_struct(frame, frame_addr, 0);
bellard66fb9762003-03-23 01:06:05 +00001092 return eax;
1093
1094badframe:
bellard579a97f2007-11-11 14:26:47 +00001095 unlock_user_struct(frame, frame_addr, 0);
bellard66fb9762003-03-23 01:06:05 +00001096 force_sig(TARGET_SIGSEGV);
1097 return 0;
1098}
1099
1100long do_rt_sigreturn(CPUX86State *env)
1101{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001102 abi_ulong frame_addr;
1103 struct rt_sigframe *frame;
1104 sigset_t set;
1105 int eax;
bellard66fb9762003-03-23 01:06:05 +00001106
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001107 frame_addr = env->regs[R_ESP] - 4;
1108 trace_user_do_rt_sigreturn(env, frame_addr);
1109 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
1110 goto badframe;
1111 target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
1112 do_sigprocmask(SIG_SETMASK, &set, NULL);
ths5fafdf22007-09-16 21:08:06 +00001113
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001114 if (restore_sigcontext(env, &frame->uc.tuc_mcontext, &eax)) {
1115 goto badframe;
1116 }
bellard66fb9762003-03-23 01:06:05 +00001117
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001118 if (do_sigaltstack(frame_addr + offsetof(struct rt_sigframe, uc.tuc_stack), 0,
1119 get_sp_from_cpustate(env)) == -EFAULT) {
1120 goto badframe;
1121 }
thsa04e1342007-09-27 13:57:58 +00001122
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001123 unlock_user_struct(frame, frame_addr, 0);
1124 return eax;
bellard66fb9762003-03-23 01:06:05 +00001125
1126badframe:
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001127 unlock_user_struct(frame, frame_addr, 0);
1128 force_sig(TARGET_SIGSEGV);
1129 return 0;
bellard66fb9762003-03-23 01:06:05 +00001130}
1131
Andreas Schwab1744aea2013-09-03 20:12:16 +01001132#elif defined(TARGET_AARCH64)
1133
1134struct target_sigcontext {
1135 uint64_t fault_address;
1136 /* AArch64 registers */
1137 uint64_t regs[31];
1138 uint64_t sp;
1139 uint64_t pc;
1140 uint64_t pstate;
1141 /* 4K reserved for FP/SIMD state and future expansion */
1142 char __reserved[4096] __attribute__((__aligned__(16)));
1143};
1144
1145struct target_ucontext {
1146 abi_ulong tuc_flags;
1147 abi_ulong tuc_link;
1148 target_stack_t tuc_stack;
1149 target_sigset_t tuc_sigmask;
1150 /* glibc uses a 1024-bit sigset_t */
1151 char __unused[1024 / 8 - sizeof(target_sigset_t)];
1152 /* last for future expansion */
1153 struct target_sigcontext tuc_mcontext;
1154};
1155
1156/*
1157 * Header to be used at the beginning of structures extending the user
1158 * context. Such structures must be placed after the rt_sigframe on the stack
1159 * and be 16-byte aligned. The last structure must be a dummy one with the
1160 * magic and size set to 0.
1161 */
1162struct target_aarch64_ctx {
1163 uint32_t magic;
1164 uint32_t size;
1165};
1166
1167#define TARGET_FPSIMD_MAGIC 0x46508001
1168
1169struct target_fpsimd_context {
1170 struct target_aarch64_ctx head;
1171 uint32_t fpsr;
1172 uint32_t fpcr;
1173 uint64_t vregs[32 * 2]; /* really uint128_t vregs[32] */
1174};
1175
1176/*
1177 * Auxiliary context saved in the sigcontext.__reserved array. Not exported to
1178 * user space as it will change with the addition of new context. User space
1179 * should check the magic/size information.
1180 */
1181struct target_aux_context {
1182 struct target_fpsimd_context fpsimd;
1183 /* additional context to be added before "end" */
1184 struct target_aarch64_ctx end;
1185};
1186
1187struct target_rt_sigframe {
1188 struct target_siginfo info;
1189 struct target_ucontext uc;
1190 uint64_t fp;
1191 uint64_t lr;
1192 uint32_t tramp[2];
1193};
1194
1195static int target_setup_sigframe(struct target_rt_sigframe *sf,
1196 CPUARMState *env, target_sigset_t *set)
1197{
1198 int i;
1199 struct target_aux_context *aux =
1200 (struct target_aux_context *)sf->uc.tuc_mcontext.__reserved;
1201
1202 /* set up the stack frame for unwinding */
1203 __put_user(env->xregs[29], &sf->fp);
1204 __put_user(env->xregs[30], &sf->lr);
1205
1206 for (i = 0; i < 31; i++) {
1207 __put_user(env->xregs[i], &sf->uc.tuc_mcontext.regs[i]);
1208 }
1209 __put_user(env->xregs[31], &sf->uc.tuc_mcontext.sp);
1210 __put_user(env->pc, &sf->uc.tuc_mcontext.pc);
Peter Maydelld3563122013-12-17 19:42:30 +00001211 __put_user(pstate_read(env), &sf->uc.tuc_mcontext.pstate);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001212
Peter Maydell7af03922014-05-01 18:36:17 +01001213 __put_user(env->exception.vaddress, &sf->uc.tuc_mcontext.fault_address);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001214
1215 for (i = 0; i < TARGET_NSIG_WORDS; i++) {
1216 __put_user(set->sig[i], &sf->uc.tuc_sigmask.sig[i]);
1217 }
1218
1219 for (i = 0; i < 32; i++) {
1220#ifdef TARGET_WORDS_BIGENDIAN
1221 __put_user(env->vfp.regs[i * 2], &aux->fpsimd.vregs[i * 2 + 1]);
1222 __put_user(env->vfp.regs[i * 2 + 1], &aux->fpsimd.vregs[i * 2]);
1223#else
1224 __put_user(env->vfp.regs[i * 2], &aux->fpsimd.vregs[i * 2]);
1225 __put_user(env->vfp.regs[i * 2 + 1], &aux->fpsimd.vregs[i * 2 + 1]);
1226#endif
1227 }
Will Newtone0ee1382014-01-04 22:15:48 +00001228 __put_user(vfp_get_fpsr(env), &aux->fpsimd.fpsr);
1229 __put_user(vfp_get_fpcr(env), &aux->fpsimd.fpcr);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001230 __put_user(TARGET_FPSIMD_MAGIC, &aux->fpsimd.head.magic);
1231 __put_user(sizeof(struct target_fpsimd_context),
1232 &aux->fpsimd.head.size);
1233
1234 /* set the "end" magic */
1235 __put_user(0, &aux->end.magic);
1236 __put_user(0, &aux->end.size);
1237
1238 return 0;
1239}
1240
1241static int target_restore_sigframe(CPUARMState *env,
1242 struct target_rt_sigframe *sf)
1243{
1244 sigset_t set;
1245 int i;
1246 struct target_aux_context *aux =
1247 (struct target_aux_context *)sf->uc.tuc_mcontext.__reserved;
Will Newtone0ee1382014-01-04 22:15:48 +00001248 uint32_t magic, size, fpsr, fpcr;
Peter Maydelld3563122013-12-17 19:42:30 +00001249 uint64_t pstate;
Andreas Schwab1744aea2013-09-03 20:12:16 +01001250
1251 target_to_host_sigset(&set, &sf->uc.tuc_sigmask);
Alex Barcelo1c275922014-03-14 14:36:55 +00001252 do_sigprocmask(SIG_SETMASK, &set, NULL);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001253
1254 for (i = 0; i < 31; i++) {
1255 __get_user(env->xregs[i], &sf->uc.tuc_mcontext.regs[i]);
1256 }
1257
1258 __get_user(env->xregs[31], &sf->uc.tuc_mcontext.sp);
1259 __get_user(env->pc, &sf->uc.tuc_mcontext.pc);
Peter Maydelld3563122013-12-17 19:42:30 +00001260 __get_user(pstate, &sf->uc.tuc_mcontext.pstate);
1261 pstate_write(env, pstate);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001262
1263 __get_user(magic, &aux->fpsimd.head.magic);
1264 __get_user(size, &aux->fpsimd.head.size);
1265
1266 if (magic != TARGET_FPSIMD_MAGIC
1267 || size != sizeof(struct target_fpsimd_context)) {
1268 return 1;
1269 }
1270
Peter Maydell4cf23482014-03-02 19:36:38 +00001271 for (i = 0; i < 32; i++) {
1272#ifdef TARGET_WORDS_BIGENDIAN
1273 __get_user(env->vfp.regs[i * 2], &aux->fpsimd.vregs[i * 2 + 1]);
1274 __get_user(env->vfp.regs[i * 2 + 1], &aux->fpsimd.vregs[i * 2]);
1275#else
1276 __get_user(env->vfp.regs[i * 2], &aux->fpsimd.vregs[i * 2]);
1277 __get_user(env->vfp.regs[i * 2 + 1], &aux->fpsimd.vregs[i * 2 + 1]);
1278#endif
Andreas Schwab1744aea2013-09-03 20:12:16 +01001279 }
Will Newtone0ee1382014-01-04 22:15:48 +00001280 __get_user(fpsr, &aux->fpsimd.fpsr);
1281 vfp_set_fpsr(env, fpsr);
1282 __get_user(fpcr, &aux->fpsimd.fpcr);
1283 vfp_set_fpcr(env, fpcr);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001284
1285 return 0;
1286}
1287
1288static abi_ulong get_sigframe(struct target_sigaction *ka, CPUARMState *env)
1289{
1290 abi_ulong sp;
1291
1292 sp = env->xregs[31];
1293
1294 /*
1295 * This is the X/Open sanctioned signal stack switching.
1296 */
Riku Voipiob545f632014-07-15 17:01:55 +03001297 if ((ka->sa_flags & TARGET_SA_ONSTACK) && !sas_ss_flags(sp)) {
Andreas Schwab1744aea2013-09-03 20:12:16 +01001298 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
1299 }
1300
1301 sp = (sp - sizeof(struct target_rt_sigframe)) & ~15;
1302
1303 return sp;
1304}
1305
1306static void target_setup_frame(int usig, struct target_sigaction *ka,
1307 target_siginfo_t *info, target_sigset_t *set,
1308 CPUARMState *env)
1309{
1310 struct target_rt_sigframe *frame;
Michael Matz8a3ae912014-03-02 19:36:39 +00001311 abi_ulong frame_addr, return_addr;
Andreas Schwab1744aea2013-09-03 20:12:16 +01001312
1313 frame_addr = get_sigframe(ka, env);
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01001314 trace_user_setup_frame(env, frame_addr);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001315 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
1316 goto give_sigsegv;
1317 }
1318
1319 __put_user(0, &frame->uc.tuc_flags);
1320 __put_user(0, &frame->uc.tuc_link);
1321
1322 __put_user(target_sigaltstack_used.ss_sp,
1323 &frame->uc.tuc_stack.ss_sp);
1324 __put_user(sas_ss_flags(env->xregs[31]),
1325 &frame->uc.tuc_stack.ss_flags);
1326 __put_user(target_sigaltstack_used.ss_size,
1327 &frame->uc.tuc_stack.ss_size);
1328 target_setup_sigframe(frame, env, set);
Michael Matz8a3ae912014-03-02 19:36:39 +00001329 if (ka->sa_flags & TARGET_SA_RESTORER) {
1330 return_addr = ka->sa_restorer;
1331 } else {
1332 /* mov x8,#__NR_rt_sigreturn; svc #0 */
1333 __put_user(0xd2801168, &frame->tramp[0]);
1334 __put_user(0xd4000001, &frame->tramp[1]);
1335 return_addr = frame_addr + offsetof(struct target_rt_sigframe, tramp);
1336 }
Andreas Schwab1744aea2013-09-03 20:12:16 +01001337 env->xregs[0] = usig;
1338 env->xregs[31] = frame_addr;
1339 env->xregs[29] = env->xregs[31] + offsetof(struct target_rt_sigframe, fp);
1340 env->pc = ka->_sa_handler;
Michael Matz8a3ae912014-03-02 19:36:39 +00001341 env->xregs[30] = return_addr;
Andreas Schwab1744aea2013-09-03 20:12:16 +01001342 if (info) {
Peter Maydellf6c7a052015-01-08 12:19:48 +00001343 tswap_siginfo(&frame->info, info);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001344 env->xregs[1] = frame_addr + offsetof(struct target_rt_sigframe, info);
1345 env->xregs[2] = frame_addr + offsetof(struct target_rt_sigframe, uc);
1346 }
1347
1348 unlock_user_struct(frame, frame_addr, 1);
1349 return;
1350
1351 give_sigsegv:
1352 unlock_user_struct(frame, frame_addr, 1);
1353 force_sig(TARGET_SIGSEGV);
1354}
1355
1356static void setup_rt_frame(int sig, struct target_sigaction *ka,
1357 target_siginfo_t *info, target_sigset_t *set,
1358 CPUARMState *env)
1359{
1360 target_setup_frame(sig, ka, info, set, env);
1361}
1362
1363static void setup_frame(int sig, struct target_sigaction *ka,
1364 target_sigset_t *set, CPUARMState *env)
1365{
1366 target_setup_frame(sig, ka, 0, set, env);
1367}
1368
1369long do_rt_sigreturn(CPUARMState *env)
1370{
Peter Maydell7f72cd22014-03-12 13:06:00 +00001371 struct target_rt_sigframe *frame = NULL;
Andreas Schwab1744aea2013-09-03 20:12:16 +01001372 abi_ulong frame_addr = env->xregs[31];
1373
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01001374 trace_user_do_rt_sigreturn(env, frame_addr);
Andreas Schwab1744aea2013-09-03 20:12:16 +01001375 if (frame_addr & 15) {
1376 goto badframe;
1377 }
1378
1379 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
1380 goto badframe;
1381 }
1382
1383 if (target_restore_sigframe(env, frame)) {
1384 goto badframe;
1385 }
1386
1387 if (do_sigaltstack(frame_addr +
1388 offsetof(struct target_rt_sigframe, uc.tuc_stack),
1389 0, get_sp_from_cpustate(env)) == -EFAULT) {
1390 goto badframe;
1391 }
1392
1393 unlock_user_struct(frame, frame_addr, 0);
1394 return env->xregs[0];
1395
1396 badframe:
1397 unlock_user_struct(frame, frame_addr, 0);
1398 force_sig(TARGET_SIGSEGV);
1399 return 0;
1400}
1401
1402long do_sigreturn(CPUARMState *env)
1403{
1404 return do_rt_sigreturn(env);
1405}
1406
bellard43fff232003-07-09 19:31:39 +00001407#elif defined(TARGET_ARM)
1408
1409struct target_sigcontext {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001410 abi_ulong trap_no;
1411 abi_ulong error_code;
1412 abi_ulong oldmask;
1413 abi_ulong arm_r0;
1414 abi_ulong arm_r1;
1415 abi_ulong arm_r2;
1416 abi_ulong arm_r3;
1417 abi_ulong arm_r4;
1418 abi_ulong arm_r5;
1419 abi_ulong arm_r6;
1420 abi_ulong arm_r7;
1421 abi_ulong arm_r8;
1422 abi_ulong arm_r9;
1423 abi_ulong arm_r10;
1424 abi_ulong arm_fp;
1425 abi_ulong arm_ip;
1426 abi_ulong arm_sp;
1427 abi_ulong arm_lr;
1428 abi_ulong arm_pc;
1429 abi_ulong arm_cpsr;
1430 abi_ulong fault_address;
bellard43fff232003-07-09 19:31:39 +00001431};
1432
pbrooka745ec62008-05-06 15:36:17 +00001433struct target_ucontext_v1 {
blueswir1992f48a2007-10-14 16:27:31 +00001434 abi_ulong tuc_flags;
1435 abi_ulong tuc_link;
Anthony Liguoric227f092009-10-01 16:12:16 -05001436 target_stack_t tuc_stack;
bellardb8076a72005-04-07 22:20:31 +00001437 struct target_sigcontext tuc_mcontext;
Anthony Liguoric227f092009-10-01 16:12:16 -05001438 target_sigset_t tuc_sigmask; /* mask last for extensibility */
bellard43fff232003-07-09 19:31:39 +00001439};
1440
pbrooka745ec62008-05-06 15:36:17 +00001441struct target_ucontext_v2 {
1442 abi_ulong tuc_flags;
1443 abi_ulong tuc_link;
Anthony Liguoric227f092009-10-01 16:12:16 -05001444 target_stack_t tuc_stack;
pbrooka745ec62008-05-06 15:36:17 +00001445 struct target_sigcontext tuc_mcontext;
Anthony Liguoric227f092009-10-01 16:12:16 -05001446 target_sigset_t tuc_sigmask; /* mask last for extensibility */
Peter Maydell5f0b7c82010-11-24 15:20:03 +00001447 char __unused[128 - sizeof(target_sigset_t)];
pbrooka745ec62008-05-06 15:36:17 +00001448 abi_ulong tuc_regspace[128] __attribute__((__aligned__(8)));
1449};
1450
Peter Maydell0d871bd2010-11-24 15:20:05 +00001451struct target_user_vfp {
1452 uint64_t fpregs[32];
1453 abi_ulong fpscr;
1454};
1455
1456struct target_user_vfp_exc {
1457 abi_ulong fpexc;
1458 abi_ulong fpinst;
1459 abi_ulong fpinst2;
1460};
1461
1462struct target_vfp_sigframe {
1463 abi_ulong magic;
1464 abi_ulong size;
1465 struct target_user_vfp ufp;
1466 struct target_user_vfp_exc ufp_exc;
1467} __attribute__((__aligned__(8)));
1468
Peter Maydell08e11252010-11-24 15:20:07 +00001469struct target_iwmmxt_sigframe {
1470 abi_ulong magic;
1471 abi_ulong size;
1472 uint64_t regs[16];
1473 /* Note that not all the coprocessor control registers are stored here */
1474 uint32_t wcssf;
1475 uint32_t wcasf;
1476 uint32_t wcgr0;
1477 uint32_t wcgr1;
1478 uint32_t wcgr2;
1479 uint32_t wcgr3;
1480} __attribute__((__aligned__(8)));
1481
Peter Maydell0d871bd2010-11-24 15:20:05 +00001482#define TARGET_VFP_MAGIC 0x56465001
Peter Maydell08e11252010-11-24 15:20:07 +00001483#define TARGET_IWMMXT_MAGIC 0x12ef842a
Peter Maydell0d871bd2010-11-24 15:20:05 +00001484
pbrooka8c33202008-05-07 23:22:46 +00001485struct sigframe_v1
bellard43fff232003-07-09 19:31:39 +00001486{
1487 struct target_sigcontext sc;
blueswir1992f48a2007-10-14 16:27:31 +00001488 abi_ulong extramask[TARGET_NSIG_WORDS-1];
1489 abi_ulong retcode;
bellard43fff232003-07-09 19:31:39 +00001490};
1491
pbrooka8c33202008-05-07 23:22:46 +00001492struct sigframe_v2
1493{
1494 struct target_ucontext_v2 uc;
1495 abi_ulong retcode;
1496};
1497
pbrooka745ec62008-05-06 15:36:17 +00001498struct rt_sigframe_v1
bellard43fff232003-07-09 19:31:39 +00001499{
bellardf8b0aa22007-11-11 23:03:42 +00001500 abi_ulong pinfo;
1501 abi_ulong puc;
bellard43fff232003-07-09 19:31:39 +00001502 struct target_siginfo info;
pbrooka745ec62008-05-06 15:36:17 +00001503 struct target_ucontext_v1 uc;
1504 abi_ulong retcode;
1505};
1506
1507struct rt_sigframe_v2
1508{
1509 struct target_siginfo info;
1510 struct target_ucontext_v2 uc;
blueswir1992f48a2007-10-14 16:27:31 +00001511 abi_ulong retcode;
bellard43fff232003-07-09 19:31:39 +00001512};
1513
1514#define TARGET_CONFIG_CPU_32 1
1515
1516/*
1517 * For ARM syscalls, we encode the syscall number into the instruction.
1518 */
1519#define SWI_SYS_SIGRETURN (0xef000000|(TARGET_NR_sigreturn + ARM_SYSCALL_BASE))
1520#define SWI_SYS_RT_SIGRETURN (0xef000000|(TARGET_NR_rt_sigreturn + ARM_SYSCALL_BASE))
1521
1522/*
1523 * For Thumb syscalls, we pass the syscall number via r7. We therefore
1524 * need two 16-bit instructions.
1525 */
1526#define SWI_THUMB_SIGRETURN (0xdf00 << 16 | 0x2700 | (TARGET_NR_sigreturn))
1527#define SWI_THUMB_RT_SIGRETURN (0xdf00 << 16 | 0x2700 | (TARGET_NR_rt_sigreturn))
1528
blueswir1992f48a2007-10-14 16:27:31 +00001529static const abi_ulong retcodes[4] = {
bellard43fff232003-07-09 19:31:39 +00001530 SWI_SYS_SIGRETURN, SWI_THUMB_SIGRETURN,
1531 SWI_SYS_RT_SIGRETURN, SWI_THUMB_RT_SIGRETURN
1532};
1533
1534
Andreas Färber05390242012-02-25 03:37:53 +01001535static inline int valid_user_regs(CPUARMState *regs)
bellard43fff232003-07-09 19:31:39 +00001536{
1537 return 1;
1538}
1539
pbrooka8c33202008-05-07 23:22:46 +00001540static void
bellard43fff232003-07-09 19:31:39 +00001541setup_sigcontext(struct target_sigcontext *sc, /*struct _fpstate *fpstate,*/
Andreas Färber05390242012-02-25 03:37:53 +01001542 CPUARMState *env, abi_ulong mask)
bellard43fff232003-07-09 19:31:39 +00001543{
Paolo Bonzinia0e1e6d2016-03-04 11:30:18 +00001544 __put_user(env->regs[0], &sc->arm_r0);
1545 __put_user(env->regs[1], &sc->arm_r1);
1546 __put_user(env->regs[2], &sc->arm_r2);
1547 __put_user(env->regs[3], &sc->arm_r3);
1548 __put_user(env->regs[4], &sc->arm_r4);
1549 __put_user(env->regs[5], &sc->arm_r5);
1550 __put_user(env->regs[6], &sc->arm_r6);
1551 __put_user(env->regs[7], &sc->arm_r7);
1552 __put_user(env->regs[8], &sc->arm_r8);
1553 __put_user(env->regs[9], &sc->arm_r9);
1554 __put_user(env->regs[10], &sc->arm_r10);
1555 __put_user(env->regs[11], &sc->arm_fp);
1556 __put_user(env->regs[12], &sc->arm_ip);
1557 __put_user(env->regs[13], &sc->arm_sp);
1558 __put_user(env->regs[14], &sc->arm_lr);
1559 __put_user(env->regs[15], &sc->arm_pc);
bellard43fff232003-07-09 19:31:39 +00001560#ifdef TARGET_CONFIG_CPU_32
Paolo Bonzinia0e1e6d2016-03-04 11:30:18 +00001561 __put_user(cpsr_read(env), &sc->arm_cpsr);
bellard43fff232003-07-09 19:31:39 +00001562#endif
1563
Paolo Bonzinia0e1e6d2016-03-04 11:30:18 +00001564 __put_user(/* current->thread.trap_no */ 0, &sc->trap_no);
1565 __put_user(/* current->thread.error_code */ 0, &sc->error_code);
1566 __put_user(/* current->thread.address */ 0, &sc->fault_address);
1567 __put_user(mask, &sc->oldmask);
bellard43fff232003-07-09 19:31:39 +00001568}
1569
bellard579a97f2007-11-11 14:26:47 +00001570static inline abi_ulong
Andreas Färber05390242012-02-25 03:37:53 +01001571get_sigframe(struct target_sigaction *ka, CPUARMState *regs, int framesize)
bellard43fff232003-07-09 19:31:39 +00001572{
Paolo Bonzinia0e1e6d2016-03-04 11:30:18 +00001573 unsigned long sp = regs->regs[13];
bellard43fff232003-07-09 19:31:39 +00001574
Paolo Bonzinia0e1e6d2016-03-04 11:30:18 +00001575 /*
1576 * This is the X/Open sanctioned signal stack switching.
1577 */
1578 if ((ka->sa_flags & TARGET_SA_ONSTACK) && !sas_ss_flags(sp)) {
1579 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
1580 }
1581 /*
1582 * ATPCS B01 mandates 8-byte alignment
1583 */
1584 return (sp - framesize) & ~7;
bellard43fff232003-07-09 19:31:39 +00001585}
1586
Riku Voipio0188fad2014-04-23 13:34:15 +03001587static void
Andreas Färber05390242012-02-25 03:37:53 +01001588setup_return(CPUARMState *env, struct target_sigaction *ka,
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001589 abi_ulong *rc, abi_ulong frame_addr, int usig, abi_ulong rc_addr)
bellard43fff232003-07-09 19:31:39 +00001590{
Paolo Bonzinia0e1e6d2016-03-04 11:30:18 +00001591 abi_ulong handler = ka->_sa_handler;
1592 abi_ulong retcode;
1593 int thumb = handler & 1;
1594 uint32_t cpsr = cpsr_read(env);
Peter Maydell964413d2011-01-14 20:39:19 +01001595
Paolo Bonzinia0e1e6d2016-03-04 11:30:18 +00001596 cpsr &= ~CPSR_IT;
1597 if (thumb) {
1598 cpsr |= CPSR_T;
1599 } else {
1600 cpsr &= ~CPSR_T;
1601 }
bellard43fff232003-07-09 19:31:39 +00001602
Paolo Bonzinia0e1e6d2016-03-04 11:30:18 +00001603 if (ka->sa_flags & TARGET_SA_RESTORER) {
1604 retcode = ka->sa_restorer;
1605 } else {
1606 unsigned int idx = thumb;
bellard43fff232003-07-09 19:31:39 +00001607
Paolo Bonzinia0e1e6d2016-03-04 11:30:18 +00001608 if (ka->sa_flags & TARGET_SA_SIGINFO) {
1609 idx += 2;
1610 }
bellard43fff232003-07-09 19:31:39 +00001611
Riku Voipio0188fad2014-04-23 13:34:15 +03001612 __put_user(retcodes[idx], rc);
Stefan Weilca8a2772011-10-03 22:43:19 +02001613
Paolo Bonzinia0e1e6d2016-03-04 11:30:18 +00001614 retcode = rc_addr + thumb;
1615 }
bellard43fff232003-07-09 19:31:39 +00001616
Paolo Bonzinia0e1e6d2016-03-04 11:30:18 +00001617 env->regs[0] = usig;
1618 env->regs[13] = frame_addr;
1619 env->regs[14] = retcode;
1620 env->regs[15] = handler & (thumb ? ~1 : ~3);
1621 cpsr_write(env, cpsr, CPSR_IT | CPSR_T, CPSRWriteByInstr);
bellard43fff232003-07-09 19:31:39 +00001622}
1623
Andreas Färber05390242012-02-25 03:37:53 +01001624static abi_ulong *setup_sigframe_v2_vfp(abi_ulong *regspace, CPUARMState *env)
Peter Maydell0d871bd2010-11-24 15:20:05 +00001625{
1626 int i;
1627 struct target_vfp_sigframe *vfpframe;
1628 vfpframe = (struct target_vfp_sigframe *)regspace;
1629 __put_user(TARGET_VFP_MAGIC, &vfpframe->magic);
1630 __put_user(sizeof(*vfpframe), &vfpframe->size);
1631 for (i = 0; i < 32; i++) {
Peter Maydell005e1a02011-02-10 13:59:35 +00001632 __put_user(float64_val(env->vfp.regs[i]), &vfpframe->ufp.fpregs[i]);
Peter Maydell0d871bd2010-11-24 15:20:05 +00001633 }
1634 __put_user(vfp_get_fpscr(env), &vfpframe->ufp.fpscr);
1635 __put_user(env->vfp.xregs[ARM_VFP_FPEXC], &vfpframe->ufp_exc.fpexc);
1636 __put_user(env->vfp.xregs[ARM_VFP_FPINST], &vfpframe->ufp_exc.fpinst);
1637 __put_user(env->vfp.xregs[ARM_VFP_FPINST2], &vfpframe->ufp_exc.fpinst2);
1638 return (abi_ulong*)(vfpframe+1);
1639}
1640
Andreas Färber05390242012-02-25 03:37:53 +01001641static abi_ulong *setup_sigframe_v2_iwmmxt(abi_ulong *regspace,
1642 CPUARMState *env)
Peter Maydell08e11252010-11-24 15:20:07 +00001643{
1644 int i;
1645 struct target_iwmmxt_sigframe *iwmmxtframe;
1646 iwmmxtframe = (struct target_iwmmxt_sigframe *)regspace;
1647 __put_user(TARGET_IWMMXT_MAGIC, &iwmmxtframe->magic);
1648 __put_user(sizeof(*iwmmxtframe), &iwmmxtframe->size);
1649 for (i = 0; i < 16; i++) {
1650 __put_user(env->iwmmxt.regs[i], &iwmmxtframe->regs[i]);
1651 }
1652 __put_user(env->vfp.xregs[ARM_IWMMXT_wCSSF], &iwmmxtframe->wcssf);
1653 __put_user(env->vfp.xregs[ARM_IWMMXT_wCASF], &iwmmxtframe->wcssf);
1654 __put_user(env->vfp.xregs[ARM_IWMMXT_wCGR0], &iwmmxtframe->wcgr0);
1655 __put_user(env->vfp.xregs[ARM_IWMMXT_wCGR1], &iwmmxtframe->wcgr1);
1656 __put_user(env->vfp.xregs[ARM_IWMMXT_wCGR2], &iwmmxtframe->wcgr2);
1657 __put_user(env->vfp.xregs[ARM_IWMMXT_wCGR3], &iwmmxtframe->wcgr3);
1658 return (abi_ulong*)(iwmmxtframe+1);
1659}
1660
pbrooka8c33202008-05-07 23:22:46 +00001661static void setup_sigframe_v2(struct target_ucontext_v2 *uc,
Andreas Färber05390242012-02-25 03:37:53 +01001662 target_sigset_t *set, CPUARMState *env)
bellard43fff232003-07-09 19:31:39 +00001663{
pbrooka8c33202008-05-07 23:22:46 +00001664 struct target_sigaltstack stack;
1665 int i;
Peter Maydell0d871bd2010-11-24 15:20:05 +00001666 abi_ulong *regspace;
pbrooka8c33202008-05-07 23:22:46 +00001667
1668 /* Clear all the bits of the ucontext we don't use. */
1669 memset(uc, 0, offsetof(struct target_ucontext_v2, tuc_mcontext));
1670
1671 memset(&stack, 0, sizeof(stack));
1672 __put_user(target_sigaltstack_used.ss_sp, &stack.ss_sp);
1673 __put_user(target_sigaltstack_used.ss_size, &stack.ss_size);
1674 __put_user(sas_ss_flags(get_sp_from_cpustate(env)), &stack.ss_flags);
1675 memcpy(&uc->tuc_stack, &stack, sizeof(stack));
1676
1677 setup_sigcontext(&uc->tuc_mcontext, env, set->sig[0]);
Peter Maydell0d871bd2010-11-24 15:20:05 +00001678 /* Save coprocessor signal frame. */
1679 regspace = uc->tuc_regspace;
1680 if (arm_feature(env, ARM_FEATURE_VFP)) {
1681 regspace = setup_sigframe_v2_vfp(regspace, env);
1682 }
Peter Maydell08e11252010-11-24 15:20:07 +00001683 if (arm_feature(env, ARM_FEATURE_IWMMXT)) {
1684 regspace = setup_sigframe_v2_iwmmxt(regspace, env);
1685 }
1686
Peter Maydell0d871bd2010-11-24 15:20:05 +00001687 /* Write terminating magic word */
1688 __put_user(0, regspace);
1689
pbrooka8c33202008-05-07 23:22:46 +00001690 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
1691 __put_user(set->sig[i], &uc->tuc_sigmask.sig[i]);
1692 }
1693}
1694
1695/* compare linux/arch/arm/kernel/signal.c:setup_frame() */
pbrook624f7972008-05-31 16:11:38 +00001696static void setup_frame_v1(int usig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01001697 target_sigset_t *set, CPUARMState *regs)
pbrooka8c33202008-05-07 23:22:46 +00001698{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001699 struct sigframe_v1 *frame;
1700 abi_ulong frame_addr = get_sigframe(ka, regs, sizeof(*frame));
1701 int i;
bellard43fff232003-07-09 19:31:39 +00001702
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001703 trace_user_setup_frame(regs, frame_addr);
1704 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
1705 return;
1706 }
bellard579a97f2007-11-11 14:26:47 +00001707
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001708 setup_sigcontext(&frame->sc, regs, set->sig[0]);
bellard43fff232003-07-09 19:31:39 +00001709
Riku Voipio0188fad2014-04-23 13:34:15 +03001710 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
1711 __put_user(set->sig[i], &frame->extramask[i - 1]);
1712 }
bellard43fff232003-07-09 19:31:39 +00001713
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001714 setup_return(regs, ka, &frame->retcode, frame_addr, usig,
1715 frame_addr + offsetof(struct sigframe_v1, retcode));
bellard579a97f2007-11-11 14:26:47 +00001716
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001717 unlock_user_struct(frame, frame_addr, 1);
pbrooka8c33202008-05-07 23:22:46 +00001718}
1719
pbrook624f7972008-05-31 16:11:38 +00001720static void setup_frame_v2(int usig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01001721 target_sigset_t *set, CPUARMState *regs)
pbrooka8c33202008-05-07 23:22:46 +00001722{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001723 struct sigframe_v2 *frame;
1724 abi_ulong frame_addr = get_sigframe(ka, regs, sizeof(*frame));
pbrooka8c33202008-05-07 23:22:46 +00001725
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001726 trace_user_setup_frame(regs, frame_addr);
1727 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
1728 return;
1729 }
pbrooka8c33202008-05-07 23:22:46 +00001730
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001731 setup_sigframe_v2(&frame->uc, set, regs);
pbrooka8c33202008-05-07 23:22:46 +00001732
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001733 setup_return(regs, ka, &frame->retcode, frame_addr, usig,
1734 frame_addr + offsetof(struct sigframe_v2, retcode));
pbrooka8c33202008-05-07 23:22:46 +00001735
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001736 unlock_user_struct(frame, frame_addr, 1);
pbrooka8c33202008-05-07 23:22:46 +00001737}
1738
pbrook624f7972008-05-31 16:11:38 +00001739static void setup_frame(int usig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01001740 target_sigset_t *set, CPUARMState *regs)
pbrooka8c33202008-05-07 23:22:46 +00001741{
1742 if (get_osversion() >= 0x020612) {
1743 setup_frame_v2(usig, ka, set, regs);
1744 } else {
1745 setup_frame_v1(usig, ka, set, regs);
1746 }
bellard43fff232003-07-09 19:31:39 +00001747}
1748
bellard579a97f2007-11-11 14:26:47 +00001749/* compare linux/arch/arm/kernel/signal.c:setup_rt_frame() */
pbrook624f7972008-05-31 16:11:38 +00001750static void setup_rt_frame_v1(int usig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05001751 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01001752 target_sigset_t *set, CPUARMState *env)
bellard43fff232003-07-09 19:31:39 +00001753{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001754 struct rt_sigframe_v1 *frame;
1755 abi_ulong frame_addr = get_sigframe(ka, env, sizeof(*frame));
1756 struct target_sigaltstack stack;
1757 int i;
1758 abi_ulong info_addr, uc_addr;
bellard43fff232003-07-09 19:31:39 +00001759
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001760 trace_user_setup_rt_frame(env, frame_addr);
1761 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
1762 return /* 1 */;
1763 }
bellardedf779f2004-02-22 13:40:13 +00001764
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001765 info_addr = frame_addr + offsetof(struct rt_sigframe_v1, info);
1766 __put_user(info_addr, &frame->pinfo);
1767 uc_addr = frame_addr + offsetof(struct rt_sigframe_v1, uc);
1768 __put_user(uc_addr, &frame->puc);
1769 tswap_siginfo(&frame->info, info);
bellard43fff232003-07-09 19:31:39 +00001770
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001771 /* Clear all the bits of the ucontext we don't use. */
1772 memset(&frame->uc, 0, offsetof(struct target_ucontext_v1, tuc_mcontext));
bellard43fff232003-07-09 19:31:39 +00001773
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001774 memset(&stack, 0, sizeof(stack));
1775 __put_user(target_sigaltstack_used.ss_sp, &stack.ss_sp);
1776 __put_user(target_sigaltstack_used.ss_size, &stack.ss_size);
1777 __put_user(sas_ss_flags(get_sp_from_cpustate(env)), &stack.ss_flags);
1778 memcpy(&frame->uc.tuc_stack, &stack, sizeof(stack));
thsa04e1342007-09-27 13:57:58 +00001779
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001780 setup_sigcontext(&frame->uc.tuc_mcontext, env, set->sig[0]);
1781 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
1782 __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
1783 }
bellard43fff232003-07-09 19:31:39 +00001784
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001785 setup_return(env, ka, &frame->retcode, frame_addr, usig,
1786 frame_addr + offsetof(struct rt_sigframe_v1, retcode));
pbrooka745ec62008-05-06 15:36:17 +00001787
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001788 env->regs[1] = info_addr;
1789 env->regs[2] = uc_addr;
pbrooka745ec62008-05-06 15:36:17 +00001790
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001791 unlock_user_struct(frame, frame_addr, 1);
pbrooka745ec62008-05-06 15:36:17 +00001792}
1793
pbrook624f7972008-05-31 16:11:38 +00001794static void setup_rt_frame_v2(int usig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05001795 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01001796 target_sigset_t *set, CPUARMState *env)
pbrooka745ec62008-05-06 15:36:17 +00001797{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001798 struct rt_sigframe_v2 *frame;
1799 abi_ulong frame_addr = get_sigframe(ka, env, sizeof(*frame));
1800 abi_ulong info_addr, uc_addr;
pbrooka745ec62008-05-06 15:36:17 +00001801
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001802 trace_user_setup_rt_frame(env, frame_addr);
1803 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
1804 return /* 1 */;
1805 }
pbrooka745ec62008-05-06 15:36:17 +00001806
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001807 info_addr = frame_addr + offsetof(struct rt_sigframe_v2, info);
1808 uc_addr = frame_addr + offsetof(struct rt_sigframe_v2, uc);
1809 tswap_siginfo(&frame->info, info);
pbrooka745ec62008-05-06 15:36:17 +00001810
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001811 setup_sigframe_v2(&frame->uc, set, env);
pbrooka745ec62008-05-06 15:36:17 +00001812
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001813 setup_return(env, ka, &frame->retcode, frame_addr, usig,
1814 frame_addr + offsetof(struct rt_sigframe_v2, retcode));
pbrooka745ec62008-05-06 15:36:17 +00001815
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001816 env->regs[1] = info_addr;
1817 env->regs[2] = uc_addr;
pbrooka745ec62008-05-06 15:36:17 +00001818
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001819 unlock_user_struct(frame, frame_addr, 1);
bellard43fff232003-07-09 19:31:39 +00001820}
1821
pbrook624f7972008-05-31 16:11:38 +00001822static void setup_rt_frame(int usig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05001823 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01001824 target_sigset_t *set, CPUARMState *env)
pbrooka745ec62008-05-06 15:36:17 +00001825{
1826 if (get_osversion() >= 0x020612) {
1827 setup_rt_frame_v2(usig, ka, info, set, env);
1828 } else {
1829 setup_rt_frame_v1(usig, ka, info, set, env);
1830 }
1831}
1832
bellard43fff232003-07-09 19:31:39 +00001833static int
Andreas Färber05390242012-02-25 03:37:53 +01001834restore_sigcontext(CPUARMState *env, struct target_sigcontext *sc)
bellard43fff232003-07-09 19:31:39 +00001835{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001836 int err = 0;
1837 uint32_t cpsr;
bellard43fff232003-07-09 19:31:39 +00001838
Riku Voipio1d8b5122014-04-23 10:26:05 +03001839 __get_user(env->regs[0], &sc->arm_r0);
1840 __get_user(env->regs[1], &sc->arm_r1);
1841 __get_user(env->regs[2], &sc->arm_r2);
1842 __get_user(env->regs[3], &sc->arm_r3);
1843 __get_user(env->regs[4], &sc->arm_r4);
1844 __get_user(env->regs[5], &sc->arm_r5);
1845 __get_user(env->regs[6], &sc->arm_r6);
1846 __get_user(env->regs[7], &sc->arm_r7);
1847 __get_user(env->regs[8], &sc->arm_r8);
1848 __get_user(env->regs[9], &sc->arm_r9);
1849 __get_user(env->regs[10], &sc->arm_r10);
1850 __get_user(env->regs[11], &sc->arm_fp);
1851 __get_user(env->regs[12], &sc->arm_ip);
1852 __get_user(env->regs[13], &sc->arm_sp);
1853 __get_user(env->regs[14], &sc->arm_lr);
1854 __get_user(env->regs[15], &sc->arm_pc);
bellard43fff232003-07-09 19:31:39 +00001855#ifdef TARGET_CONFIG_CPU_32
Riku Voipio1d8b5122014-04-23 10:26:05 +03001856 __get_user(cpsr, &sc->arm_cpsr);
Peter Maydell50866ba2016-02-23 15:36:43 +00001857 cpsr_write(env, cpsr, CPSR_USER | CPSR_EXEC, CPSRWriteByInstr);
bellard43fff232003-07-09 19:31:39 +00001858#endif
1859
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001860 err |= !valid_user_regs(env);
bellard43fff232003-07-09 19:31:39 +00001861
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001862 return err;
bellard43fff232003-07-09 19:31:39 +00001863}
1864
Andreas Färber05390242012-02-25 03:37:53 +01001865static long do_sigreturn_v1(CPUARMState *env)
bellard43fff232003-07-09 19:31:39 +00001866{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001867 abi_ulong frame_addr;
1868 struct sigframe_v1 *frame = NULL;
1869 target_sigset_t set;
1870 sigset_t host_set;
1871 int i;
bellard43fff232003-07-09 19:31:39 +00001872
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001873 /*
1874 * Since we stacked the signal on a 64-bit boundary,
1875 * then 'sp' should be word aligned here. If it's
1876 * not, then the user is trying to mess with us.
1877 */
1878 frame_addr = env->regs[13];
1879 trace_user_do_sigreturn(env, frame_addr);
1880 if (frame_addr & 7) {
1881 goto badframe;
1882 }
Peter Maydell978fae92013-07-29 12:00:32 +01001883
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001884 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
1885 goto badframe;
1886 }
bellard43fff232003-07-09 19:31:39 +00001887
Riku Voipiof5f601a2014-04-23 13:00:17 +03001888 __get_user(set.sig[0], &frame->sc.oldmask);
1889 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
1890 __get_user(set.sig[i], &frame->extramask[i - 1]);
1891 }
bellard43fff232003-07-09 19:31:39 +00001892
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001893 target_to_host_sigset_internal(&host_set, &set);
1894 do_sigprocmask(SIG_SETMASK, &host_set, NULL);
bellard43fff232003-07-09 19:31:39 +00001895
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001896 if (restore_sigcontext(env, &frame->sc)) {
1897 goto badframe;
1898 }
bellard43fff232003-07-09 19:31:39 +00001899
1900#if 0
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001901 /* Send SIGTRAP if we're single-stepping */
1902 if (ptrace_cancel_bpt(current))
1903 send_sig(SIGTRAP, current, 1);
bellard43fff232003-07-09 19:31:39 +00001904#endif
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001905 unlock_user_struct(frame, frame_addr, 0);
1906 return env->regs[0];
bellard43fff232003-07-09 19:31:39 +00001907
1908badframe:
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01001909 force_sig(TARGET_SIGSEGV /* , current */);
1910 return 0;
bellard43fff232003-07-09 19:31:39 +00001911}
1912
Andreas Färber05390242012-02-25 03:37:53 +01001913static abi_ulong *restore_sigframe_v2_vfp(CPUARMState *env, abi_ulong *regspace)
Peter Maydell5f9099d2010-11-24 15:20:06 +00001914{
1915 int i;
1916 abi_ulong magic, sz;
1917 uint32_t fpscr, fpexc;
1918 struct target_vfp_sigframe *vfpframe;
1919 vfpframe = (struct target_vfp_sigframe *)regspace;
1920
1921 __get_user(magic, &vfpframe->magic);
1922 __get_user(sz, &vfpframe->size);
1923 if (magic != TARGET_VFP_MAGIC || sz != sizeof(*vfpframe)) {
1924 return 0;
1925 }
1926 for (i = 0; i < 32; i++) {
Peter Maydell005e1a02011-02-10 13:59:35 +00001927 __get_user(float64_val(env->vfp.regs[i]), &vfpframe->ufp.fpregs[i]);
Peter Maydell5f9099d2010-11-24 15:20:06 +00001928 }
1929 __get_user(fpscr, &vfpframe->ufp.fpscr);
1930 vfp_set_fpscr(env, fpscr);
1931 __get_user(fpexc, &vfpframe->ufp_exc.fpexc);
1932 /* Sanitise FPEXC: ensure VFP is enabled, FPINST2 is invalid
1933 * and the exception flag is cleared
1934 */
1935 fpexc |= (1 << 30);
1936 fpexc &= ~((1 << 31) | (1 << 28));
1937 env->vfp.xregs[ARM_VFP_FPEXC] = fpexc;
1938 __get_user(env->vfp.xregs[ARM_VFP_FPINST], &vfpframe->ufp_exc.fpinst);
1939 __get_user(env->vfp.xregs[ARM_VFP_FPINST2], &vfpframe->ufp_exc.fpinst2);
1940 return (abi_ulong*)(vfpframe + 1);
1941}
1942
Andreas Färber05390242012-02-25 03:37:53 +01001943static abi_ulong *restore_sigframe_v2_iwmmxt(CPUARMState *env,
1944 abi_ulong *regspace)
Peter Maydella59d69d2010-11-24 15:20:08 +00001945{
1946 int i;
1947 abi_ulong magic, sz;
1948 struct target_iwmmxt_sigframe *iwmmxtframe;
1949 iwmmxtframe = (struct target_iwmmxt_sigframe *)regspace;
1950
1951 __get_user(magic, &iwmmxtframe->magic);
1952 __get_user(sz, &iwmmxtframe->size);
1953 if (magic != TARGET_IWMMXT_MAGIC || sz != sizeof(*iwmmxtframe)) {
1954 return 0;
1955 }
1956 for (i = 0; i < 16; i++) {
1957 __get_user(env->iwmmxt.regs[i], &iwmmxtframe->regs[i]);
1958 }
1959 __get_user(env->vfp.xregs[ARM_IWMMXT_wCSSF], &iwmmxtframe->wcssf);
1960 __get_user(env->vfp.xregs[ARM_IWMMXT_wCASF], &iwmmxtframe->wcssf);
1961 __get_user(env->vfp.xregs[ARM_IWMMXT_wCGR0], &iwmmxtframe->wcgr0);
1962 __get_user(env->vfp.xregs[ARM_IWMMXT_wCGR1], &iwmmxtframe->wcgr1);
1963 __get_user(env->vfp.xregs[ARM_IWMMXT_wCGR2], &iwmmxtframe->wcgr2);
1964 __get_user(env->vfp.xregs[ARM_IWMMXT_wCGR3], &iwmmxtframe->wcgr3);
1965 return (abi_ulong*)(iwmmxtframe + 1);
1966}
1967
Andreas Färber05390242012-02-25 03:37:53 +01001968static int do_sigframe_return_v2(CPUARMState *env, target_ulong frame_addr,
pbrooka8c33202008-05-07 23:22:46 +00001969 struct target_ucontext_v2 *uc)
1970{
1971 sigset_t host_set;
Peter Maydell5f9099d2010-11-24 15:20:06 +00001972 abi_ulong *regspace;
pbrooka8c33202008-05-07 23:22:46 +00001973
1974 target_to_host_sigset(&host_set, &uc->tuc_sigmask);
Alex Barcelo1c275922014-03-14 14:36:55 +00001975 do_sigprocmask(SIG_SETMASK, &host_set, NULL);
pbrooka8c33202008-05-07 23:22:46 +00001976
1977 if (restore_sigcontext(env, &uc->tuc_mcontext))
1978 return 1;
1979
Peter Maydell5f9099d2010-11-24 15:20:06 +00001980 /* Restore coprocessor signal frame */
1981 regspace = uc->tuc_regspace;
1982 if (arm_feature(env, ARM_FEATURE_VFP)) {
1983 regspace = restore_sigframe_v2_vfp(env, regspace);
1984 if (!regspace) {
1985 return 1;
1986 }
1987 }
Peter Maydella59d69d2010-11-24 15:20:08 +00001988 if (arm_feature(env, ARM_FEATURE_IWMMXT)) {
1989 regspace = restore_sigframe_v2_iwmmxt(env, regspace);
1990 if (!regspace) {
1991 return 1;
1992 }
1993 }
Peter Maydell5f9099d2010-11-24 15:20:06 +00001994
pbrooka8c33202008-05-07 23:22:46 +00001995 if (do_sigaltstack(frame_addr + offsetof(struct target_ucontext_v2, tuc_stack), 0, get_sp_from_cpustate(env)) == -EFAULT)
1996 return 1;
1997
1998#if 0
1999 /* Send SIGTRAP if we're single-stepping */
2000 if (ptrace_cancel_bpt(current))
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002001 send_sig(SIGTRAP, current, 1);
pbrooka8c33202008-05-07 23:22:46 +00002002#endif
2003
2004 return 0;
2005}
2006
Andreas Färber05390242012-02-25 03:37:53 +01002007static long do_sigreturn_v2(CPUARMState *env)
pbrooka8c33202008-05-07 23:22:46 +00002008{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002009 abi_ulong frame_addr;
2010 struct sigframe_v2 *frame = NULL;
pbrooka8c33202008-05-07 23:22:46 +00002011
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002012 /*
2013 * Since we stacked the signal on a 64-bit boundary,
2014 * then 'sp' should be word aligned here. If it's
2015 * not, then the user is trying to mess with us.
2016 */
2017 frame_addr = env->regs[13];
2018 trace_user_do_sigreturn(env, frame_addr);
2019 if (frame_addr & 7) {
2020 goto badframe;
2021 }
Peter Maydell978fae92013-07-29 12:00:32 +01002022
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002023 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
2024 goto badframe;
2025 }
pbrooka8c33202008-05-07 23:22:46 +00002026
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002027 if (do_sigframe_return_v2(env, frame_addr, &frame->uc)) {
2028 goto badframe;
2029 }
pbrooka8c33202008-05-07 23:22:46 +00002030
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002031 unlock_user_struct(frame, frame_addr, 0);
2032 return env->regs[0];
pbrooka8c33202008-05-07 23:22:46 +00002033
2034badframe:
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002035 unlock_user_struct(frame, frame_addr, 0);
2036 force_sig(TARGET_SIGSEGV /* , current */);
2037 return 0;
pbrooka8c33202008-05-07 23:22:46 +00002038}
2039
Andreas Färber05390242012-02-25 03:37:53 +01002040long do_sigreturn(CPUARMState *env)
pbrooka8c33202008-05-07 23:22:46 +00002041{
2042 if (get_osversion() >= 0x020612) {
2043 return do_sigreturn_v2(env);
2044 } else {
2045 return do_sigreturn_v1(env);
2046 }
2047}
2048
Andreas Färber05390242012-02-25 03:37:53 +01002049static long do_rt_sigreturn_v1(CPUARMState *env)
bellard43fff232003-07-09 19:31:39 +00002050{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002051 abi_ulong frame_addr;
2052 struct rt_sigframe_v1 *frame = NULL;
2053 sigset_t host_set;
bellard43fff232003-07-09 19:31:39 +00002054
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002055 /*
2056 * Since we stacked the signal on a 64-bit boundary,
2057 * then 'sp' should be word aligned here. If it's
2058 * not, then the user is trying to mess with us.
2059 */
2060 frame_addr = env->regs[13];
2061 trace_user_do_rt_sigreturn(env, frame_addr);
2062 if (frame_addr & 7) {
2063 goto badframe;
2064 }
Peter Maydell978fae92013-07-29 12:00:32 +01002065
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002066 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
2067 goto badframe;
2068 }
bellard43fff232003-07-09 19:31:39 +00002069
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002070 target_to_host_sigset(&host_set, &frame->uc.tuc_sigmask);
2071 do_sigprocmask(SIG_SETMASK, &host_set, NULL);
bellard43fff232003-07-09 19:31:39 +00002072
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002073 if (restore_sigcontext(env, &frame->uc.tuc_mcontext)) {
2074 goto badframe;
2075 }
bellard43fff232003-07-09 19:31:39 +00002076
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002077 if (do_sigaltstack(frame_addr + offsetof(struct rt_sigframe_v1, uc.tuc_stack), 0, get_sp_from_cpustate(env)) == -EFAULT)
2078 goto badframe;
thsa04e1342007-09-27 13:57:58 +00002079
bellard43fff232003-07-09 19:31:39 +00002080#if 0
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002081 /* Send SIGTRAP if we're single-stepping */
2082 if (ptrace_cancel_bpt(current))
2083 send_sig(SIGTRAP, current, 1);
bellard43fff232003-07-09 19:31:39 +00002084#endif
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002085 unlock_user_struct(frame, frame_addr, 0);
2086 return env->regs[0];
bellard43fff232003-07-09 19:31:39 +00002087
2088badframe:
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002089 unlock_user_struct(frame, frame_addr, 0);
2090 force_sig(TARGET_SIGSEGV /* , current */);
2091 return 0;
bellard43fff232003-07-09 19:31:39 +00002092}
2093
Andreas Färber05390242012-02-25 03:37:53 +01002094static long do_rt_sigreturn_v2(CPUARMState *env)
pbrooka745ec62008-05-06 15:36:17 +00002095{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002096 abi_ulong frame_addr;
2097 struct rt_sigframe_v2 *frame = NULL;
pbrooka745ec62008-05-06 15:36:17 +00002098
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002099 /*
2100 * Since we stacked the signal on a 64-bit boundary,
2101 * then 'sp' should be word aligned here. If it's
2102 * not, then the user is trying to mess with us.
2103 */
2104 frame_addr = env->regs[13];
2105 trace_user_do_rt_sigreturn(env, frame_addr);
2106 if (frame_addr & 7) {
2107 goto badframe;
2108 }
Peter Maydell978fae92013-07-29 12:00:32 +01002109
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002110 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
2111 goto badframe;
2112 }
pbrooka745ec62008-05-06 15:36:17 +00002113
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002114 if (do_sigframe_return_v2(env, frame_addr, &frame->uc)) {
2115 goto badframe;
2116 }
pbrooka745ec62008-05-06 15:36:17 +00002117
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002118 unlock_user_struct(frame, frame_addr, 0);
2119 return env->regs[0];
pbrooka745ec62008-05-06 15:36:17 +00002120
2121badframe:
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002122 unlock_user_struct(frame, frame_addr, 0);
2123 force_sig(TARGET_SIGSEGV /* , current */);
2124 return 0;
pbrooka745ec62008-05-06 15:36:17 +00002125}
2126
Andreas Färber05390242012-02-25 03:37:53 +01002127long do_rt_sigreturn(CPUARMState *env)
pbrooka745ec62008-05-06 15:36:17 +00002128{
2129 if (get_osversion() >= 0x020612) {
2130 return do_rt_sigreturn_v2(env);
2131 } else {
2132 return do_rt_sigreturn_v1(env);
2133 }
2134}
2135
bellard6d5e2162004-09-30 22:04:13 +00002136#elif defined(TARGET_SPARC)
bellard80a9d032005-01-03 23:31:27 +00002137
bellard6d5e2162004-09-30 22:04:13 +00002138#define __SUNOS_MAXWIN 31
2139
2140/* This is what SunOS does, so shall I. */
2141struct target_sigcontext {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002142 abi_ulong sigc_onstack; /* state to restore */
bellard6d5e2162004-09-30 22:04:13 +00002143
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002144 abi_ulong sigc_mask; /* sigmask to restore */
2145 abi_ulong sigc_sp; /* stack pointer */
2146 abi_ulong sigc_pc; /* program counter */
2147 abi_ulong sigc_npc; /* next program counter */
2148 abi_ulong sigc_psr; /* for condition codes etc */
2149 abi_ulong sigc_g1; /* User uses these two registers */
2150 abi_ulong sigc_o0; /* within the trampoline code. */
bellard6d5e2162004-09-30 22:04:13 +00002151
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002152 /* Now comes information regarding the users window set
bellard6d5e2162004-09-30 22:04:13 +00002153 * at the time of the signal.
2154 */
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002155 abi_ulong sigc_oswins; /* outstanding windows */
bellard6d5e2162004-09-30 22:04:13 +00002156
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002157 /* stack ptrs for each regwin buf */
2158 char *sigc_spbuf[__SUNOS_MAXWIN];
bellard6d5e2162004-09-30 22:04:13 +00002159
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002160 /* Windows to restore after signal */
2161 struct {
2162 abi_ulong locals[8];
2163 abi_ulong ins[8];
2164 } sigc_wbuf[__SUNOS_MAXWIN];
bellard6d5e2162004-09-30 22:04:13 +00002165};
2166/* A Sparc stack frame */
2167struct sparc_stackf {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002168 abi_ulong locals[8];
2169 abi_ulong ins[8];
2170 /* It's simpler to treat fp and callers_pc as elements of ins[]
Peter Maydelle321c342011-02-01 15:54:52 +00002171 * since we never need to access them ourselves.
2172 */
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002173 char *structptr;
2174 abi_ulong xargs[6];
2175 abi_ulong xxargs[1];
bellard6d5e2162004-09-30 22:04:13 +00002176};
2177
2178typedef struct {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002179 struct {
2180 abi_ulong psr;
2181 abi_ulong pc;
2182 abi_ulong npc;
2183 abi_ulong y;
2184 abi_ulong u_regs[16]; /* globals and ins */
2185 } si_regs;
2186 int si_mask;
bellard6d5e2162004-09-30 22:04:13 +00002187} __siginfo_t;
2188
2189typedef struct {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002190 abi_ulong si_float_regs[32];
2191 unsigned long si_fsr;
2192 unsigned long si_fpqdepth;
2193 struct {
2194 unsigned long *insn_addr;
2195 unsigned long insn;
2196 } si_fpqueue [16];
Anthony Liguoric227f092009-10-01 16:12:16 -05002197} qemu_siginfo_fpu_t;
bellard6d5e2162004-09-30 22:04:13 +00002198
2199
2200struct target_signal_frame {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002201 struct sparc_stackf ss;
2202 __siginfo_t info;
2203 abi_ulong fpu_save;
2204 abi_ulong insns[2] __attribute__ ((aligned (8)));
2205 abi_ulong extramask[TARGET_NSIG_WORDS - 1];
2206 abi_ulong extra_size; /* Should be 0 */
2207 qemu_siginfo_fpu_t fpu_state;
bellard6d5e2162004-09-30 22:04:13 +00002208};
2209struct target_rt_signal_frame {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002210 struct sparc_stackf ss;
2211 siginfo_t info;
2212 abi_ulong regs[20];
2213 sigset_t mask;
2214 abi_ulong fpu_save;
2215 unsigned int insns[2];
2216 stack_t stack;
2217 unsigned int extra_size; /* Should be 0 */
2218 qemu_siginfo_fpu_t fpu_state;
bellard6d5e2162004-09-30 22:04:13 +00002219};
2220
bellarde80cfcf2004-12-19 23:18:01 +00002221#define UREG_O0 16
2222#define UREG_O6 22
2223#define UREG_I0 0
2224#define UREG_I1 1
2225#define UREG_I2 2
blueswir15bfb56b2007-10-05 17:01:51 +00002226#define UREG_I3 3
2227#define UREG_I4 4
2228#define UREG_I5 5
bellarde80cfcf2004-12-19 23:18:01 +00002229#define UREG_I6 6
2230#define UREG_I7 7
2231#define UREG_L0 8
bellard6d5e2162004-09-30 22:04:13 +00002232#define UREG_FP UREG_I6
2233#define UREG_SP UREG_O6
2234
pbrook624f7972008-05-31 16:11:38 +00002235static inline abi_ulong get_sigframe(struct target_sigaction *sa,
Andreas Färber05390242012-02-25 03:37:53 +01002236 CPUSPARCState *env,
2237 unsigned long framesize)
bellard6d5e2162004-09-30 22:04:13 +00002238{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002239 abi_ulong sp;
bellard6d5e2162004-09-30 22:04:13 +00002240
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002241 sp = env->regwptr[UREG_FP];
bellard6d5e2162004-09-30 22:04:13 +00002242
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002243 /* This is the X/Open sanctioned signal stack switching. */
2244 if (sa->sa_flags & TARGET_SA_ONSTACK) {
2245 if (!on_sig_stack(sp)
2246 && !((target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size) & 7)) {
2247 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
2248 }
2249 }
2250 return sp - framesize;
bellard6d5e2162004-09-30 22:04:13 +00002251}
2252
2253static int
Andreas Färber05390242012-02-25 03:37:53 +01002254setup___siginfo(__siginfo_t *si, CPUSPARCState *env, abi_ulong mask)
bellard6d5e2162004-09-30 22:04:13 +00002255{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002256 int err = 0, i;
bellard6d5e2162004-09-30 22:04:13 +00002257
Riku Voipio1d8b5122014-04-23 10:26:05 +03002258 __put_user(env->psr, &si->si_regs.psr);
2259 __put_user(env->pc, &si->si_regs.pc);
2260 __put_user(env->npc, &si->si_regs.npc);
2261 __put_user(env->y, &si->si_regs.y);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002262 for (i=0; i < 8; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002263 __put_user(env->gregs[i], &si->si_regs.u_regs[i]);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002264 }
2265 for (i=0; i < 8; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002266 __put_user(env->regwptr[UREG_I0 + i], &si->si_regs.u_regs[i+8]);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002267 }
Riku Voipio1d8b5122014-04-23 10:26:05 +03002268 __put_user(mask, &si->si_mask);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002269 return err;
bellard6d5e2162004-09-30 22:04:13 +00002270}
bellarde80cfcf2004-12-19 23:18:01 +00002271
bellard80a9d032005-01-03 23:31:27 +00002272#if 0
bellard6d5e2162004-09-30 22:04:13 +00002273static int
2274setup_sigcontext(struct target_sigcontext *sc, /*struct _fpstate *fpstate,*/
Andreas Färber05390242012-02-25 03:37:53 +01002275 CPUSPARCState *env, unsigned long mask)
bellard6d5e2162004-09-30 22:04:13 +00002276{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002277 int err = 0;
bellard6d5e2162004-09-30 22:04:13 +00002278
Riku Voipio1d8b5122014-04-23 10:26:05 +03002279 __put_user(mask, &sc->sigc_mask);
2280 __put_user(env->regwptr[UREG_SP], &sc->sigc_sp);
2281 __put_user(env->pc, &sc->sigc_pc);
2282 __put_user(env->npc, &sc->sigc_npc);
2283 __put_user(env->psr, &sc->sigc_psr);
2284 __put_user(env->gregs[1], &sc->sigc_g1);
2285 __put_user(env->regwptr[UREG_O0], &sc->sigc_o0);
bellard6d5e2162004-09-30 22:04:13 +00002286
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002287 return err;
bellard6d5e2162004-09-30 22:04:13 +00002288}
bellard80a9d032005-01-03 23:31:27 +00002289#endif
bellard6d5e2162004-09-30 22:04:13 +00002290#define NF_ALIGNEDSZ (((sizeof(struct target_signal_frame) + 7) & (~7)))
2291
pbrook624f7972008-05-31 16:11:38 +00002292static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01002293 target_sigset_t *set, CPUSPARCState *env)
bellard6d5e2162004-09-30 22:04:13 +00002294{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002295 abi_ulong sf_addr;
2296 struct target_signal_frame *sf;
2297 int sigframe_size, err, i;
bellard6d5e2162004-09-30 22:04:13 +00002298
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002299 /* 1. Make sure everything is clean */
2300 //synchronize_user_stack();
bellard6d5e2162004-09-30 22:04:13 +00002301
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002302 sigframe_size = NF_ALIGNEDSZ;
2303 sf_addr = get_sigframe(ka, env, sigframe_size);
2304 trace_user_setup_frame(env, sf_addr);
bellard6d5e2162004-09-30 22:04:13 +00002305
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002306 sf = lock_user(VERIFY_WRITE, sf_addr,
2307 sizeof(struct target_signal_frame), 0);
2308 if (!sf) {
2309 goto sigsegv;
2310 }
bellard6d5e2162004-09-30 22:04:13 +00002311#if 0
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002312 if (invalid_frame_pointer(sf, sigframe_size))
2313 goto sigill_and_return;
bellard6d5e2162004-09-30 22:04:13 +00002314#endif
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002315 /* 2. Save the current process state */
2316 err = setup___siginfo(&sf->info, env, set->sig[0]);
Riku Voipio1d8b5122014-04-23 10:26:05 +03002317 __put_user(0, &sf->extra_size);
bellard6d5e2162004-09-30 22:04:13 +00002318
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002319 //save_fpu_state(regs, &sf->fpu_state);
2320 //__put_user(&sf->fpu_state, &sf->fpu_save);
bellard6d5e2162004-09-30 22:04:13 +00002321
Riku Voipio1d8b5122014-04-23 10:26:05 +03002322 __put_user(set->sig[0], &sf->info.si_mask);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002323 for (i = 0; i < TARGET_NSIG_WORDS - 1; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002324 __put_user(set->sig[i + 1], &sf->extramask[i]);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002325 }
bellard6d5e2162004-09-30 22:04:13 +00002326
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002327 for (i = 0; i < 8; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002328 __put_user(env->regwptr[i + UREG_L0], &sf->ss.locals[i]);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002329 }
2330 for (i = 0; i < 8; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002331 __put_user(env->regwptr[i + UREG_I0], &sf->ss.ins[i]);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002332 }
2333 if (err)
2334 goto sigsegv;
bellard6d5e2162004-09-30 22:04:13 +00002335
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002336 /* 3. signal handler back-trampoline and parameters */
2337 env->regwptr[UREG_FP] = sf_addr;
2338 env->regwptr[UREG_I0] = sig;
2339 env->regwptr[UREG_I1] = sf_addr +
2340 offsetof(struct target_signal_frame, info);
2341 env->regwptr[UREG_I2] = sf_addr +
2342 offsetof(struct target_signal_frame, info);
bellard6d5e2162004-09-30 22:04:13 +00002343
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002344 /* 4. signal handler */
2345 env->pc = ka->_sa_handler;
2346 env->npc = (env->pc + 4);
2347 /* 5. return to kernel instructions */
2348 if (ka->sa_restorer) {
2349 env->regwptr[UREG_I7] = ka->sa_restorer;
2350 } else {
2351 uint32_t val32;
bellard459a4012007-11-11 19:45:10 +00002352
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002353 env->regwptr[UREG_I7] = sf_addr +
2354 offsetof(struct target_signal_frame, insns) - 2 * 4;
bellard6d5e2162004-09-30 22:04:13 +00002355
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002356 /* mov __NR_sigreturn, %g1 */
2357 val32 = 0x821020d8;
Riku Voipio1d8b5122014-04-23 10:26:05 +03002358 __put_user(val32, &sf->insns[0]);
bellard6d5e2162004-09-30 22:04:13 +00002359
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002360 /* t 0x10 */
2361 val32 = 0x91d02010;
Riku Voipio1d8b5122014-04-23 10:26:05 +03002362 __put_user(val32, &sf->insns[1]);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002363 if (err)
2364 goto sigsegv;
bellard6d5e2162004-09-30 22:04:13 +00002365
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002366 /* Flush instruction space. */
2367 // flush_sig_insns(current->mm, (unsigned long) &(sf->insns[0]));
2368 // tb_flush(env);
2369 }
2370 unlock_user(sf, sf_addr, sizeof(struct target_signal_frame));
2371 return;
bellard459a4012007-11-11 19:45:10 +00002372#if 0
2373sigill_and_return:
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002374 force_sig(TARGET_SIGILL);
bellard459a4012007-11-11 19:45:10 +00002375#endif
bellard6d5e2162004-09-30 22:04:13 +00002376sigsegv:
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002377 unlock_user(sf, sf_addr, sizeof(struct target_signal_frame));
2378 force_sig(TARGET_SIGSEGV);
bellard6d5e2162004-09-30 22:04:13 +00002379}
bellard6d5e2162004-09-30 22:04:13 +00002380
pbrook624f7972008-05-31 16:11:38 +00002381static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05002382 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01002383 target_sigset_t *set, CPUSPARCState *env)
bellard6d5e2162004-09-30 22:04:13 +00002384{
2385 fprintf(stderr, "setup_rt_frame: not implemented\n");
2386}
2387
Andreas Färber05390242012-02-25 03:37:53 +01002388long do_sigreturn(CPUSPARCState *env)
bellard6d5e2162004-09-30 22:04:13 +00002389{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002390 abi_ulong sf_addr;
2391 struct target_signal_frame *sf;
2392 uint32_t up_psr, pc, npc;
2393 target_sigset_t set;
2394 sigset_t host_set;
2395 int err=0, i;
bellard6d5e2162004-09-30 22:04:13 +00002396
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002397 sf_addr = env->regwptr[UREG_FP];
2398 trace_user_do_sigreturn(env, sf_addr);
2399 if (!lock_user_struct(VERIFY_READ, sf, sf_addr, 1)) {
2400 goto segv_and_exit;
2401 }
bellard6d5e2162004-09-30 22:04:13 +00002402
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002403 /* 1. Make sure we are not getting garbage from the user */
bellard6d5e2162004-09-30 22:04:13 +00002404
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002405 if (sf_addr & 3)
2406 goto segv_and_exit;
bellard6d5e2162004-09-30 22:04:13 +00002407
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002408 __get_user(pc, &sf->info.si_regs.pc);
2409 __get_user(npc, &sf->info.si_regs.npc);
bellard6d5e2162004-09-30 22:04:13 +00002410
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002411 if ((pc | npc) & 3) {
2412 goto segv_and_exit;
2413 }
bellard6d5e2162004-09-30 22:04:13 +00002414
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002415 /* 2. Restore the state */
2416 __get_user(up_psr, &sf->info.si_regs.psr);
bellarde80cfcf2004-12-19 23:18:01 +00002417
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002418 /* User can only change condition codes and FPU enabling in %psr. */
2419 env->psr = (up_psr & (PSR_ICC /* | PSR_EF */))
2420 | (env->psr & ~(PSR_ICC /* | PSR_EF */));
bellarda315a142005-01-30 22:59:18 +00002421
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002422 env->pc = pc;
2423 env->npc = npc;
2424 __get_user(env->y, &sf->info.si_regs.y);
2425 for (i=0; i < 8; i++) {
2426 __get_user(env->gregs[i], &sf->info.si_regs.u_regs[i]);
2427 }
2428 for (i=0; i < 8; i++) {
2429 __get_user(env->regwptr[i + UREG_I0], &sf->info.si_regs.u_regs[i+8]);
2430 }
bellard6d5e2162004-09-30 22:04:13 +00002431
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002432 /* FIXME: implement FPU save/restore:
Peter Maydell2aec3a22011-06-16 17:37:14 +01002433 * __get_user(fpu_save, &sf->fpu_save);
2434 * if (fpu_save)
2435 * err |= restore_fpu_state(env, fpu_save);
2436 */
bellard6d5e2162004-09-30 22:04:13 +00002437
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002438 /* This is pretty much atomic, no amount locking would prevent
bellard6d5e2162004-09-30 22:04:13 +00002439 * the races which exist anyways.
2440 */
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002441 __get_user(set.sig[0], &sf->info.si_mask);
2442 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
2443 __get_user(set.sig[i], &sf->extramask[i - 1]);
2444 }
bellarde80cfcf2004-12-19 23:18:01 +00002445
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002446 target_to_host_sigset_internal(&host_set, &set);
2447 do_sigprocmask(SIG_SETMASK, &host_set, NULL);
bellard6d5e2162004-09-30 22:04:13 +00002448
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002449 if (err) {
2450 goto segv_and_exit;
2451 }
2452 unlock_user_struct(sf, sf_addr, 0);
2453 return env->regwptr[0];
bellard6d5e2162004-09-30 22:04:13 +00002454
2455segv_and_exit:
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002456 unlock_user_struct(sf, sf_addr, 0);
2457 force_sig(TARGET_SIGSEGV);
bellard6d5e2162004-09-30 22:04:13 +00002458}
2459
Andreas Färber05390242012-02-25 03:37:53 +01002460long do_rt_sigreturn(CPUSPARCState *env)
bellard6d5e2162004-09-30 22:04:13 +00002461{
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01002462 trace_user_do_rt_sigreturn(env, 0);
bellard6d5e2162004-09-30 22:04:13 +00002463 fprintf(stderr, "do_rt_sigreturn: not implemented\n");
bellardf8b0aa22007-11-11 23:03:42 +00002464 return -TARGET_ENOSYS;
bellard6d5e2162004-09-30 22:04:13 +00002465}
2466
bellard459a4012007-11-11 19:45:10 +00002467#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
blueswir15bfb56b2007-10-05 17:01:51 +00002468#define MC_TSTATE 0
2469#define MC_PC 1
2470#define MC_NPC 2
2471#define MC_Y 3
2472#define MC_G1 4
2473#define MC_G2 5
2474#define MC_G3 6
2475#define MC_G4 7
2476#define MC_G5 8
2477#define MC_G6 9
2478#define MC_G7 10
2479#define MC_O0 11
2480#define MC_O1 12
2481#define MC_O2 13
2482#define MC_O3 14
2483#define MC_O4 15
2484#define MC_O5 16
2485#define MC_O6 17
2486#define MC_O7 18
2487#define MC_NGREG 19
2488
Anthony Liguoric227f092009-10-01 16:12:16 -05002489typedef abi_ulong target_mc_greg_t;
2490typedef target_mc_greg_t target_mc_gregset_t[MC_NGREG];
blueswir15bfb56b2007-10-05 17:01:51 +00002491
2492struct target_mc_fq {
blueswir1992f48a2007-10-14 16:27:31 +00002493 abi_ulong *mcfq_addr;
blueswir15bfb56b2007-10-05 17:01:51 +00002494 uint32_t mcfq_insn;
2495};
2496
2497struct target_mc_fpu {
2498 union {
2499 uint32_t sregs[32];
2500 uint64_t dregs[32];
2501 //uint128_t qregs[16];
2502 } mcfpu_fregs;
blueswir1992f48a2007-10-14 16:27:31 +00002503 abi_ulong mcfpu_fsr;
2504 abi_ulong mcfpu_fprs;
2505 abi_ulong mcfpu_gsr;
blueswir15bfb56b2007-10-05 17:01:51 +00002506 struct target_mc_fq *mcfpu_fq;
2507 unsigned char mcfpu_qcnt;
2508 unsigned char mcfpu_qentsz;
2509 unsigned char mcfpu_enab;
2510};
Anthony Liguoric227f092009-10-01 16:12:16 -05002511typedef struct target_mc_fpu target_mc_fpu_t;
blueswir15bfb56b2007-10-05 17:01:51 +00002512
2513typedef struct {
Anthony Liguoric227f092009-10-01 16:12:16 -05002514 target_mc_gregset_t mc_gregs;
2515 target_mc_greg_t mc_fp;
2516 target_mc_greg_t mc_i7;
2517 target_mc_fpu_t mc_fpregs;
2518} target_mcontext_t;
blueswir15bfb56b2007-10-05 17:01:51 +00002519
2520struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02002521 struct target_ucontext *tuc_link;
2522 abi_ulong tuc_flags;
2523 target_sigset_t tuc_sigmask;
2524 target_mcontext_t tuc_mcontext;
blueswir15bfb56b2007-10-05 17:01:51 +00002525};
2526
2527/* A V9 register window */
2528struct target_reg_window {
blueswir1992f48a2007-10-14 16:27:31 +00002529 abi_ulong locals[8];
2530 abi_ulong ins[8];
blueswir15bfb56b2007-10-05 17:01:51 +00002531};
2532
2533#define TARGET_STACK_BIAS 2047
2534
2535/* {set, get}context() needed for 64-bit SparcLinux userland. */
2536void sparc64_set_context(CPUSPARCState *env)
2537{
bellard459a4012007-11-11 19:45:10 +00002538 abi_ulong ucp_addr;
2539 struct target_ucontext *ucp;
Anthony Liguoric227f092009-10-01 16:12:16 -05002540 target_mc_gregset_t *grp;
blueswir1992f48a2007-10-14 16:27:31 +00002541 abi_ulong pc, npc, tstate;
bellard459a4012007-11-11 19:45:10 +00002542 abi_ulong fp, i7, w_addr;
blueswir15bfb56b2007-10-05 17:01:51 +00002543 unsigned int i;
blueswir15bfb56b2007-10-05 17:01:51 +00002544
bellard459a4012007-11-11 19:45:10 +00002545 ucp_addr = env->regwptr[UREG_I0];
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002546 if (!lock_user_struct(VERIFY_READ, ucp, ucp_addr, 1)) {
bellard459a4012007-11-11 19:45:10 +00002547 goto do_sigsegv;
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002548 }
Aurelien Jarno60e99242010-03-29 02:12:51 +02002549 grp = &ucp->tuc_mcontext.mc_gregs;
Riku Voipio1d8b5122014-04-23 10:26:05 +03002550 __get_user(pc, &((*grp)[MC_PC]));
2551 __get_user(npc, &((*grp)[MC_NPC]));
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002552 if ((pc | npc) & 3) {
blueswir15bfb56b2007-10-05 17:01:51 +00002553 goto do_sigsegv;
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002554 }
blueswir15bfb56b2007-10-05 17:01:51 +00002555 if (env->regwptr[UREG_I1]) {
Anthony Liguoric227f092009-10-01 16:12:16 -05002556 target_sigset_t target_set;
blueswir15bfb56b2007-10-05 17:01:51 +00002557 sigset_t set;
2558
2559 if (TARGET_NSIG_WORDS == 1) {
Riku Voipiobe3ef5c2014-04-23 14:02:36 +03002560 __get_user(target_set.sig[0], &ucp->tuc_sigmask.sig[0]);
blueswir15bfb56b2007-10-05 17:01:51 +00002561 } else {
bellard459a4012007-11-11 19:45:10 +00002562 abi_ulong *src, *dst;
Aurelien Jarno60e99242010-03-29 02:12:51 +02002563 src = ucp->tuc_sigmask.sig;
bellard459a4012007-11-11 19:45:10 +00002564 dst = target_set.sig;
Stefan Weil0d9e61c2013-12-07 14:48:08 +01002565 for (i = 0; i < TARGET_NSIG_WORDS; i++, dst++, src++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002566 __get_user(*dst, src);
Stefan Weil0d9e61c2013-12-07 14:48:08 +01002567 }
blueswir15bfb56b2007-10-05 17:01:51 +00002568 }
2569 target_to_host_sigset_internal(&set, &target_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00002570 do_sigprocmask(SIG_SETMASK, &set, NULL);
blueswir15bfb56b2007-10-05 17:01:51 +00002571 }
2572 env->pc = pc;
2573 env->npc = npc;
Riku Voipio1d8b5122014-04-23 10:26:05 +03002574 __get_user(env->y, &((*grp)[MC_Y]));
2575 __get_user(tstate, &((*grp)[MC_TSTATE]));
blueswir15bfb56b2007-10-05 17:01:51 +00002576 env->asi = (tstate >> 24) & 0xff;
Blue Swirl5a834bb2010-05-09 20:19:04 +00002577 cpu_put_ccr(env, tstate >> 32);
2578 cpu_put_cwp64(env, tstate & 0x1f);
Riku Voipio1d8b5122014-04-23 10:26:05 +03002579 __get_user(env->gregs[1], (&(*grp)[MC_G1]));
2580 __get_user(env->gregs[2], (&(*grp)[MC_G2]));
2581 __get_user(env->gregs[3], (&(*grp)[MC_G3]));
2582 __get_user(env->gregs[4], (&(*grp)[MC_G4]));
2583 __get_user(env->gregs[5], (&(*grp)[MC_G5]));
2584 __get_user(env->gregs[6], (&(*grp)[MC_G6]));
2585 __get_user(env->gregs[7], (&(*grp)[MC_G7]));
2586 __get_user(env->regwptr[UREG_I0], (&(*grp)[MC_O0]));
2587 __get_user(env->regwptr[UREG_I1], (&(*grp)[MC_O1]));
2588 __get_user(env->regwptr[UREG_I2], (&(*grp)[MC_O2]));
2589 __get_user(env->regwptr[UREG_I3], (&(*grp)[MC_O3]));
2590 __get_user(env->regwptr[UREG_I4], (&(*grp)[MC_O4]));
2591 __get_user(env->regwptr[UREG_I5], (&(*grp)[MC_O5]));
2592 __get_user(env->regwptr[UREG_I6], (&(*grp)[MC_O6]));
2593 __get_user(env->regwptr[UREG_I7], (&(*grp)[MC_O7]));
blueswir15bfb56b2007-10-05 17:01:51 +00002594
Riku Voipio1d8b5122014-04-23 10:26:05 +03002595 __get_user(fp, &(ucp->tuc_mcontext.mc_fp));
2596 __get_user(i7, &(ucp->tuc_mcontext.mc_i7));
blueswir15bfb56b2007-10-05 17:01:51 +00002597
bellard459a4012007-11-11 19:45:10 +00002598 w_addr = TARGET_STACK_BIAS+env->regwptr[UREG_I6];
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002599 if (put_user(fp, w_addr + offsetof(struct target_reg_window, ins[6]),
2600 abi_ulong) != 0) {
bellard459a4012007-11-11 19:45:10 +00002601 goto do_sigsegv;
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002602 }
2603 if (put_user(i7, w_addr + offsetof(struct target_reg_window, ins[7]),
2604 abi_ulong) != 0) {
bellard459a4012007-11-11 19:45:10 +00002605 goto do_sigsegv;
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002606 }
Peter Maydellc7b016b2011-06-16 17:37:15 +01002607 /* FIXME this does not match how the kernel handles the FPU in
2608 * its sparc64_set_context implementation. In particular the FPU
2609 * is only restored if fenab is non-zero in:
2610 * __get_user(fenab, &(ucp->tuc_mcontext.mc_fpregs.mcfpu_enab));
2611 */
Riku Voipiobe3ef5c2014-04-23 14:02:36 +03002612 __get_user(env->fprs, &(ucp->tuc_mcontext.mc_fpregs.mcfpu_fprs));
bellard459a4012007-11-11 19:45:10 +00002613 {
Richard Henderson30038fd2011-10-17 10:42:49 -07002614 uint32_t *src = ucp->tuc_mcontext.mc_fpregs.mcfpu_fregs.sregs;
2615 for (i = 0; i < 64; i++, src++) {
2616 if (i & 1) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002617 __get_user(env->fpr[i/2].l.lower, src);
Richard Henderson30038fd2011-10-17 10:42:49 -07002618 } else {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002619 __get_user(env->fpr[i/2].l.upper, src);
Richard Henderson30038fd2011-10-17 10:42:49 -07002620 }
2621 }
bellard459a4012007-11-11 19:45:10 +00002622 }
Riku Voipio1d8b5122014-04-23 10:26:05 +03002623 __get_user(env->fsr,
2624 &(ucp->tuc_mcontext.mc_fpregs.mcfpu_fsr));
2625 __get_user(env->gsr,
2626 &(ucp->tuc_mcontext.mc_fpregs.mcfpu_gsr));
bellard459a4012007-11-11 19:45:10 +00002627 unlock_user_struct(ucp, ucp_addr, 0);
blueswir15bfb56b2007-10-05 17:01:51 +00002628 return;
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002629do_sigsegv:
bellard459a4012007-11-11 19:45:10 +00002630 unlock_user_struct(ucp, ucp_addr, 0);
Riku Voipio66393fb2009-12-04 15:16:32 +02002631 force_sig(TARGET_SIGSEGV);
blueswir15bfb56b2007-10-05 17:01:51 +00002632}
2633
2634void sparc64_get_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;
2639 target_mcontext_t *mcp;
bellard459a4012007-11-11 19:45:10 +00002640 abi_ulong fp, i7, w_addr;
blueswir15bfb56b2007-10-05 17:01:51 +00002641 int err;
2642 unsigned int i;
Anthony Liguoric227f092009-10-01 16:12:16 -05002643 target_sigset_t target_set;
blueswir15bfb56b2007-10-05 17:01:51 +00002644 sigset_t set;
2645
bellard459a4012007-11-11 19:45:10 +00002646 ucp_addr = env->regwptr[UREG_I0];
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002647 if (!lock_user_struct(VERIFY_WRITE, ucp, ucp_addr, 0)) {
bellard459a4012007-11-11 19:45:10 +00002648 goto do_sigsegv;
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002649 }
bellard459a4012007-11-11 19:45:10 +00002650
Aurelien Jarno60e99242010-03-29 02:12:51 +02002651 mcp = &ucp->tuc_mcontext;
blueswir15bfb56b2007-10-05 17:01:51 +00002652 grp = &mcp->mc_gregs;
2653
2654 /* Skip over the trap instruction, first. */
2655 env->pc = env->npc;
2656 env->npc += 4;
2657
2658 err = 0;
2659
Alex Barcelo1c275922014-03-14 14:36:55 +00002660 do_sigprocmask(0, NULL, &set);
blueswir15bfb56b2007-10-05 17:01:51 +00002661 host_to_target_sigset_internal(&target_set, &set);
bellard459a4012007-11-11 19:45:10 +00002662 if (TARGET_NSIG_WORDS == 1) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002663 __put_user(target_set.sig[0],
2664 (abi_ulong *)&ucp->tuc_sigmask);
bellard459a4012007-11-11 19:45:10 +00002665 } else {
2666 abi_ulong *src, *dst;
2667 src = target_set.sig;
Aurelien Jarno60e99242010-03-29 02:12:51 +02002668 dst = ucp->tuc_sigmask.sig;
Stefan Weil0d9e61c2013-12-07 14:48:08 +01002669 for (i = 0; i < TARGET_NSIG_WORDS; i++, dst++, src++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002670 __put_user(*src, dst);
Stefan Weil0d9e61c2013-12-07 14:48:08 +01002671 }
blueswir15bfb56b2007-10-05 17:01:51 +00002672 if (err)
2673 goto do_sigsegv;
2674 }
2675
bellard459a4012007-11-11 19:45:10 +00002676 /* XXX: tstate must be saved properly */
Riku Voipio1d8b5122014-04-23 10:26:05 +03002677 // __put_user(env->tstate, &((*grp)[MC_TSTATE]));
2678 __put_user(env->pc, &((*grp)[MC_PC]));
2679 __put_user(env->npc, &((*grp)[MC_NPC]));
2680 __put_user(env->y, &((*grp)[MC_Y]));
2681 __put_user(env->gregs[1], &((*grp)[MC_G1]));
2682 __put_user(env->gregs[2], &((*grp)[MC_G2]));
2683 __put_user(env->gregs[3], &((*grp)[MC_G3]));
2684 __put_user(env->gregs[4], &((*grp)[MC_G4]));
2685 __put_user(env->gregs[5], &((*grp)[MC_G5]));
2686 __put_user(env->gregs[6], &((*grp)[MC_G6]));
2687 __put_user(env->gregs[7], &((*grp)[MC_G7]));
2688 __put_user(env->regwptr[UREG_I0], &((*grp)[MC_O0]));
2689 __put_user(env->regwptr[UREG_I1], &((*grp)[MC_O1]));
2690 __put_user(env->regwptr[UREG_I2], &((*grp)[MC_O2]));
2691 __put_user(env->regwptr[UREG_I3], &((*grp)[MC_O3]));
2692 __put_user(env->regwptr[UREG_I4], &((*grp)[MC_O4]));
2693 __put_user(env->regwptr[UREG_I5], &((*grp)[MC_O5]));
2694 __put_user(env->regwptr[UREG_I6], &((*grp)[MC_O6]));
2695 __put_user(env->regwptr[UREG_I7], &((*grp)[MC_O7]));
blueswir15bfb56b2007-10-05 17:01:51 +00002696
bellard459a4012007-11-11 19:45:10 +00002697 w_addr = TARGET_STACK_BIAS+env->regwptr[UREG_I6];
2698 fp = i7 = 0;
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002699 if (get_user(fp, w_addr + offsetof(struct target_reg_window, ins[6]),
2700 abi_ulong) != 0) {
bellard459a4012007-11-11 19:45:10 +00002701 goto do_sigsegv;
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002702 }
2703 if (get_user(i7, w_addr + offsetof(struct target_reg_window, ins[7]),
2704 abi_ulong) != 0) {
bellard459a4012007-11-11 19:45:10 +00002705 goto do_sigsegv;
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002706 }
Riku Voipio1d8b5122014-04-23 10:26:05 +03002707 __put_user(fp, &(mcp->mc_fp));
2708 __put_user(i7, &(mcp->mc_i7));
blueswir15bfb56b2007-10-05 17:01:51 +00002709
bellard459a4012007-11-11 19:45:10 +00002710 {
Richard Henderson30038fd2011-10-17 10:42:49 -07002711 uint32_t *dst = ucp->tuc_mcontext.mc_fpregs.mcfpu_fregs.sregs;
2712 for (i = 0; i < 64; i++, dst++) {
2713 if (i & 1) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002714 __put_user(env->fpr[i/2].l.lower, dst);
Richard Henderson30038fd2011-10-17 10:42:49 -07002715 } else {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002716 __put_user(env->fpr[i/2].l.upper, dst);
Richard Henderson30038fd2011-10-17 10:42:49 -07002717 }
2718 }
bellard459a4012007-11-11 19:45:10 +00002719 }
Riku Voipio1d8b5122014-04-23 10:26:05 +03002720 __put_user(env->fsr, &(mcp->mc_fpregs.mcfpu_fsr));
2721 __put_user(env->gsr, &(mcp->mc_fpregs.mcfpu_gsr));
2722 __put_user(env->fprs, &(mcp->mc_fpregs.mcfpu_fprs));
blueswir15bfb56b2007-10-05 17:01:51 +00002723
2724 if (err)
2725 goto do_sigsegv;
bellard459a4012007-11-11 19:45:10 +00002726 unlock_user_struct(ucp, ucp_addr, 1);
blueswir15bfb56b2007-10-05 17:01:51 +00002727 return;
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002728do_sigsegv:
bellard459a4012007-11-11 19:45:10 +00002729 unlock_user_struct(ucp, ucp_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02002730 force_sig(TARGET_SIGSEGV);
blueswir15bfb56b2007-10-05 17:01:51 +00002731}
2732#endif
Richard Hendersonff970902013-02-10 10:30:42 -08002733#elif defined(TARGET_MIPS) || defined(TARGET_MIPS64)
bellard106ec872006-06-27 21:08:10 +00002734
Richard Hendersonff970902013-02-10 10:30:42 -08002735# if defined(TARGET_ABI_MIPSO32)
bellard106ec872006-06-27 21:08:10 +00002736struct target_sigcontext {
2737 uint32_t sc_regmask; /* Unused */
2738 uint32_t sc_status;
2739 uint64_t sc_pc;
2740 uint64_t sc_regs[32];
2741 uint64_t sc_fpregs[32];
2742 uint32_t sc_ownedfp; /* Unused */
2743 uint32_t sc_fpc_csr;
2744 uint32_t sc_fpc_eir; /* Unused */
2745 uint32_t sc_used_math;
2746 uint32_t sc_dsp; /* dsp status, was sc_ssflags */
Paul Brook94c54952009-07-09 18:40:15 +01002747 uint32_t pad0;
bellard106ec872006-06-27 21:08:10 +00002748 uint64_t sc_mdhi;
2749 uint64_t sc_mdlo;
2750 target_ulong sc_hi1; /* Was sc_cause */
2751 target_ulong sc_lo1; /* Was sc_badvaddr */
2752 target_ulong sc_hi2; /* Was sc_sigset[4] */
2753 target_ulong sc_lo2;
2754 target_ulong sc_hi3;
2755 target_ulong sc_lo3;
2756};
Richard Hendersonff970902013-02-10 10:30:42 -08002757# else /* N32 || N64 */
2758struct target_sigcontext {
2759 uint64_t sc_regs[32];
2760 uint64_t sc_fpregs[32];
2761 uint64_t sc_mdhi;
2762 uint64_t sc_hi1;
2763 uint64_t sc_hi2;
2764 uint64_t sc_hi3;
2765 uint64_t sc_mdlo;
2766 uint64_t sc_lo1;
2767 uint64_t sc_lo2;
2768 uint64_t sc_lo3;
2769 uint64_t sc_pc;
2770 uint32_t sc_fpc_csr;
2771 uint32_t sc_used_math;
2772 uint32_t sc_dsp;
2773 uint32_t sc_reserved;
2774};
2775# endif /* O32 */
bellard106ec872006-06-27 21:08:10 +00002776
2777struct sigframe {
2778 uint32_t sf_ass[4]; /* argument save space for o32 */
2779 uint32_t sf_code[2]; /* signal trampoline */
2780 struct target_sigcontext sf_sc;
Anthony Liguoric227f092009-10-01 16:12:16 -05002781 target_sigset_t sf_mask;
bellard106ec872006-06-27 21:08:10 +00002782};
2783
pbrook0b1bcb02009-04-21 01:41:10 +00002784struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02002785 target_ulong tuc_flags;
2786 target_ulong tuc_link;
2787 target_stack_t tuc_stack;
Paul Brook94c54952009-07-09 18:40:15 +01002788 target_ulong pad0;
Aurelien Jarno60e99242010-03-29 02:12:51 +02002789 struct target_sigcontext tuc_mcontext;
2790 target_sigset_t tuc_sigmask;
pbrook0b1bcb02009-04-21 01:41:10 +00002791};
2792
2793struct target_rt_sigframe {
2794 uint32_t rs_ass[4]; /* argument save space for o32 */
2795 uint32_t rs_code[2]; /* signal trampoline */
2796 struct target_siginfo rs_info;
2797 struct target_ucontext rs_uc;
2798};
2799
bellard106ec872006-06-27 21:08:10 +00002800/* Install trampoline to jump back from signal handler */
2801static inline int install_sigtramp(unsigned int *tramp, unsigned int syscall)
2802{
Richard Henderson084d0492013-02-10 10:30:44 -08002803 int err = 0;
bellard106ec872006-06-27 21:08:10 +00002804
2805 /*
Richard Henderson084d0492013-02-10 10:30:44 -08002806 * Set up the return code ...
2807 *
2808 * li v0, __NR__foo_sigreturn
2809 * syscall
2810 */
bellard106ec872006-06-27 21:08:10 +00002811
Riku Voipio1d8b5122014-04-23 10:26:05 +03002812 __put_user(0x24020000 + syscall, tramp + 0);
2813 __put_user(0x0000000c , tramp + 1);
bellard106ec872006-06-27 21:08:10 +00002814 return err;
2815}
2816
Riku Voipio41ecc722014-04-23 11:01:00 +03002817static inline void setup_sigcontext(CPUMIPSState *regs,
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002818 struct target_sigcontext *sc)
bellard106ec872006-06-27 21:08:10 +00002819{
Richard Henderson084d0492013-02-10 10:30:44 -08002820 int i;
bellard106ec872006-06-27 21:08:10 +00002821
Riku Voipio1d8b5122014-04-23 10:26:05 +03002822 __put_user(exception_resume_pc(regs), &sc->sc_pc);
Kwok Cheung Yeung1239b472013-05-17 14:51:21 -07002823 regs->hflags &= ~MIPS_HFLAG_BMASK;
bellard106ec872006-06-27 21:08:10 +00002824
Richard Henderson084d0492013-02-10 10:30:44 -08002825 __put_user(0, &sc->sc_regs[0]);
2826 for (i = 1; i < 32; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002827 __put_user(regs->active_tc.gpr[i], &sc->sc_regs[i]);
Richard Henderson084d0492013-02-10 10:30:44 -08002828 }
bellard106ec872006-06-27 21:08:10 +00002829
Riku Voipio1d8b5122014-04-23 10:26:05 +03002830 __put_user(regs->active_tc.HI[0], &sc->sc_mdhi);
2831 __put_user(regs->active_tc.LO[0], &sc->sc_mdlo);
bellard106ec872006-06-27 21:08:10 +00002832
Richard Henderson084d0492013-02-10 10:30:44 -08002833 /* Rather than checking for dsp existence, always copy. The storage
2834 would just be garbage otherwise. */
Riku Voipio1d8b5122014-04-23 10:26:05 +03002835 __put_user(regs->active_tc.HI[1], &sc->sc_hi1);
2836 __put_user(regs->active_tc.HI[2], &sc->sc_hi2);
2837 __put_user(regs->active_tc.HI[3], &sc->sc_hi3);
2838 __put_user(regs->active_tc.LO[1], &sc->sc_lo1);
2839 __put_user(regs->active_tc.LO[2], &sc->sc_lo2);
2840 __put_user(regs->active_tc.LO[3], &sc->sc_lo3);
Richard Henderson084d0492013-02-10 10:30:44 -08002841 {
2842 uint32_t dsp = cpu_rddsp(0x3ff, regs);
Riku Voipio1d8b5122014-04-23 10:26:05 +03002843 __put_user(dsp, &sc->sc_dsp);
bellard106ec872006-06-27 21:08:10 +00002844 }
Richard Henderson084d0492013-02-10 10:30:44 -08002845
Riku Voipio1d8b5122014-04-23 10:26:05 +03002846 __put_user(1, &sc->sc_used_math);
Richard Henderson084d0492013-02-10 10:30:44 -08002847
2848 for (i = 0; i < 32; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002849 __put_user(regs->active_fpu.fpr[i].d, &sc->sc_fpregs[i]);
bellard106ec872006-06-27 21:08:10 +00002850 }
bellard106ec872006-06-27 21:08:10 +00002851}
2852
Riku Voipio016d2e12014-04-23 11:19:48 +03002853static inline void
Andreas Färber05390242012-02-25 03:37:53 +01002854restore_sigcontext(CPUMIPSState *regs, struct target_sigcontext *sc)
bellard106ec872006-06-27 21:08:10 +00002855{
Richard Henderson084d0492013-02-10 10:30:44 -08002856 int i;
bellard106ec872006-06-27 21:08:10 +00002857
Riku Voipio1d8b5122014-04-23 10:26:05 +03002858 __get_user(regs->CP0_EPC, &sc->sc_pc);
bellard106ec872006-06-27 21:08:10 +00002859
Riku Voipio1d8b5122014-04-23 10:26:05 +03002860 __get_user(regs->active_tc.HI[0], &sc->sc_mdhi);
2861 __get_user(regs->active_tc.LO[0], &sc->sc_mdlo);
bellard106ec872006-06-27 21:08:10 +00002862
Richard Henderson084d0492013-02-10 10:30:44 -08002863 for (i = 1; i < 32; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002864 __get_user(regs->active_tc.gpr[i], &sc->sc_regs[i]);
bellard106ec872006-06-27 21:08:10 +00002865 }
2866
Riku Voipio1d8b5122014-04-23 10:26:05 +03002867 __get_user(regs->active_tc.HI[1], &sc->sc_hi1);
2868 __get_user(regs->active_tc.HI[2], &sc->sc_hi2);
2869 __get_user(regs->active_tc.HI[3], &sc->sc_hi3);
2870 __get_user(regs->active_tc.LO[1], &sc->sc_lo1);
2871 __get_user(regs->active_tc.LO[2], &sc->sc_lo2);
2872 __get_user(regs->active_tc.LO[3], &sc->sc_lo3);
Richard Henderson084d0492013-02-10 10:30:44 -08002873 {
2874 uint32_t dsp;
Riku Voipio1d8b5122014-04-23 10:26:05 +03002875 __get_user(dsp, &sc->sc_dsp);
Richard Henderson084d0492013-02-10 10:30:44 -08002876 cpu_wrdsp(dsp, 0x3ff, regs);
2877 }
2878
2879 for (i = 0; i < 32; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03002880 __get_user(regs->active_fpu.fpr[i].d, &sc->sc_fpregs[i]);
Richard Henderson084d0492013-02-10 10:30:44 -08002881 }
bellard106ec872006-06-27 21:08:10 +00002882}
Richard Hendersonff970902013-02-10 10:30:42 -08002883
bellard106ec872006-06-27 21:08:10 +00002884/*
2885 * Determine which stack to use..
2886 */
bellard579a97f2007-11-11 14:26:47 +00002887static inline abi_ulong
Andreas Färber05390242012-02-25 03:37:53 +01002888get_sigframe(struct target_sigaction *ka, CPUMIPSState *regs, size_t frame_size)
bellard106ec872006-06-27 21:08:10 +00002889{
2890 unsigned long sp;
2891
2892 /* Default to using normal stack */
thsb5dc7732008-06-27 10:02:35 +00002893 sp = regs->active_tc.gpr[29];
bellard106ec872006-06-27 21:08:10 +00002894
2895 /*
Stefan Weil93148aa2012-02-26 18:46:12 +01002896 * FPU emulator may have its own trampoline active just
bellard106ec872006-06-27 21:08:10 +00002897 * above the user stack, 16-bytes before the next lowest
2898 * 16 byte boundary. Try to avoid trashing it.
2899 */
2900 sp -= 32;
2901
bellard106ec872006-06-27 21:08:10 +00002902 /* This is the X/Open sanctioned signal stack switching. */
pbrook624f7972008-05-31 16:11:38 +00002903 if ((ka->sa_flags & TARGET_SA_ONSTACK) && (sas_ss_flags (sp) == 0)) {
thsa04e1342007-09-27 13:57:58 +00002904 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
2905 }
bellard106ec872006-06-27 21:08:10 +00002906
bellard579a97f2007-11-11 14:26:47 +00002907 return (sp - frame_size) & ~7;
bellard106ec872006-06-27 21:08:10 +00002908}
2909
Kwok Cheung Yeungea3164a2013-05-17 14:51:20 -07002910static void mips_set_hflags_isa_mode_from_pc(CPUMIPSState *env)
2911{
2912 if (env->insn_flags & (ASE_MIPS16 | ASE_MICROMIPS)) {
2913 env->hflags &= ~MIPS_HFLAG_M16;
2914 env->hflags |= (env->active_tc.PC & 1) << MIPS_HFLAG_M16_SHIFT;
2915 env->active_tc.PC &= ~(target_ulong) 1;
2916 }
2917}
2918
Richard Hendersonff970902013-02-10 10:30:42 -08002919# if defined(TARGET_ABI_MIPSO32)
bellard579a97f2007-11-11 14:26:47 +00002920/* compare linux/arch/mips/kernel/signal.c:setup_frame() */
pbrook624f7972008-05-31 16:11:38 +00002921static void setup_frame(int sig, struct target_sigaction * ka,
Andreas Färber05390242012-02-25 03:37:53 +01002922 target_sigset_t *set, CPUMIPSState *regs)
bellard106ec872006-06-27 21:08:10 +00002923{
2924 struct sigframe *frame;
bellard579a97f2007-11-11 14:26:47 +00002925 abi_ulong frame_addr;
bellard106ec872006-06-27 21:08:10 +00002926 int i;
2927
bellard579a97f2007-11-11 14:26:47 +00002928 frame_addr = get_sigframe(ka, regs, sizeof(*frame));
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01002929 trace_user_setup_frame(regs, frame_addr);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002930 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
2931 goto give_sigsegv;
2932 }
bellard106ec872006-06-27 21:08:10 +00002933
2934 install_sigtramp(frame->sf_code, TARGET_NR_sigreturn);
2935
Riku Voipio41ecc722014-04-23 11:01:00 +03002936 setup_sigcontext(regs, &frame->sf_sc);
bellard106ec872006-06-27 21:08:10 +00002937
2938 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
Riku Voipio0188fad2014-04-23 13:34:15 +03002939 __put_user(set->sig[i], &frame->sf_mask.sig[i]);
bellard106ec872006-06-27 21:08:10 +00002940 }
2941
2942 /*
2943 * Arguments to signal handler:
2944 *
2945 * a0 = signal number
2946 * a1 = 0 (should be cause)
2947 * a2 = pointer to struct sigcontext
2948 *
2949 * $25 and PC point to the signal handler, $29 points to the
2950 * struct sigframe.
2951 */
thsb5dc7732008-06-27 10:02:35 +00002952 regs->active_tc.gpr[ 4] = sig;
2953 regs->active_tc.gpr[ 5] = 0;
2954 regs->active_tc.gpr[ 6] = frame_addr + offsetof(struct sigframe, sf_sc);
2955 regs->active_tc.gpr[29] = frame_addr;
2956 regs->active_tc.gpr[31] = frame_addr + offsetof(struct sigframe, sf_code);
bellard106ec872006-06-27 21:08:10 +00002957 /* The original kernel code sets CP0_EPC to the handler
2958 * since it returns to userland using eret
2959 * we cannot do this here, and we must set PC directly */
thsb5dc7732008-06-27 10:02:35 +00002960 regs->active_tc.PC = regs->active_tc.gpr[25] = ka->_sa_handler;
Kwok Cheung Yeungea3164a2013-05-17 14:51:20 -07002961 mips_set_hflags_isa_mode_from_pc(regs);
bellard579a97f2007-11-11 14:26:47 +00002962 unlock_user_struct(frame, frame_addr, 1);
bellard106ec872006-06-27 21:08:10 +00002963 return;
2964
2965give_sigsegv:
2966 force_sig(TARGET_SIGSEGV/*, current*/);
bellard106ec872006-06-27 21:08:10 +00002967}
2968
Andreas Färber05390242012-02-25 03:37:53 +01002969long do_sigreturn(CPUMIPSState *regs)
bellard106ec872006-06-27 21:08:10 +00002970{
ths388bb212007-05-13 13:58:00 +00002971 struct sigframe *frame;
bellard579a97f2007-11-11 14:26:47 +00002972 abi_ulong frame_addr;
ths388bb212007-05-13 13:58:00 +00002973 sigset_t blocked;
Anthony Liguoric227f092009-10-01 16:12:16 -05002974 target_sigset_t target_set;
ths388bb212007-05-13 13:58:00 +00002975 int i;
bellard106ec872006-06-27 21:08:10 +00002976
thsb5dc7732008-06-27 10:02:35 +00002977 frame_addr = regs->active_tc.gpr[29];
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01002978 trace_user_do_sigreturn(regs, frame_addr);
bellard579a97f2007-11-11 14:26:47 +00002979 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01002980 goto badframe;
bellard106ec872006-06-27 21:08:10 +00002981
ths388bb212007-05-13 13:58:00 +00002982 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
Riku Voipiof5f601a2014-04-23 13:00:17 +03002983 __get_user(target_set.sig[i], &frame->sf_mask.sig[i]);
ths388bb212007-05-13 13:58:00 +00002984 }
bellard106ec872006-06-27 21:08:10 +00002985
ths388bb212007-05-13 13:58:00 +00002986 target_to_host_sigset_internal(&blocked, &target_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00002987 do_sigprocmask(SIG_SETMASK, &blocked, NULL);
bellard106ec872006-06-27 21:08:10 +00002988
Riku Voipio016d2e12014-04-23 11:19:48 +03002989 restore_sigcontext(regs, &frame->sf_sc);
bellard106ec872006-06-27 21:08:10 +00002990
2991#if 0
ths388bb212007-05-13 13:58:00 +00002992 /*
2993 * Don't let your children do this ...
2994 */
2995 __asm__ __volatile__(
bellard106ec872006-06-27 21:08:10 +00002996 "move\t$29, %0\n\t"
2997 "j\tsyscall_exit"
2998 :/* no outputs */
2999 :"r" (&regs));
ths388bb212007-05-13 13:58:00 +00003000 /* Unreached */
bellard106ec872006-06-27 21:08:10 +00003001#endif
ths3b46e622007-09-17 08:09:54 +00003002
thsb5dc7732008-06-27 10:02:35 +00003003 regs->active_tc.PC = regs->CP0_EPC;
Kwok Cheung Yeungea3164a2013-05-17 14:51:20 -07003004 mips_set_hflags_isa_mode_from_pc(regs);
ths388bb212007-05-13 13:58:00 +00003005 /* I am not sure this is right, but it seems to work
bellard106ec872006-06-27 21:08:10 +00003006 * maybe a problem with nested signals ? */
3007 regs->CP0_EPC = 0;
pbrook0b1bcb02009-04-21 01:41:10 +00003008 return -TARGET_QEMU_ESIGRETURN;
bellard106ec872006-06-27 21:08:10 +00003009
3010badframe:
ths388bb212007-05-13 13:58:00 +00003011 force_sig(TARGET_SIGSEGV/*, current*/);
3012 return 0;
bellard106ec872006-06-27 21:08:10 +00003013}
Richard Hendersonff970902013-02-10 10:30:42 -08003014# endif /* O32 */
bellard106ec872006-06-27 21:08:10 +00003015
pbrook624f7972008-05-31 16:11:38 +00003016static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05003017 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01003018 target_sigset_t *set, CPUMIPSState *env)
bellard106ec872006-06-27 21:08:10 +00003019{
pbrook0b1bcb02009-04-21 01:41:10 +00003020 struct target_rt_sigframe *frame;
3021 abi_ulong frame_addr;
3022 int i;
3023
3024 frame_addr = get_sigframe(ka, env, sizeof(*frame));
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01003025 trace_user_setup_rt_frame(env, frame_addr);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003026 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
3027 goto give_sigsegv;
3028 }
pbrook0b1bcb02009-04-21 01:41:10 +00003029
3030 install_sigtramp(frame->rs_code, TARGET_NR_rt_sigreturn);
3031
Peter Maydellf6c7a052015-01-08 12:19:48 +00003032 tswap_siginfo(&frame->rs_info, info);
pbrook0b1bcb02009-04-21 01:41:10 +00003033
Aurelien Jarno60e99242010-03-29 02:12:51 +02003034 __put_user(0, &frame->rs_uc.tuc_flags);
3035 __put_user(0, &frame->rs_uc.tuc_link);
3036 __put_user(target_sigaltstack_used.ss_sp, &frame->rs_uc.tuc_stack.ss_sp);
3037 __put_user(target_sigaltstack_used.ss_size, &frame->rs_uc.tuc_stack.ss_size);
pbrook0b1bcb02009-04-21 01:41:10 +00003038 __put_user(sas_ss_flags(get_sp_from_cpustate(env)),
Aurelien Jarno60e99242010-03-29 02:12:51 +02003039 &frame->rs_uc.tuc_stack.ss_flags);
pbrook0b1bcb02009-04-21 01:41:10 +00003040
Aurelien Jarno60e99242010-03-29 02:12:51 +02003041 setup_sigcontext(env, &frame->rs_uc.tuc_mcontext);
pbrook0b1bcb02009-04-21 01:41:10 +00003042
3043 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
Aurelien Jarno60e99242010-03-29 02:12:51 +02003044 __put_user(set->sig[i], &frame->rs_uc.tuc_sigmask.sig[i]);
pbrook0b1bcb02009-04-21 01:41:10 +00003045 }
3046
3047 /*
3048 * Arguments to signal handler:
3049 *
3050 * a0 = signal number
Richard W.M. Jones02d2bd52012-07-05 03:32:44 +00003051 * a1 = pointer to siginfo_t
pbrook0b1bcb02009-04-21 01:41:10 +00003052 * a2 = pointer to struct ucontext
3053 *
3054 * $25 and PC point to the signal handler, $29 points to the
3055 * struct sigframe.
3056 */
3057 env->active_tc.gpr[ 4] = sig;
3058 env->active_tc.gpr[ 5] = frame_addr
3059 + offsetof(struct target_rt_sigframe, rs_info);
3060 env->active_tc.gpr[ 6] = frame_addr
3061 + offsetof(struct target_rt_sigframe, rs_uc);
3062 env->active_tc.gpr[29] = frame_addr;
3063 env->active_tc.gpr[31] = frame_addr
3064 + offsetof(struct target_rt_sigframe, rs_code);
3065 /* The original kernel code sets CP0_EPC to the handler
3066 * since it returns to userland using eret
3067 * we cannot do this here, and we must set PC directly */
3068 env->active_tc.PC = env->active_tc.gpr[25] = ka->_sa_handler;
Kwok Cheung Yeungea3164a2013-05-17 14:51:20 -07003069 mips_set_hflags_isa_mode_from_pc(env);
pbrook0b1bcb02009-04-21 01:41:10 +00003070 unlock_user_struct(frame, frame_addr, 1);
3071 return;
3072
3073give_sigsegv:
3074 unlock_user_struct(frame, frame_addr, 1);
3075 force_sig(TARGET_SIGSEGV/*, current*/);
bellard106ec872006-06-27 21:08:10 +00003076}
3077
Andreas Färber05390242012-02-25 03:37:53 +01003078long do_rt_sigreturn(CPUMIPSState *env)
bellard106ec872006-06-27 21:08:10 +00003079{
pbrook0b1bcb02009-04-21 01:41:10 +00003080 struct target_rt_sigframe *frame;
3081 abi_ulong frame_addr;
3082 sigset_t blocked;
3083
pbrook0b1bcb02009-04-21 01:41:10 +00003084 frame_addr = env->active_tc.gpr[29];
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01003085 trace_user_do_rt_sigreturn(env, frame_addr);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003086 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
3087 goto badframe;
3088 }
pbrook0b1bcb02009-04-21 01:41:10 +00003089
Aurelien Jarno60e99242010-03-29 02:12:51 +02003090 target_to_host_sigset(&blocked, &frame->rs_uc.tuc_sigmask);
Alex Barcelo1c275922014-03-14 14:36:55 +00003091 do_sigprocmask(SIG_SETMASK, &blocked, NULL);
pbrook0b1bcb02009-04-21 01:41:10 +00003092
Riku Voipio016d2e12014-04-23 11:19:48 +03003093 restore_sigcontext(env, &frame->rs_uc.tuc_mcontext);
pbrook0b1bcb02009-04-21 01:41:10 +00003094
3095 if (do_sigaltstack(frame_addr +
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003096 offsetof(struct target_rt_sigframe, rs_uc.tuc_stack),
3097 0, get_sp_from_cpustate(env)) == -EFAULT)
pbrook0b1bcb02009-04-21 01:41:10 +00003098 goto badframe;
3099
3100 env->active_tc.PC = env->CP0_EPC;
Kwok Cheung Yeungea3164a2013-05-17 14:51:20 -07003101 mips_set_hflags_isa_mode_from_pc(env);
pbrook0b1bcb02009-04-21 01:41:10 +00003102 /* I am not sure this is right, but it seems to work
3103 * maybe a problem with nested signals ? */
3104 env->CP0_EPC = 0;
3105 return -TARGET_QEMU_ESIGRETURN;
3106
3107badframe:
3108 force_sig(TARGET_SIGSEGV/*, current*/);
3109 return 0;
bellard106ec872006-06-27 21:08:10 +00003110}
bellard6d5e2162004-09-30 22:04:13 +00003111
thsc3b5bc82007-12-02 06:31:25 +00003112#elif defined(TARGET_SH4)
3113
3114/*
3115 * code and data structures from linux kernel:
3116 * include/asm-sh/sigcontext.h
3117 * arch/sh/kernel/signal.c
3118 */
3119
3120struct target_sigcontext {
3121 target_ulong oldmask;
3122
3123 /* CPU registers */
3124 target_ulong sc_gregs[16];
3125 target_ulong sc_pc;
3126 target_ulong sc_pr;
3127 target_ulong sc_sr;
3128 target_ulong sc_gbr;
3129 target_ulong sc_mach;
3130 target_ulong sc_macl;
3131
3132 /* FPU registers */
3133 target_ulong sc_fpregs[16];
3134 target_ulong sc_xfpregs[16];
3135 unsigned int sc_fpscr;
3136 unsigned int sc_fpul;
3137 unsigned int sc_ownedfp;
3138};
3139
3140struct target_sigframe
3141{
3142 struct target_sigcontext sc;
3143 target_ulong extramask[TARGET_NSIG_WORDS-1];
3144 uint16_t retcode[3];
3145};
3146
3147
3148struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02003149 target_ulong tuc_flags;
3150 struct target_ucontext *tuc_link;
3151 target_stack_t tuc_stack;
3152 struct target_sigcontext tuc_mcontext;
3153 target_sigset_t tuc_sigmask; /* mask last for extensibility */
thsc3b5bc82007-12-02 06:31:25 +00003154};
3155
3156struct target_rt_sigframe
3157{
3158 struct target_siginfo info;
3159 struct target_ucontext uc;
3160 uint16_t retcode[3];
3161};
3162
3163
3164#define MOVW(n) (0x9300|((n)-2)) /* Move mem word at PC+n to R3 */
3165#define TRAP_NOARG 0xc310 /* Syscall w/no args (NR in R3) SH3/4 */
3166
pbrook624f7972008-05-31 16:11:38 +00003167static abi_ulong get_sigframe(struct target_sigaction *ka,
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003168 unsigned long sp, size_t frame_size)
thsc3b5bc82007-12-02 06:31:25 +00003169{
pbrook624f7972008-05-31 16:11:38 +00003170 if ((ka->sa_flags & TARGET_SA_ONSTACK) && (sas_ss_flags(sp) == 0)) {
thsc3b5bc82007-12-02 06:31:25 +00003171 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
3172 }
3173
3174 return (sp - frame_size) & -8ul;
3175}
3176
Riku Voipio41ecc722014-04-23 11:01:00 +03003177static void setup_sigcontext(struct target_sigcontext *sc,
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003178 CPUSH4State *regs, unsigned long mask)
thsc3b5bc82007-12-02 06:31:25 +00003179{
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003180 int i;
thsc3b5bc82007-12-02 06:31:25 +00003181
Riku Voipio1d8b5122014-04-23 10:26:05 +03003182#define COPY(x) __put_user(regs->x, &sc->sc_##x)
thsc3b5bc82007-12-02 06:31:25 +00003183 COPY(gregs[0]); COPY(gregs[1]);
3184 COPY(gregs[2]); COPY(gregs[3]);
3185 COPY(gregs[4]); COPY(gregs[5]);
3186 COPY(gregs[6]); COPY(gregs[7]);
3187 COPY(gregs[8]); COPY(gregs[9]);
3188 COPY(gregs[10]); COPY(gregs[11]);
3189 COPY(gregs[12]); COPY(gregs[13]);
3190 COPY(gregs[14]); COPY(gregs[15]);
3191 COPY(gbr); COPY(mach);
3192 COPY(macl); COPY(pr);
3193 COPY(sr); COPY(pc);
3194#undef COPY
3195
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003196 for (i=0; i<16; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03003197 __put_user(regs->fregs[i], &sc->sc_fpregs[i]);
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003198 }
Riku Voipio1d8b5122014-04-23 10:26:05 +03003199 __put_user(regs->fpscr, &sc->sc_fpscr);
3200 __put_user(regs->fpul, &sc->sc_fpul);
thsc3b5bc82007-12-02 06:31:25 +00003201
3202 /* non-iBCS2 extensions.. */
Riku Voipio1d8b5122014-04-23 10:26:05 +03003203 __put_user(mask, &sc->oldmask);
thsc3b5bc82007-12-02 06:31:25 +00003204}
3205
Riku Voipio016d2e12014-04-23 11:19:48 +03003206static void restore_sigcontext(CPUSH4State *regs, struct target_sigcontext *sc,
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003207 target_ulong *r0_p)
thsc3b5bc82007-12-02 06:31:25 +00003208{
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003209 int i;
thsc3b5bc82007-12-02 06:31:25 +00003210
Riku Voipio1d8b5122014-04-23 10:26:05 +03003211#define COPY(x) __get_user(regs->x, &sc->sc_##x)
thsc3b5bc82007-12-02 06:31:25 +00003212 COPY(gregs[1]);
3213 COPY(gregs[2]); COPY(gregs[3]);
3214 COPY(gregs[4]); COPY(gregs[5]);
3215 COPY(gregs[6]); COPY(gregs[7]);
3216 COPY(gregs[8]); COPY(gregs[9]);
3217 COPY(gregs[10]); COPY(gregs[11]);
3218 COPY(gregs[12]); COPY(gregs[13]);
3219 COPY(gregs[14]); COPY(gregs[15]);
3220 COPY(gbr); COPY(mach);
3221 COPY(macl); COPY(pr);
3222 COPY(sr); COPY(pc);
3223#undef COPY
3224
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003225 for (i=0; i<16; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03003226 __get_user(regs->fregs[i], &sc->sc_fpregs[i]);
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003227 }
Riku Voipio1d8b5122014-04-23 10:26:05 +03003228 __get_user(regs->fpscr, &sc->sc_fpscr);
3229 __get_user(regs->fpul, &sc->sc_fpul);
thsc3b5bc82007-12-02 06:31:25 +00003230
3231 regs->tra = -1; /* disable syscall checks */
Riku Voipio1d8b5122014-04-23 10:26:05 +03003232 __get_user(*r0_p, &sc->sc_gregs[0]);
thsc3b5bc82007-12-02 06:31:25 +00003233}
3234
pbrook624f7972008-05-31 16:11:38 +00003235static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01003236 target_sigset_t *set, CPUSH4State *regs)
thsc3b5bc82007-12-02 06:31:25 +00003237{
3238 struct target_sigframe *frame;
3239 abi_ulong frame_addr;
3240 int i;
thsc3b5bc82007-12-02 06:31:25 +00003241
3242 frame_addr = get_sigframe(ka, regs->gregs[15], sizeof(*frame));
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01003243 trace_user_setup_frame(regs, frame_addr);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003244 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
3245 goto give_sigsegv;
3246 }
thsc3b5bc82007-12-02 06:31:25 +00003247
Riku Voipio41ecc722014-04-23 11:01:00 +03003248 setup_sigcontext(&frame->sc, regs, set->sig[0]);
thsc3b5bc82007-12-02 06:31:25 +00003249
3250 for (i = 0; i < TARGET_NSIG_WORDS - 1; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03003251 __put_user(set->sig[i + 1], &frame->extramask[i]);
thsc3b5bc82007-12-02 06:31:25 +00003252 }
3253
3254 /* Set up to return from userspace. If provided, use a stub
3255 already in userspace. */
pbrook624f7972008-05-31 16:11:38 +00003256 if (ka->sa_flags & TARGET_SA_RESTORER) {
3257 regs->pr = (unsigned long) ka->sa_restorer;
thsc3b5bc82007-12-02 06:31:25 +00003258 } else {
3259 /* Generate return code (system call to sigreturn) */
Laurent Vivier2a0fa682015-11-23 11:38:26 +01003260 abi_ulong retcode_addr = frame_addr +
3261 offsetof(struct target_sigframe, retcode);
Riku Voipio1d8b5122014-04-23 10:26:05 +03003262 __put_user(MOVW(2), &frame->retcode[0]);
3263 __put_user(TRAP_NOARG, &frame->retcode[1]);
3264 __put_user((TARGET_NR_sigreturn), &frame->retcode[2]);
Laurent Vivier2a0fa682015-11-23 11:38:26 +01003265 regs->pr = (unsigned long) retcode_addr;
thsc3b5bc82007-12-02 06:31:25 +00003266 }
3267
thsc3b5bc82007-12-02 06:31:25 +00003268 /* Set up registers for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003269 regs->gregs[15] = frame_addr;
Peter Maydellb6e2c932015-01-08 12:19:43 +00003270 regs->gregs[4] = sig; /* Arg for signal handler */
thsc3b5bc82007-12-02 06:31:25 +00003271 regs->gregs[5] = 0;
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003272 regs->gregs[6] = frame_addr += offsetof(typeof(*frame), sc);
pbrook624f7972008-05-31 16:11:38 +00003273 regs->pc = (unsigned long) ka->_sa_handler;
thsc3b5bc82007-12-02 06:31:25 +00003274
3275 unlock_user_struct(frame, frame_addr, 1);
3276 return;
3277
3278give_sigsegv:
3279 unlock_user_struct(frame, frame_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02003280 force_sig(TARGET_SIGSEGV);
thsc3b5bc82007-12-02 06:31:25 +00003281}
3282
pbrook624f7972008-05-31 16:11:38 +00003283static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05003284 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01003285 target_sigset_t *set, CPUSH4State *regs)
thsc3b5bc82007-12-02 06:31:25 +00003286{
3287 struct target_rt_sigframe *frame;
3288 abi_ulong frame_addr;
3289 int i;
thsc3b5bc82007-12-02 06:31:25 +00003290
3291 frame_addr = get_sigframe(ka, regs->gregs[15], sizeof(*frame));
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01003292 trace_user_setup_rt_frame(regs, frame_addr);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003293 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
3294 goto give_sigsegv;
3295 }
thsc3b5bc82007-12-02 06:31:25 +00003296
Peter Maydellf6c7a052015-01-08 12:19:48 +00003297 tswap_siginfo(&frame->info, info);
thsc3b5bc82007-12-02 06:31:25 +00003298
3299 /* Create the ucontext. */
Riku Voipio1d8b5122014-04-23 10:26:05 +03003300 __put_user(0, &frame->uc.tuc_flags);
3301 __put_user(0, (unsigned long *)&frame->uc.tuc_link);
3302 __put_user((unsigned long)target_sigaltstack_used.ss_sp,
3303 &frame->uc.tuc_stack.ss_sp);
3304 __put_user(sas_ss_flags(regs->gregs[15]),
3305 &frame->uc.tuc_stack.ss_flags);
3306 __put_user(target_sigaltstack_used.ss_size,
3307 &frame->uc.tuc_stack.ss_size);
3308 setup_sigcontext(&frame->uc.tuc_mcontext,
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003309 regs, set->sig[0]);
thsc3b5bc82007-12-02 06:31:25 +00003310 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03003311 __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
thsc3b5bc82007-12-02 06:31:25 +00003312 }
3313
3314 /* Set up to return from userspace. If provided, use a stub
3315 already in userspace. */
pbrook624f7972008-05-31 16:11:38 +00003316 if (ka->sa_flags & TARGET_SA_RESTORER) {
3317 regs->pr = (unsigned long) ka->sa_restorer;
thsc3b5bc82007-12-02 06:31:25 +00003318 } else {
3319 /* Generate return code (system call to sigreturn) */
Laurent Vivier2a0fa682015-11-23 11:38:26 +01003320 abi_ulong retcode_addr = frame_addr +
3321 offsetof(struct target_rt_sigframe, retcode);
Riku Voipio1d8b5122014-04-23 10:26:05 +03003322 __put_user(MOVW(2), &frame->retcode[0]);
3323 __put_user(TRAP_NOARG, &frame->retcode[1]);
3324 __put_user((TARGET_NR_rt_sigreturn), &frame->retcode[2]);
Laurent Vivier2a0fa682015-11-23 11:38:26 +01003325 regs->pr = (unsigned long) retcode_addr;
thsc3b5bc82007-12-02 06:31:25 +00003326 }
3327
thsc3b5bc82007-12-02 06:31:25 +00003328 /* Set up registers for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003329 regs->gregs[15] = frame_addr;
Peter Maydellb6e2c932015-01-08 12:19:43 +00003330 regs->gregs[4] = sig; /* Arg for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003331 regs->gregs[5] = frame_addr + offsetof(typeof(*frame), info);
3332 regs->gregs[6] = frame_addr + offsetof(typeof(*frame), uc);
pbrook624f7972008-05-31 16:11:38 +00003333 regs->pc = (unsigned long) ka->_sa_handler;
thsc3b5bc82007-12-02 06:31:25 +00003334
3335 unlock_user_struct(frame, frame_addr, 1);
3336 return;
3337
3338give_sigsegv:
3339 unlock_user_struct(frame, frame_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02003340 force_sig(TARGET_SIGSEGV);
thsc3b5bc82007-12-02 06:31:25 +00003341}
3342
Andreas Färber05390242012-02-25 03:37:53 +01003343long do_sigreturn(CPUSH4State *regs)
thsc3b5bc82007-12-02 06:31:25 +00003344{
3345 struct target_sigframe *frame;
3346 abi_ulong frame_addr;
3347 sigset_t blocked;
Anthony Liguoric227f092009-10-01 16:12:16 -05003348 target_sigset_t target_set;
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003349 target_ulong r0;
thsc3b5bc82007-12-02 06:31:25 +00003350 int i;
3351 int err = 0;
3352
thsc3b5bc82007-12-02 06:31:25 +00003353 frame_addr = regs->gregs[15];
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01003354 trace_user_do_sigreturn(regs, frame_addr);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003355 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
3356 goto badframe;
3357 }
thsc3b5bc82007-12-02 06:31:25 +00003358
Riku Voipio1d8b5122014-04-23 10:26:05 +03003359 __get_user(target_set.sig[0], &frame->sc.oldmask);
thsc3b5bc82007-12-02 06:31:25 +00003360 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03003361 __get_user(target_set.sig[i], &frame->extramask[i - 1]);
thsc3b5bc82007-12-02 06:31:25 +00003362 }
3363
3364 if (err)
3365 goto badframe;
3366
3367 target_to_host_sigset_internal(&blocked, &target_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00003368 do_sigprocmask(SIG_SETMASK, &blocked, NULL);
thsc3b5bc82007-12-02 06:31:25 +00003369
Riku Voipio016d2e12014-04-23 11:19:48 +03003370 restore_sigcontext(regs, &frame->sc, &r0);
thsc3b5bc82007-12-02 06:31:25 +00003371
3372 unlock_user_struct(frame, frame_addr, 0);
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003373 return r0;
thsc3b5bc82007-12-02 06:31:25 +00003374
3375badframe:
3376 unlock_user_struct(frame, frame_addr, 0);
3377 force_sig(TARGET_SIGSEGV);
3378 return 0;
3379}
3380
Andreas Färber05390242012-02-25 03:37:53 +01003381long do_rt_sigreturn(CPUSH4State *regs)
thsc3b5bc82007-12-02 06:31:25 +00003382{
3383 struct target_rt_sigframe *frame;
3384 abi_ulong frame_addr;
3385 sigset_t blocked;
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003386 target_ulong r0;
thsc3b5bc82007-12-02 06:31:25 +00003387
thsc3b5bc82007-12-02 06:31:25 +00003388 frame_addr = regs->gregs[15];
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01003389 trace_user_do_rt_sigreturn(regs, frame_addr);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003390 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
3391 goto badframe;
3392 }
thsc3b5bc82007-12-02 06:31:25 +00003393
Aurelien Jarno60e99242010-03-29 02:12:51 +02003394 target_to_host_sigset(&blocked, &frame->uc.tuc_sigmask);
Alex Barcelo1c275922014-03-14 14:36:55 +00003395 do_sigprocmask(SIG_SETMASK, &blocked, NULL);
thsc3b5bc82007-12-02 06:31:25 +00003396
Riku Voipio016d2e12014-04-23 11:19:48 +03003397 restore_sigcontext(regs, &frame->uc.tuc_mcontext, &r0);
thsc3b5bc82007-12-02 06:31:25 +00003398
3399 if (do_sigaltstack(frame_addr +
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003400 offsetof(struct target_rt_sigframe, uc.tuc_stack),
3401 0, get_sp_from_cpustate(regs)) == -EFAULT) {
thsc3b5bc82007-12-02 06:31:25 +00003402 goto badframe;
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003403 }
thsc3b5bc82007-12-02 06:31:25 +00003404
3405 unlock_user_struct(frame, frame_addr, 0);
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003406 return r0;
thsc3b5bc82007-12-02 06:31:25 +00003407
3408badframe:
3409 unlock_user_struct(frame, frame_addr, 0);
3410 force_sig(TARGET_SIGSEGV);
3411 return 0;
3412}
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003413#elif defined(TARGET_MICROBLAZE)
3414
3415struct target_sigcontext {
3416 struct target_pt_regs regs; /* needs to be first */
3417 uint32_t oldmask;
3418};
3419
Edgar E. Iglesiasb2178702010-07-23 09:30:37 +02003420struct target_stack_t {
3421 abi_ulong ss_sp;
3422 int ss_flags;
3423 unsigned int ss_size;
3424};
3425
3426struct target_ucontext {
Richard Hendersonf711df62010-11-22 14:57:52 -08003427 abi_ulong tuc_flags;
3428 abi_ulong tuc_link;
3429 struct target_stack_t tuc_stack;
3430 struct target_sigcontext tuc_mcontext;
3431 uint32_t tuc_extramask[TARGET_NSIG_WORDS - 1];
Edgar E. Iglesiasb2178702010-07-23 09:30:37 +02003432};
3433
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003434/* Signal frames. */
3435struct target_signal_frame {
Edgar E. Iglesiasb2178702010-07-23 09:30:37 +02003436 struct target_ucontext uc;
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003437 uint32_t extramask[TARGET_NSIG_WORDS - 1];
3438 uint32_t tramp[2];
3439};
3440
3441struct rt_signal_frame {
Richard W.M. Jones02d2bd52012-07-05 03:32:44 +00003442 siginfo_t info;
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003443 struct ucontext uc;
3444 uint32_t tramp[2];
3445};
3446
Andreas Färber05390242012-02-25 03:37:53 +01003447static void setup_sigcontext(struct target_sigcontext *sc, CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003448{
3449 __put_user(env->regs[0], &sc->regs.r0);
3450 __put_user(env->regs[1], &sc->regs.r1);
3451 __put_user(env->regs[2], &sc->regs.r2);
3452 __put_user(env->regs[3], &sc->regs.r3);
3453 __put_user(env->regs[4], &sc->regs.r4);
3454 __put_user(env->regs[5], &sc->regs.r5);
3455 __put_user(env->regs[6], &sc->regs.r6);
3456 __put_user(env->regs[7], &sc->regs.r7);
3457 __put_user(env->regs[8], &sc->regs.r8);
3458 __put_user(env->regs[9], &sc->regs.r9);
3459 __put_user(env->regs[10], &sc->regs.r10);
3460 __put_user(env->regs[11], &sc->regs.r11);
3461 __put_user(env->regs[12], &sc->regs.r12);
3462 __put_user(env->regs[13], &sc->regs.r13);
3463 __put_user(env->regs[14], &sc->regs.r14);
3464 __put_user(env->regs[15], &sc->regs.r15);
3465 __put_user(env->regs[16], &sc->regs.r16);
3466 __put_user(env->regs[17], &sc->regs.r17);
3467 __put_user(env->regs[18], &sc->regs.r18);
3468 __put_user(env->regs[19], &sc->regs.r19);
3469 __put_user(env->regs[20], &sc->regs.r20);
3470 __put_user(env->regs[21], &sc->regs.r21);
3471 __put_user(env->regs[22], &sc->regs.r22);
3472 __put_user(env->regs[23], &sc->regs.r23);
3473 __put_user(env->regs[24], &sc->regs.r24);
3474 __put_user(env->regs[25], &sc->regs.r25);
3475 __put_user(env->regs[26], &sc->regs.r26);
3476 __put_user(env->regs[27], &sc->regs.r27);
3477 __put_user(env->regs[28], &sc->regs.r28);
3478 __put_user(env->regs[29], &sc->regs.r29);
3479 __put_user(env->regs[30], &sc->regs.r30);
3480 __put_user(env->regs[31], &sc->regs.r31);
3481 __put_user(env->sregs[SR_PC], &sc->regs.pc);
3482}
3483
Andreas Färber05390242012-02-25 03:37:53 +01003484static void restore_sigcontext(struct target_sigcontext *sc, CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003485{
3486 __get_user(env->regs[0], &sc->regs.r0);
3487 __get_user(env->regs[1], &sc->regs.r1);
3488 __get_user(env->regs[2], &sc->regs.r2);
3489 __get_user(env->regs[3], &sc->regs.r3);
3490 __get_user(env->regs[4], &sc->regs.r4);
3491 __get_user(env->regs[5], &sc->regs.r5);
3492 __get_user(env->regs[6], &sc->regs.r6);
3493 __get_user(env->regs[7], &sc->regs.r7);
3494 __get_user(env->regs[8], &sc->regs.r8);
3495 __get_user(env->regs[9], &sc->regs.r9);
3496 __get_user(env->regs[10], &sc->regs.r10);
3497 __get_user(env->regs[11], &sc->regs.r11);
3498 __get_user(env->regs[12], &sc->regs.r12);
3499 __get_user(env->regs[13], &sc->regs.r13);
3500 __get_user(env->regs[14], &sc->regs.r14);
3501 __get_user(env->regs[15], &sc->regs.r15);
3502 __get_user(env->regs[16], &sc->regs.r16);
3503 __get_user(env->regs[17], &sc->regs.r17);
3504 __get_user(env->regs[18], &sc->regs.r18);
3505 __get_user(env->regs[19], &sc->regs.r19);
3506 __get_user(env->regs[20], &sc->regs.r20);
3507 __get_user(env->regs[21], &sc->regs.r21);
3508 __get_user(env->regs[22], &sc->regs.r22);
3509 __get_user(env->regs[23], &sc->regs.r23);
3510 __get_user(env->regs[24], &sc->regs.r24);
3511 __get_user(env->regs[25], &sc->regs.r25);
3512 __get_user(env->regs[26], &sc->regs.r26);
3513 __get_user(env->regs[27], &sc->regs.r27);
3514 __get_user(env->regs[28], &sc->regs.r28);
3515 __get_user(env->regs[29], &sc->regs.r29);
3516 __get_user(env->regs[30], &sc->regs.r30);
3517 __get_user(env->regs[31], &sc->regs.r31);
3518 __get_user(env->sregs[SR_PC], &sc->regs.pc);
3519}
3520
3521static abi_ulong get_sigframe(struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01003522 CPUMBState *env, int frame_size)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003523{
3524 abi_ulong sp = env->regs[1];
3525
Riku Voipiob545f632014-07-15 17:01:55 +03003526 if ((ka->sa_flags & TARGET_SA_ONSTACK) != 0 && !on_sig_stack(sp)) {
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003527 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
Riku Voipiob545f632014-07-15 17:01:55 +03003528 }
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003529
3530 return ((sp - frame_size) & -8UL);
3531}
3532
3533static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01003534 target_sigset_t *set, CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003535{
3536 struct target_signal_frame *frame;
3537 abi_ulong frame_addr;
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003538 int i;
3539
3540 frame_addr = get_sigframe(ka, env, sizeof *frame);
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01003541 trace_user_setup_frame(env, frame_addr);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003542 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
3543 goto badframe;
3544
3545 /* Save the mask. */
Riku Voipio1d8b5122014-04-23 10:26:05 +03003546 __put_user(set->sig[0], &frame->uc.tuc_mcontext.oldmask);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003547
3548 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
Riku Voipio0188fad2014-04-23 13:34:15 +03003549 __put_user(set->sig[i], &frame->extramask[i - 1]);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003550 }
3551
Richard Hendersonf711df62010-11-22 14:57:52 -08003552 setup_sigcontext(&frame->uc.tuc_mcontext, env);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003553
3554 /* Set up to return from userspace. If provided, use a stub
3555 already in userspace. */
3556 /* minus 8 is offset to cater for "rtsd r15,8" offset */
3557 if (ka->sa_flags & TARGET_SA_RESTORER) {
3558 env->regs[15] = ((unsigned long)ka->sa_restorer)-8;
3559 } else {
3560 uint32_t t;
3561 /* Note, these encodings are _big endian_! */
3562 /* addi r12, r0, __NR_sigreturn */
3563 t = 0x31800000UL | TARGET_NR_sigreturn;
Riku Voipio1d8b5122014-04-23 10:26:05 +03003564 __put_user(t, frame->tramp + 0);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003565 /* brki r14, 0x8 */
3566 t = 0xb9cc0008UL;
Riku Voipio1d8b5122014-04-23 10:26:05 +03003567 __put_user(t, frame->tramp + 1);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003568
3569 /* Return from sighandler will jump to the tramp.
3570 Negative 8 offset because return is rtsd r15, 8 */
3571 env->regs[15] = ((unsigned long)frame->tramp) - 8;
3572 }
3573
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003574 /* Set up registers for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003575 env->regs[1] = frame_addr;
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003576 /* Signal handler args: */
3577 env->regs[5] = sig; /* Arg 0: signum */
Edgar E. Iglesias187b4e02010-07-15 15:32:51 +02003578 env->regs[6] = 0;
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02003579 /* arg 1: sigcontext */
3580 env->regs[7] = frame_addr += offsetof(typeof(*frame), uc);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003581
3582 /* Offset of 4 to handle microblaze rtid r14, 0 */
3583 env->sregs[SR_PC] = (unsigned long)ka->_sa_handler;
3584
3585 unlock_user_struct(frame, frame_addr, 1);
3586 return;
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003587badframe:
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003588 force_sig(TARGET_SIGSEGV);
3589}
3590
3591static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05003592 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01003593 target_sigset_t *set, CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003594{
3595 fprintf(stderr, "Microblaze setup_rt_frame: not implemented\n");
3596}
3597
Andreas Färber05390242012-02-25 03:37:53 +01003598long do_sigreturn(CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003599{
3600 struct target_signal_frame *frame;
3601 abi_ulong frame_addr;
Anthony Liguoric227f092009-10-01 16:12:16 -05003602 target_sigset_t target_set;
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003603 sigset_t set;
3604 int i;
3605
3606 frame_addr = env->regs[R_SP];
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01003607 trace_user_do_sigreturn(env, frame_addr);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003608 /* Make sure the guest isn't playing games. */
3609 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 1))
3610 goto badframe;
3611
3612 /* Restore blocked signals */
Riku Voipiof5f601a2014-04-23 13:00:17 +03003613 __get_user(target_set.sig[0], &frame->uc.tuc_mcontext.oldmask);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003614 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003615 __get_user(target_set.sig[i], &frame->extramask[i - 1]);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003616 }
3617 target_to_host_sigset_internal(&set, &target_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00003618 do_sigprocmask(SIG_SETMASK, &set, NULL);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003619
Richard Hendersonf711df62010-11-22 14:57:52 -08003620 restore_sigcontext(&frame->uc.tuc_mcontext, env);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003621 /* We got here through a sigreturn syscall, our path back is via an
3622 rtb insn so setup r14 for that. */
3623 env->regs[14] = env->sregs[SR_PC];
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003624
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003625 unlock_user_struct(frame, frame_addr, 0);
3626 return env->regs[10];
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003627badframe:
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003628 force_sig(TARGET_SIGSEGV);
3629}
3630
Andreas Färber05390242012-02-25 03:37:53 +01003631long do_rt_sigreturn(CPUMBState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003632{
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01003633 trace_user_do_rt_sigreturn(env, 0);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003634 fprintf(stderr, "Microblaze do_rt_sigreturn: not implemented\n");
3635 return -TARGET_ENOSYS;
3636}
3637
edgar_iglb6d3abd2008-02-28 11:29:27 +00003638#elif defined(TARGET_CRIS)
3639
3640struct target_sigcontext {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003641 struct target_pt_regs regs; /* needs to be first */
3642 uint32_t oldmask;
3643 uint32_t usp; /* usp before stacking this gunk on it */
edgar_iglb6d3abd2008-02-28 11:29:27 +00003644};
3645
3646/* Signal frames. */
3647struct target_signal_frame {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003648 struct target_sigcontext sc;
3649 uint32_t extramask[TARGET_NSIG_WORDS - 1];
3650 uint16_t retcode[4]; /* Trampoline code. */
edgar_iglb6d3abd2008-02-28 11:29:27 +00003651};
3652
3653struct rt_signal_frame {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003654 siginfo_t *pinfo;
3655 void *puc;
3656 siginfo_t info;
3657 struct ucontext uc;
3658 uint16_t retcode[4]; /* Trampoline code. */
edgar_iglb6d3abd2008-02-28 11:29:27 +00003659};
3660
Andreas Färber05390242012-02-25 03:37:53 +01003661static void setup_sigcontext(struct target_sigcontext *sc, CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003662{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003663 __put_user(env->regs[0], &sc->regs.r0);
3664 __put_user(env->regs[1], &sc->regs.r1);
3665 __put_user(env->regs[2], &sc->regs.r2);
3666 __put_user(env->regs[3], &sc->regs.r3);
3667 __put_user(env->regs[4], &sc->regs.r4);
3668 __put_user(env->regs[5], &sc->regs.r5);
3669 __put_user(env->regs[6], &sc->regs.r6);
3670 __put_user(env->regs[7], &sc->regs.r7);
3671 __put_user(env->regs[8], &sc->regs.r8);
3672 __put_user(env->regs[9], &sc->regs.r9);
3673 __put_user(env->regs[10], &sc->regs.r10);
3674 __put_user(env->regs[11], &sc->regs.r11);
3675 __put_user(env->regs[12], &sc->regs.r12);
3676 __put_user(env->regs[13], &sc->regs.r13);
3677 __put_user(env->regs[14], &sc->usp);
3678 __put_user(env->regs[15], &sc->regs.acr);
3679 __put_user(env->pregs[PR_MOF], &sc->regs.mof);
3680 __put_user(env->pregs[PR_SRP], &sc->regs.srp);
3681 __put_user(env->pc, &sc->regs.erp);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003682}
edgar_igl9664d922008-03-03 22:23:53 +00003683
Andreas Färber05390242012-02-25 03:37:53 +01003684static void restore_sigcontext(struct target_sigcontext *sc, CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003685{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003686 __get_user(env->regs[0], &sc->regs.r0);
3687 __get_user(env->regs[1], &sc->regs.r1);
3688 __get_user(env->regs[2], &sc->regs.r2);
3689 __get_user(env->regs[3], &sc->regs.r3);
3690 __get_user(env->regs[4], &sc->regs.r4);
3691 __get_user(env->regs[5], &sc->regs.r5);
3692 __get_user(env->regs[6], &sc->regs.r6);
3693 __get_user(env->regs[7], &sc->regs.r7);
3694 __get_user(env->regs[8], &sc->regs.r8);
3695 __get_user(env->regs[9], &sc->regs.r9);
3696 __get_user(env->regs[10], &sc->regs.r10);
3697 __get_user(env->regs[11], &sc->regs.r11);
3698 __get_user(env->regs[12], &sc->regs.r12);
3699 __get_user(env->regs[13], &sc->regs.r13);
3700 __get_user(env->regs[14], &sc->usp);
3701 __get_user(env->regs[15], &sc->regs.acr);
3702 __get_user(env->pregs[PR_MOF], &sc->regs.mof);
3703 __get_user(env->pregs[PR_SRP], &sc->regs.srp);
3704 __get_user(env->pc, &sc->regs.erp);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003705}
3706
Andreas Färber05390242012-02-25 03:37:53 +01003707static abi_ulong get_sigframe(CPUCRISState *env, int framesize)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003708{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003709 abi_ulong sp;
3710 /* Align the stack downwards to 4. */
3711 sp = (env->regs[R_SP] & ~3);
3712 return sp - framesize;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003713}
3714
pbrook624f7972008-05-31 16:11:38 +00003715static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01003716 target_sigset_t *set, CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003717{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003718 struct target_signal_frame *frame;
3719 abi_ulong frame_addr;
3720 int i;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003721
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003722 frame_addr = get_sigframe(env, sizeof *frame);
3723 trace_user_setup_frame(env, frame_addr);
3724 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
3725 goto badframe;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003726
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003727 /*
3728 * The CRIS signal return trampoline. A real linux/CRIS kernel doesn't
3729 * use this trampoline anymore but it sets it up for GDB.
3730 * In QEMU, using the trampoline simplifies things a bit so we use it.
3731 *
3732 * This is movu.w __NR_sigreturn, r9; break 13;
3733 */
Riku Voipio1d8b5122014-04-23 10:26:05 +03003734 __put_user(0x9c5f, frame->retcode+0);
3735 __put_user(TARGET_NR_sigreturn,
3736 frame->retcode + 1);
3737 __put_user(0xe93d, frame->retcode + 2);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003738
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003739 /* Save the mask. */
Riku Voipio1d8b5122014-04-23 10:26:05 +03003740 __put_user(set->sig[0], &frame->sc.oldmask);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003741
Riku Voipio0188fad2014-04-23 13:34:15 +03003742 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
3743 __put_user(set->sig[i], &frame->extramask[i - 1]);
3744 }
edgar_iglb6d3abd2008-02-28 11:29:27 +00003745
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003746 setup_sigcontext(&frame->sc, env);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003747
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003748 /* Move the stack and setup the arguments for the handler. */
3749 env->regs[R_SP] = frame_addr;
3750 env->regs[10] = sig;
3751 env->pc = (unsigned long) ka->_sa_handler;
3752 /* Link SRP so the guest returns through the trampoline. */
3753 env->pregs[PR_SRP] = frame_addr + offsetof(typeof(*frame), retcode);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003754
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003755 unlock_user_struct(frame, frame_addr, 1);
3756 return;
3757badframe:
3758 force_sig(TARGET_SIGSEGV);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003759}
3760
pbrook624f7972008-05-31 16:11:38 +00003761static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05003762 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01003763 target_sigset_t *set, CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003764{
3765 fprintf(stderr, "CRIS setup_rt_frame: not implemented\n");
3766}
3767
Andreas Färber05390242012-02-25 03:37:53 +01003768long do_sigreturn(CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003769{
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003770 struct target_signal_frame *frame;
3771 abi_ulong frame_addr;
3772 target_sigset_t target_set;
3773 sigset_t set;
3774 int i;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003775
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003776 frame_addr = env->regs[R_SP];
3777 trace_user_do_sigreturn(env, frame_addr);
3778 /* Make sure the guest isn't playing games. */
3779 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 1)) {
3780 goto badframe;
3781 }
edgar_iglb6d3abd2008-02-28 11:29:27 +00003782
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003783 /* Restore blocked signals */
Riku Voipiof5f601a2014-04-23 13:00:17 +03003784 __get_user(target_set.sig[0], &frame->sc.oldmask);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003785 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
Riku Voipiof5f601a2014-04-23 13:00:17 +03003786 __get_user(target_set.sig[i], &frame->extramask[i - 1]);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003787 }
3788 target_to_host_sigset_internal(&set, &target_set);
3789 do_sigprocmask(SIG_SETMASK, &set, NULL);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003790
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003791 restore_sigcontext(&frame->sc, env);
3792 unlock_user_struct(frame, frame_addr, 0);
3793 return env->regs[10];
3794badframe:
3795 force_sig(TARGET_SIGSEGV);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003796}
3797
Andreas Färber05390242012-02-25 03:37:53 +01003798long do_rt_sigreturn(CPUCRISState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003799{
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01003800 trace_user_do_rt_sigreturn(env, 0);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003801 fprintf(stderr, "CRIS do_rt_sigreturn: not implemented\n");
3802 return -TARGET_ENOSYS;
3803}
thsc3b5bc82007-12-02 06:31:25 +00003804
Jia Liud9627832012-07-20 15:50:52 +08003805#elif defined(TARGET_OPENRISC)
3806
3807struct target_sigcontext {
3808 struct target_pt_regs regs;
3809 abi_ulong oldmask;
3810 abi_ulong usp;
3811};
3812
3813struct target_ucontext {
3814 abi_ulong tuc_flags;
3815 abi_ulong tuc_link;
3816 target_stack_t tuc_stack;
3817 struct target_sigcontext tuc_mcontext;
3818 target_sigset_t tuc_sigmask; /* mask last for extensibility */
3819};
3820
3821struct target_rt_sigframe {
3822 abi_ulong pinfo;
3823 uint64_t puc;
3824 struct target_siginfo info;
3825 struct target_sigcontext sc;
3826 struct target_ucontext uc;
3827 unsigned char retcode[16]; /* trampoline code */
3828};
3829
3830/* This is the asm-generic/ucontext.h version */
3831#if 0
3832static int restore_sigcontext(CPUOpenRISCState *regs,
3833 struct target_sigcontext *sc)
3834{
3835 unsigned int err = 0;
3836 unsigned long old_usp;
3837
3838 /* Alwys make any pending restarted system call return -EINTR */
3839 current_thread_info()->restart_block.fn = do_no_restart_syscall;
3840
3841 /* restore the regs from &sc->regs (same as sc, since regs is first)
3842 * (sc is already checked for VERIFY_READ since the sigframe was
3843 * checked in sys_sigreturn previously)
3844 */
3845
3846 if (copy_from_user(regs, &sc, sizeof(struct target_pt_regs))) {
3847 goto badframe;
3848 }
3849
3850 /* make sure the U-flag is set so user-mode cannot fool us */
3851
3852 regs->sr &= ~SR_SM;
3853
3854 /* restore the old USP as it was before we stacked the sc etc.
3855 * (we cannot just pop the sigcontext since we aligned the sp and
3856 * stuff after pushing it)
3857 */
3858
Riku Voipio1d8b5122014-04-23 10:26:05 +03003859 __get_user(old_usp, &sc->usp);
Jia Liud9627832012-07-20 15:50:52 +08003860 phx_signal("old_usp 0x%lx", old_usp);
3861
3862 __PHX__ REALLY /* ??? */
3863 wrusp(old_usp);
3864 regs->gpr[1] = old_usp;
3865
3866 /* TODO: the other ports use regs->orig_XX to disable syscall checks
3867 * after this completes, but we don't use that mechanism. maybe we can
3868 * use it now ?
3869 */
3870
3871 return err;
3872
3873badframe:
3874 return 1;
3875}
3876#endif
3877
3878/* Set up a signal frame. */
3879
Riku Voipio41ecc722014-04-23 11:01:00 +03003880static void setup_sigcontext(struct target_sigcontext *sc,
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01003881 CPUOpenRISCState *regs,
3882 unsigned long mask)
Jia Liud9627832012-07-20 15:50:52 +08003883{
Jia Liud9627832012-07-20 15:50:52 +08003884 unsigned long usp = regs->gpr[1];
3885
3886 /* copy the regs. they are first in sc so we can use sc directly */
3887
Riku Voipio1d8b5122014-04-23 10:26:05 +03003888 /*copy_to_user(&sc, regs, sizeof(struct target_pt_regs));*/
Jia Liud9627832012-07-20 15:50:52 +08003889
3890 /* Set the frametype to CRIS_FRAME_NORMAL for the execution of
3891 the signal handler. The frametype will be restored to its previous
3892 value in restore_sigcontext. */
3893 /*regs->frametype = CRIS_FRAME_NORMAL;*/
3894
3895 /* then some other stuff */
Riku Voipio1d8b5122014-04-23 10:26:05 +03003896 __put_user(mask, &sc->oldmask);
Riku Voipio41ecc722014-04-23 11:01:00 +03003897 __put_user(usp, &sc->usp);
Jia Liud9627832012-07-20 15:50:52 +08003898}
3899
3900static inline unsigned long align_sigframe(unsigned long sp)
3901{
3902 unsigned long i;
3903 i = sp & ~3UL;
3904 return i;
3905}
3906
3907static inline abi_ulong get_sigframe(struct target_sigaction *ka,
3908 CPUOpenRISCState *regs,
3909 size_t frame_size)
3910{
3911 unsigned long sp = regs->gpr[1];
3912 int onsigstack = on_sig_stack(sp);
3913
3914 /* redzone */
3915 /* This is the X/Open sanctioned signal stack switching. */
Riku Voipiob545f632014-07-15 17:01:55 +03003916 if ((ka->sa_flags & TARGET_SA_ONSTACK) != 0 && !onsigstack) {
Jia Liud9627832012-07-20 15:50:52 +08003917 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
3918 }
3919
3920 sp = align_sigframe(sp - frame_size);
3921
3922 /*
3923 * If we are on the alternate signal stack and would overflow it, don't.
3924 * Return an always-bogus address instead so we will die with SIGSEGV.
3925 */
3926
3927 if (onsigstack && !likely(on_sig_stack(sp))) {
3928 return -1L;
3929 }
3930
3931 return sp;
3932}
3933
Jia Liud9627832012-07-20 15:50:52 +08003934static void setup_rt_frame(int sig, struct target_sigaction *ka,
3935 target_siginfo_t *info,
3936 target_sigset_t *set, CPUOpenRISCState *env)
3937{
3938 int err = 0;
3939 abi_ulong frame_addr;
3940 unsigned long return_ip;
3941 struct target_rt_sigframe *frame;
3942 abi_ulong info_addr, uc_addr;
3943
Jia Liud9627832012-07-20 15:50:52 +08003944 frame_addr = get_sigframe(ka, env, sizeof(*frame));
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01003945 trace_user_setup_rt_frame(env, frame_addr);
Jia Liud9627832012-07-20 15:50:52 +08003946 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
3947 goto give_sigsegv;
3948 }
3949
3950 info_addr = frame_addr + offsetof(struct target_rt_sigframe, info);
Riku Voipio1d8b5122014-04-23 10:26:05 +03003951 __put_user(info_addr, &frame->pinfo);
Jia Liud9627832012-07-20 15:50:52 +08003952 uc_addr = frame_addr + offsetof(struct target_rt_sigframe, uc);
Riku Voipio1d8b5122014-04-23 10:26:05 +03003953 __put_user(uc_addr, &frame->puc);
Jia Liud9627832012-07-20 15:50:52 +08003954
3955 if (ka->sa_flags & SA_SIGINFO) {
Peter Maydellf6c7a052015-01-08 12:19:48 +00003956 tswap_siginfo(&frame->info, info);
Jia Liud9627832012-07-20 15:50:52 +08003957 }
3958
3959 /*err |= __clear_user(&frame->uc, offsetof(struct ucontext, uc_mcontext));*/
Riku Voipio1d8b5122014-04-23 10:26:05 +03003960 __put_user(0, &frame->uc.tuc_flags);
3961 __put_user(0, &frame->uc.tuc_link);
3962 __put_user(target_sigaltstack_used.ss_sp,
3963 &frame->uc.tuc_stack.ss_sp);
3964 __put_user(sas_ss_flags(env->gpr[1]), &frame->uc.tuc_stack.ss_flags);
3965 __put_user(target_sigaltstack_used.ss_size,
3966 &frame->uc.tuc_stack.ss_size);
Riku Voipio41ecc722014-04-23 11:01:00 +03003967 setup_sigcontext(&frame->sc, env, set->sig[0]);
Jia Liud9627832012-07-20 15:50:52 +08003968
3969 /*err |= copy_to_user(frame->uc.tuc_sigmask, set, sizeof(*set));*/
3970
Jia Liud9627832012-07-20 15:50:52 +08003971 /* trampoline - the desired return ip is the retcode itself */
3972 return_ip = (unsigned long)&frame->retcode;
3973 /* This is l.ori r11,r0,__NR_sigreturn, l.sys 1 */
Riku Voipio1d8b5122014-04-23 10:26:05 +03003974 __put_user(0xa960, (short *)(frame->retcode + 0));
3975 __put_user(TARGET_NR_rt_sigreturn, (short *)(frame->retcode + 2));
3976 __put_user(0x20000001, (unsigned long *)(frame->retcode + 4));
3977 __put_user(0x15000000, (unsigned long *)(frame->retcode + 8));
Jia Liud9627832012-07-20 15:50:52 +08003978
3979 if (err) {
3980 goto give_sigsegv;
3981 }
3982
3983 /* TODO what is the current->exec_domain stuff and invmap ? */
3984
3985 /* Set up registers for signal handler */
3986 env->pc = (unsigned long)ka->_sa_handler; /* what we enter NOW */
3987 env->gpr[9] = (unsigned long)return_ip; /* what we enter LATER */
3988 env->gpr[3] = (unsigned long)sig; /* arg 1: signo */
3989 env->gpr[4] = (unsigned long)&frame->info; /* arg 2: (siginfo_t*) */
3990 env->gpr[5] = (unsigned long)&frame->uc; /* arg 3: ucontext */
3991
3992 /* actually move the usp to reflect the stacked frame */
3993 env->gpr[1] = (unsigned long)frame;
3994
3995 return;
3996
3997give_sigsegv:
3998 unlock_user_struct(frame, frame_addr, 1);
3999 if (sig == TARGET_SIGSEGV) {
4000 ka->_sa_handler = TARGET_SIG_DFL;
4001 }
4002 force_sig(TARGET_SIGSEGV);
4003}
4004
4005long do_sigreturn(CPUOpenRISCState *env)
4006{
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01004007 trace_user_do_sigreturn(env, 0);
4008 fprintf(stderr, "do_sigreturn: not implemented\n");
Jia Liud9627832012-07-20 15:50:52 +08004009 return -TARGET_ENOSYS;
4010}
4011
4012long do_rt_sigreturn(CPUOpenRISCState *env)
4013{
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01004014 trace_user_do_rt_sigreturn(env, 0);
4015 fprintf(stderr, "do_rt_sigreturn: not implemented\n");
Jia Liud9627832012-07-20 15:50:52 +08004016 return -TARGET_ENOSYS;
4017}
4018/* TARGET_OPENRISC */
4019
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004020#elif defined(TARGET_S390X)
4021
4022#define __NUM_GPRS 16
4023#define __NUM_FPRS 16
4024#define __NUM_ACRS 16
4025
4026#define S390_SYSCALL_SIZE 2
4027#define __SIGNAL_FRAMESIZE 160 /* FIXME: 31-bit mode -> 96 */
4028
4029#define _SIGCONTEXT_NSIG 64
4030#define _SIGCONTEXT_NSIG_BPW 64 /* FIXME: 31-bit mode -> 32 */
4031#define _SIGCONTEXT_NSIG_WORDS (_SIGCONTEXT_NSIG / _SIGCONTEXT_NSIG_BPW)
4032#define _SIGMASK_COPY_SIZE (sizeof(unsigned long)*_SIGCONTEXT_NSIG_WORDS)
4033#define PSW_ADDR_AMODE 0x0000000000000000UL /* 0x80000000UL for 31-bit */
4034#define S390_SYSCALL_OPCODE ((uint16_t)0x0a00)
4035
4036typedef struct {
4037 target_psw_t psw;
4038 target_ulong gprs[__NUM_GPRS];
4039 unsigned int acrs[__NUM_ACRS];
4040} target_s390_regs_common;
4041
4042typedef struct {
4043 unsigned int fpc;
4044 double fprs[__NUM_FPRS];
4045} target_s390_fp_regs;
4046
4047typedef struct {
4048 target_s390_regs_common regs;
4049 target_s390_fp_regs fpregs;
4050} target_sigregs;
4051
4052struct target_sigcontext {
4053 target_ulong oldmask[_SIGCONTEXT_NSIG_WORDS];
4054 target_sigregs *sregs;
4055};
4056
4057typedef struct {
4058 uint8_t callee_used_stack[__SIGNAL_FRAMESIZE];
4059 struct target_sigcontext sc;
4060 target_sigregs sregs;
4061 int signo;
4062 uint8_t retcode[S390_SYSCALL_SIZE];
4063} sigframe;
4064
4065struct target_ucontext {
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004066 target_ulong tuc_flags;
4067 struct target_ucontext *tuc_link;
4068 target_stack_t tuc_stack;
4069 target_sigregs tuc_mcontext;
4070 target_sigset_t tuc_sigmask; /* mask last for extensibility */
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004071};
4072
4073typedef struct {
4074 uint8_t callee_used_stack[__SIGNAL_FRAMESIZE];
4075 uint8_t retcode[S390_SYSCALL_SIZE];
4076 struct target_siginfo info;
4077 struct target_ucontext uc;
4078} rt_sigframe;
4079
4080static inline abi_ulong
Andreas Färber05390242012-02-25 03:37:53 +01004081get_sigframe(struct target_sigaction *ka, CPUS390XState *env, size_t frame_size)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004082{
4083 abi_ulong sp;
4084
4085 /* Default to using normal stack */
4086 sp = env->regs[15];
4087
4088 /* This is the X/Open sanctioned signal stack switching. */
4089 if (ka->sa_flags & TARGET_SA_ONSTACK) {
4090 if (!sas_ss_flags(sp)) {
4091 sp = target_sigaltstack_used.ss_sp +
4092 target_sigaltstack_used.ss_size;
4093 }
4094 }
4095
4096 /* This is the legacy signal stack switching. */
4097 else if (/* FIXME !user_mode(regs) */ 0 &&
4098 !(ka->sa_flags & TARGET_SA_RESTORER) &&
4099 ka->sa_restorer) {
4100 sp = (abi_ulong) ka->sa_restorer;
4101 }
4102
4103 return (sp - frame_size) & -8ul;
4104}
4105
Andreas Färber05390242012-02-25 03:37:53 +01004106static void save_sigregs(CPUS390XState *env, target_sigregs *sregs)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004107{
4108 int i;
4109 //save_access_regs(current->thread.acrs); FIXME
4110
4111 /* Copy a 'clean' PSW mask to the user to avoid leaking
4112 information about whether PER is currently on. */
4113 __put_user(env->psw.mask, &sregs->regs.psw.mask);
4114 __put_user(env->psw.addr, &sregs->regs.psw.addr);
4115 for (i = 0; i < 16; i++) {
4116 __put_user(env->regs[i], &sregs->regs.gprs[i]);
4117 }
4118 for (i = 0; i < 16; i++) {
4119 __put_user(env->aregs[i], &sregs->regs.acrs[i]);
4120 }
4121 /*
4122 * We have to store the fp registers to current->thread.fp_regs
4123 * to merge them with the emulated registers.
4124 */
4125 //save_fp_regs(&current->thread.fp_regs); FIXME
4126 for (i = 0; i < 16; i++) {
Eric Farmanc498d8e2015-05-07 14:35:44 -04004127 __put_user(get_freg(env, i)->ll, &sregs->fpregs.fprs[i]);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004128 }
4129}
4130
4131static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01004132 target_sigset_t *set, CPUS390XState *env)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004133{
4134 sigframe *frame;
4135 abi_ulong frame_addr;
4136
4137 frame_addr = get_sigframe(ka, env, sizeof(*frame));
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01004138 trace_user_setup_frame(env, frame_addr);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004139 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01004140 goto give_sigsegv;
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004141 }
4142
Riku Voipio0188fad2014-04-23 13:34:15 +03004143 __put_user(set->sig[0], &frame->sc.oldmask[0]);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004144
4145 save_sigregs(env, &frame->sregs);
4146
4147 __put_user((abi_ulong)(unsigned long)&frame->sregs,
4148 (abi_ulong *)&frame->sc.sregs);
4149
4150 /* Set up to return from userspace. If provided, use a stub
4151 already in userspace. */
4152 if (ka->sa_flags & TARGET_SA_RESTORER) {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01004153 env->regs[14] = (unsigned long)
4154 ka->sa_restorer | PSW_ADDR_AMODE;
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004155 } else {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01004156 env->regs[14] = (unsigned long)
4157 frame->retcode | PSW_ADDR_AMODE;
4158 __put_user(S390_SYSCALL_OPCODE | TARGET_NR_sigreturn,
4159 (uint16_t *)(frame->retcode));
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004160 }
4161
4162 /* Set up backchain. */
Riku Voipio0188fad2014-04-23 13:34:15 +03004163 __put_user(env->regs[15], (abi_ulong *) frame);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004164
4165 /* Set up registers for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02004166 env->regs[15] = frame_addr;
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004167 env->psw.addr = (target_ulong) ka->_sa_handler | PSW_ADDR_AMODE;
4168
4169 env->regs[2] = sig; //map_signal(sig);
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02004170 env->regs[3] = frame_addr += offsetof(typeof(*frame), sc);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004171
4172 /* We forgot to include these in the sigcontext.
4173 To avoid breaking binary compatibility, they are passed as args. */
4174 env->regs[4] = 0; // FIXME: no clue... current->thread.trap_no;
4175 env->regs[5] = 0; // FIXME: no clue... current->thread.prot_addr;
4176
4177 /* Place signal number on stack to allow backtrace from handler. */
Riku Voipio0188fad2014-04-23 13:34:15 +03004178 __put_user(env->regs[2], (int *) &frame->signo);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004179 unlock_user_struct(frame, frame_addr, 1);
4180 return;
4181
4182give_sigsegv:
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004183 force_sig(TARGET_SIGSEGV);
4184}
4185
4186static void setup_rt_frame(int sig, struct target_sigaction *ka,
4187 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01004188 target_sigset_t *set, CPUS390XState *env)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004189{
4190 int i;
4191 rt_sigframe *frame;
4192 abi_ulong frame_addr;
4193
4194 frame_addr = get_sigframe(ka, env, sizeof *frame);
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01004195 trace_user_setup_rt_frame(env, frame_addr);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004196 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
4197 goto give_sigsegv;
4198 }
4199
Peter Maydellf6c7a052015-01-08 12:19:48 +00004200 tswap_siginfo(&frame->info, info);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004201
4202 /* Create the ucontext. */
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004203 __put_user(0, &frame->uc.tuc_flags);
4204 __put_user((abi_ulong)0, (abi_ulong *)&frame->uc.tuc_link);
4205 __put_user(target_sigaltstack_used.ss_sp, &frame->uc.tuc_stack.ss_sp);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004206 __put_user(sas_ss_flags(get_sp_from_cpustate(env)),
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01004207 &frame->uc.tuc_stack.ss_flags);
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004208 __put_user(target_sigaltstack_used.ss_size, &frame->uc.tuc_stack.ss_size);
4209 save_sigregs(env, &frame->uc.tuc_mcontext);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004210 for (i = 0; i < TARGET_NSIG_WORDS; i++) {
4211 __put_user((abi_ulong)set->sig[i],
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01004212 (abi_ulong *)&frame->uc.tuc_sigmask.sig[i]);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004213 }
4214
4215 /* Set up to return from userspace. If provided, use a stub
4216 already in userspace. */
4217 if (ka->sa_flags & TARGET_SA_RESTORER) {
4218 env->regs[14] = (unsigned long) ka->sa_restorer | PSW_ADDR_AMODE;
4219 } else {
4220 env->regs[14] = (unsigned long) frame->retcode | PSW_ADDR_AMODE;
Riku Voipio0188fad2014-04-23 13:34:15 +03004221 __put_user(S390_SYSCALL_OPCODE | TARGET_NR_rt_sigreturn,
4222 (uint16_t *)(frame->retcode));
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004223 }
4224
4225 /* Set up backchain. */
Riku Voipio0188fad2014-04-23 13:34:15 +03004226 __put_user(env->regs[15], (abi_ulong *) frame);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004227
4228 /* Set up registers for signal handler */
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02004229 env->regs[15] = frame_addr;
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004230 env->psw.addr = (target_ulong) ka->_sa_handler | PSW_ADDR_AMODE;
4231
4232 env->regs[2] = sig; //map_signal(sig);
Edgar E. Iglesiascb9c6262011-08-22 18:44:58 +02004233 env->regs[3] = frame_addr + offsetof(typeof(*frame), info);
4234 env->regs[4] = frame_addr + offsetof(typeof(*frame), uc);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004235 return;
4236
4237give_sigsegv:
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004238 force_sig(TARGET_SIGSEGV);
4239}
4240
4241static int
Andreas Färber05390242012-02-25 03:37:53 +01004242restore_sigregs(CPUS390XState *env, target_sigregs *sc)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004243{
4244 int err = 0;
4245 int i;
4246
4247 for (i = 0; i < 16; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03004248 __get_user(env->regs[i], &sc->regs.gprs[i]);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004249 }
4250
Riku Voipio1d8b5122014-04-23 10:26:05 +03004251 __get_user(env->psw.mask, &sc->regs.psw.mask);
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01004252 trace_user_s390x_restore_sigregs(env, (unsigned long long)sc->regs.psw.addr,
4253 (unsigned long long)env->psw.addr);
Riku Voipio1d8b5122014-04-23 10:26:05 +03004254 __get_user(env->psw.addr, &sc->regs.psw.addr);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004255 /* FIXME: 31-bit -> | PSW_ADDR_AMODE */
4256
4257 for (i = 0; i < 16; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03004258 __get_user(env->aregs[i], &sc->regs.acrs[i]);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004259 }
4260 for (i = 0; i < 16; i++) {
Eric Farmanc498d8e2015-05-07 14:35:44 -04004261 __get_user(get_freg(env, i)->ll, &sc->fpregs.fprs[i]);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004262 }
4263
4264 return err;
4265}
4266
Andreas Färber05390242012-02-25 03:37:53 +01004267long do_sigreturn(CPUS390XState *env)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004268{
4269 sigframe *frame;
4270 abi_ulong frame_addr = env->regs[15];
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004271 target_sigset_t target_set;
4272 sigset_t set;
4273
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01004274 trace_user_do_sigreturn(env, frame_addr);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004275 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
4276 goto badframe;
4277 }
Riku Voipiof5f601a2014-04-23 13:00:17 +03004278 __get_user(target_set.sig[0], &frame->sc.oldmask[0]);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004279
4280 target_to_host_sigset_internal(&set, &target_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00004281 do_sigprocmask(SIG_SETMASK, &set, NULL); /* ~_BLOCKABLE? */
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004282
4283 if (restore_sigregs(env, &frame->sregs)) {
4284 goto badframe;
4285 }
4286
4287 unlock_user_struct(frame, frame_addr, 0);
4288 return env->regs[2];
4289
4290badframe:
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004291 force_sig(TARGET_SIGSEGV);
4292 return 0;
4293}
4294
Andreas Färber05390242012-02-25 03:37:53 +01004295long do_rt_sigreturn(CPUS390XState *env)
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004296{
4297 rt_sigframe *frame;
4298 abi_ulong frame_addr = env->regs[15];
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004299 sigset_t set;
4300
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01004301 trace_user_do_rt_sigreturn(env, frame_addr);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004302 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
4303 goto badframe;
4304 }
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004305 target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004306
Alex Barcelo1c275922014-03-14 14:36:55 +00004307 do_sigprocmask(SIG_SETMASK, &set, NULL); /* ~_BLOCKABLE? */
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004308
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004309 if (restore_sigregs(env, &frame->uc.tuc_mcontext)) {
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004310 goto badframe;
4311 }
4312
Peter Maydell6fea2ea2011-07-12 21:27:15 +01004313 if (do_sigaltstack(frame_addr + offsetof(rt_sigframe, uc.tuc_stack), 0,
Ulrich Hechta4c075f2009-07-24 16:57:31 +02004314 get_sp_from_cpustate(env)) == -EFAULT) {
4315 goto badframe;
4316 }
4317 unlock_user_struct(frame, frame_addr, 0);
4318 return env->regs[2];
4319
4320badframe:
4321 unlock_user_struct(frame, frame_addr, 0);
4322 force_sig(TARGET_SIGSEGV);
4323 return 0;
4324}
4325
Tom Musta61e75fe2014-06-30 08:13:38 -05004326#elif defined(TARGET_PPC)
Nathan Froydbcd49332009-05-12 19:13:18 -07004327
4328/* Size of dummy stack frame allocated when calling signal handler.
4329 See arch/powerpc/include/asm/ptrace.h. */
4330#if defined(TARGET_PPC64)
4331#define SIGNAL_FRAMESIZE 128
4332#else
4333#define SIGNAL_FRAMESIZE 64
4334#endif
4335
Tom Musta61e75fe2014-06-30 08:13:38 -05004336/* See arch/powerpc/include/asm/ucontext.h. Only used for 32-bit PPC;
4337 on 64-bit PPC, sigcontext and mcontext are one and the same. */
4338struct target_mcontext {
4339 target_ulong mc_gregs[48];
4340 /* Includes fpscr. */
4341 uint64_t mc_fregs[33];
4342 target_ulong mc_pad[2];
4343 /* We need to handle Altivec and SPE at the same time, which no
4344 kernel needs to do. Fortunately, the kernel defines this bit to
4345 be Altivec-register-large all the time, rather than trying to
4346 twiddle it based on the specific platform. */
4347 union {
4348 /* SPE vector registers. One extra for SPEFSCR. */
4349 uint32_t spe[33];
4350 /* Altivec vector registers. The packing of VSCR and VRSAVE
4351 varies depending on whether we're PPC64 or not: PPC64 splits
4352 them apart; PPC32 stuffs them together. */
4353#if defined(TARGET_PPC64)
4354#define QEMU_NVRREG 34
4355#else
4356#define QEMU_NVRREG 33
4357#endif
4358 ppc_avr_t altivec[QEMU_NVRREG];
4359#undef QEMU_NVRREG
4360 } mc_vregs __attribute__((__aligned__(16)));
4361};
4362
Nathan Froydbcd49332009-05-12 19:13:18 -07004363/* See arch/powerpc/include/asm/sigcontext.h. */
4364struct target_sigcontext {
4365 target_ulong _unused[4];
4366 int32_t signal;
4367#if defined(TARGET_PPC64)
4368 int32_t pad0;
4369#endif
4370 target_ulong handler;
4371 target_ulong oldmask;
4372 target_ulong regs; /* struct pt_regs __user * */
Tom Musta61e75fe2014-06-30 08:13:38 -05004373#if defined(TARGET_PPC64)
4374 struct target_mcontext mcontext;
4375#endif
Nathan Froydbcd49332009-05-12 19:13:18 -07004376};
4377
4378/* Indices for target_mcontext.mc_gregs, below.
4379 See arch/powerpc/include/asm/ptrace.h for details. */
4380enum {
4381 TARGET_PT_R0 = 0,
4382 TARGET_PT_R1 = 1,
4383 TARGET_PT_R2 = 2,
4384 TARGET_PT_R3 = 3,
4385 TARGET_PT_R4 = 4,
4386 TARGET_PT_R5 = 5,
4387 TARGET_PT_R6 = 6,
4388 TARGET_PT_R7 = 7,
4389 TARGET_PT_R8 = 8,
4390 TARGET_PT_R9 = 9,
4391 TARGET_PT_R10 = 10,
4392 TARGET_PT_R11 = 11,
4393 TARGET_PT_R12 = 12,
4394 TARGET_PT_R13 = 13,
4395 TARGET_PT_R14 = 14,
4396 TARGET_PT_R15 = 15,
4397 TARGET_PT_R16 = 16,
4398 TARGET_PT_R17 = 17,
4399 TARGET_PT_R18 = 18,
4400 TARGET_PT_R19 = 19,
4401 TARGET_PT_R20 = 20,
4402 TARGET_PT_R21 = 21,
4403 TARGET_PT_R22 = 22,
4404 TARGET_PT_R23 = 23,
4405 TARGET_PT_R24 = 24,
4406 TARGET_PT_R25 = 25,
4407 TARGET_PT_R26 = 26,
4408 TARGET_PT_R27 = 27,
4409 TARGET_PT_R28 = 28,
4410 TARGET_PT_R29 = 29,
4411 TARGET_PT_R30 = 30,
4412 TARGET_PT_R31 = 31,
4413 TARGET_PT_NIP = 32,
4414 TARGET_PT_MSR = 33,
4415 TARGET_PT_ORIG_R3 = 34,
4416 TARGET_PT_CTR = 35,
4417 TARGET_PT_LNK = 36,
4418 TARGET_PT_XER = 37,
4419 TARGET_PT_CCR = 38,
4420 /* Yes, there are two registers with #39. One is 64-bit only. */
4421 TARGET_PT_MQ = 39,
4422 TARGET_PT_SOFTE = 39,
4423 TARGET_PT_TRAP = 40,
4424 TARGET_PT_DAR = 41,
4425 TARGET_PT_DSISR = 42,
4426 TARGET_PT_RESULT = 43,
4427 TARGET_PT_REGS_COUNT = 44
4428};
4429
Nathan Froydbcd49332009-05-12 19:13:18 -07004430
4431struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02004432 target_ulong tuc_flags;
4433 target_ulong tuc_link; /* struct ucontext __user * */
4434 struct target_sigaltstack tuc_stack;
Nathan Froydbcd49332009-05-12 19:13:18 -07004435#if !defined(TARGET_PPC64)
Aurelien Jarno60e99242010-03-29 02:12:51 +02004436 int32_t tuc_pad[7];
4437 target_ulong tuc_regs; /* struct mcontext __user *
Nathan Froydbcd49332009-05-12 19:13:18 -07004438 points to uc_mcontext field */
4439#endif
Aurelien Jarno60e99242010-03-29 02:12:51 +02004440 target_sigset_t tuc_sigmask;
Nathan Froydbcd49332009-05-12 19:13:18 -07004441#if defined(TARGET_PPC64)
Anthony Liguoric227f092009-10-01 16:12:16 -05004442 target_sigset_t unused[15]; /* Allow for uc_sigmask growth */
Tom Musta61e75fe2014-06-30 08:13:38 -05004443 struct target_sigcontext tuc_sigcontext;
Nathan Froydbcd49332009-05-12 19:13:18 -07004444#else
Aurelien Jarno60e99242010-03-29 02:12:51 +02004445 int32_t tuc_maskext[30];
4446 int32_t tuc_pad2[3];
4447 struct target_mcontext tuc_mcontext;
Nathan Froydbcd49332009-05-12 19:13:18 -07004448#endif
4449};
4450
4451/* See arch/powerpc/kernel/signal_32.c. */
4452struct target_sigframe {
4453 struct target_sigcontext sctx;
4454 struct target_mcontext mctx;
4455 int32_t abigap[56];
4456};
4457
Tom Musta61e75fe2014-06-30 08:13:38 -05004458#if defined(TARGET_PPC64)
4459
4460#define TARGET_TRAMP_SIZE 6
4461
4462struct target_rt_sigframe {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01004463 /* sys_rt_sigreturn requires the ucontext be the first field */
4464 struct target_ucontext uc;
4465 target_ulong _unused[2];
4466 uint32_t trampoline[TARGET_TRAMP_SIZE];
4467 target_ulong pinfo; /* struct siginfo __user * */
4468 target_ulong puc; /* void __user * */
4469 struct target_siginfo info;
4470 /* 64 bit ABI allows for 288 bytes below sp before decrementing it. */
4471 char abigap[288];
Tom Musta61e75fe2014-06-30 08:13:38 -05004472} __attribute__((aligned(16)));
4473
4474#else
4475
Nathan Froydbcd49332009-05-12 19:13:18 -07004476struct target_rt_sigframe {
4477 struct target_siginfo info;
4478 struct target_ucontext uc;
4479 int32_t abigap[56];
4480};
4481
Tom Musta61e75fe2014-06-30 08:13:38 -05004482#endif
4483
Tom Musta8d6ab332014-06-30 08:13:39 -05004484#if defined(TARGET_PPC64)
4485
4486struct target_func_ptr {
4487 target_ulong entry;
4488 target_ulong toc;
4489};
4490
4491#endif
4492
Nathan Froydbcd49332009-05-12 19:13:18 -07004493/* We use the mc_pad field for the signal return trampoline. */
4494#define tramp mc_pad
4495
4496/* See arch/powerpc/kernel/signal.c. */
4497static target_ulong get_sigframe(struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01004498 CPUPPCState *env,
Nathan Froydbcd49332009-05-12 19:13:18 -07004499 int frame_size)
4500{
4501 target_ulong oldsp, newsp;
4502
4503 oldsp = env->gpr[1];
4504
4505 if ((ka->sa_flags & TARGET_SA_ONSTACK) &&
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01004506 (sas_ss_flags(oldsp) == 0)) {
Nathan Froydbcd49332009-05-12 19:13:18 -07004507 oldsp = (target_sigaltstack_used.ss_sp
4508 + target_sigaltstack_used.ss_size);
4509 }
4510
4511 newsp = (oldsp - frame_size) & ~0xFUL;
4512
4513 return newsp;
4514}
4515
Tom Musta76781082014-06-30 08:13:37 -05004516static void save_user_regs(CPUPPCState *env, struct target_mcontext *frame)
Nathan Froydbcd49332009-05-12 19:13:18 -07004517{
4518 target_ulong msr = env->msr;
4519 int i;
4520 target_ulong ccr = 0;
4521
4522 /* In general, the kernel attempts to be intelligent about what it
4523 needs to save for Altivec/FP/SPE registers. We don't care that
4524 much, so we just go ahead and save everything. */
4525
4526 /* Save general registers. */
4527 for (i = 0; i < ARRAY_SIZE(env->gpr); i++) {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01004528 __put_user(env->gpr[i], &frame->mc_gregs[i]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004529 }
Riku Voipioc650c002014-04-23 13:53:45 +03004530 __put_user(env->nip, &frame->mc_gregs[TARGET_PT_NIP]);
4531 __put_user(env->ctr, &frame->mc_gregs[TARGET_PT_CTR]);
4532 __put_user(env->lr, &frame->mc_gregs[TARGET_PT_LNK]);
4533 __put_user(env->xer, &frame->mc_gregs[TARGET_PT_XER]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004534
4535 for (i = 0; i < ARRAY_SIZE(env->crf); i++) {
4536 ccr |= env->crf[i] << (32 - ((i + 1) * 4));
4537 }
Riku Voipioc650c002014-04-23 13:53:45 +03004538 __put_user(ccr, &frame->mc_gregs[TARGET_PT_CCR]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004539
4540 /* Save Altivec registers if necessary. */
4541 if (env->insns_flags & PPC_ALTIVEC) {
4542 for (i = 0; i < ARRAY_SIZE(env->avr); i++) {
Anthony Liguoric227f092009-10-01 16:12:16 -05004543 ppc_avr_t *avr = &env->avr[i];
4544 ppc_avr_t *vreg = &frame->mc_vregs.altivec[i];
Nathan Froydbcd49332009-05-12 19:13:18 -07004545
Riku Voipioc650c002014-04-23 13:53:45 +03004546 __put_user(avr->u64[0], &vreg->u64[0]);
4547 __put_user(avr->u64[1], &vreg->u64[1]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004548 }
4549 /* Set MSR_VR in the saved MSR value to indicate that
4550 frame->mc_vregs contains valid data. */
4551 msr |= MSR_VR;
Riku Voipioc650c002014-04-23 13:53:45 +03004552 __put_user((uint32_t)env->spr[SPR_VRSAVE],
4553 &frame->mc_vregs.altivec[32].u32[3]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004554 }
4555
4556 /* Save floating point registers. */
4557 if (env->insns_flags & PPC_FLOAT) {
4558 for (i = 0; i < ARRAY_SIZE(env->fpr); i++) {
Riku Voipioc650c002014-04-23 13:53:45 +03004559 __put_user(env->fpr[i], &frame->mc_fregs[i]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004560 }
Riku Voipioc650c002014-04-23 13:53:45 +03004561 __put_user((uint64_t) env->fpscr, &frame->mc_fregs[32]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004562 }
4563
4564 /* Save SPE registers. The kernel only saves the high half. */
4565 if (env->insns_flags & PPC_SPE) {
4566#if defined(TARGET_PPC64)
4567 for (i = 0; i < ARRAY_SIZE(env->gpr); i++) {
Riku Voipioc650c002014-04-23 13:53:45 +03004568 __put_user(env->gpr[i] >> 32, &frame->mc_vregs.spe[i]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004569 }
4570#else
4571 for (i = 0; i < ARRAY_SIZE(env->gprh); i++) {
Riku Voipioc650c002014-04-23 13:53:45 +03004572 __put_user(env->gprh[i], &frame->mc_vregs.spe[i]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004573 }
4574#endif
4575 /* Set MSR_SPE in the saved MSR value to indicate that
4576 frame->mc_vregs contains valid data. */
4577 msr |= MSR_SPE;
Riku Voipioc650c002014-04-23 13:53:45 +03004578 __put_user(env->spe_fscr, &frame->mc_vregs.spe[32]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004579 }
4580
4581 /* Store MSR. */
Riku Voipioc650c002014-04-23 13:53:45 +03004582 __put_user(msr, &frame->mc_gregs[TARGET_PT_MSR]);
Tom Musta76781082014-06-30 08:13:37 -05004583}
Nathan Froydbcd49332009-05-12 19:13:18 -07004584
Tom Musta76781082014-06-30 08:13:37 -05004585static void encode_trampoline(int sigret, uint32_t *tramp)
4586{
Nathan Froydbcd49332009-05-12 19:13:18 -07004587 /* Set up the sigreturn trampoline: li r0,sigret; sc. */
4588 if (sigret) {
Tom Musta76781082014-06-30 08:13:37 -05004589 __put_user(0x38000000 | sigret, &tramp[0]);
4590 __put_user(0x44000002, &tramp[1]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004591 }
Nathan Froydbcd49332009-05-12 19:13:18 -07004592}
4593
Riku Voipioc650c002014-04-23 13:53:45 +03004594static void restore_user_regs(CPUPPCState *env,
4595 struct target_mcontext *frame, int sig)
Nathan Froydbcd49332009-05-12 19:13:18 -07004596{
4597 target_ulong save_r2 = 0;
4598 target_ulong msr;
4599 target_ulong ccr;
4600
4601 int i;
4602
4603 if (!sig) {
4604 save_r2 = env->gpr[2];
4605 }
4606
4607 /* Restore general registers. */
4608 for (i = 0; i < ARRAY_SIZE(env->gpr); i++) {
Riku Voipioc650c002014-04-23 13:53:45 +03004609 __get_user(env->gpr[i], &frame->mc_gregs[i]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004610 }
Riku Voipioc650c002014-04-23 13:53:45 +03004611 __get_user(env->nip, &frame->mc_gregs[TARGET_PT_NIP]);
4612 __get_user(env->ctr, &frame->mc_gregs[TARGET_PT_CTR]);
4613 __get_user(env->lr, &frame->mc_gregs[TARGET_PT_LNK]);
4614 __get_user(env->xer, &frame->mc_gregs[TARGET_PT_XER]);
4615 __get_user(ccr, &frame->mc_gregs[TARGET_PT_CCR]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004616
4617 for (i = 0; i < ARRAY_SIZE(env->crf); i++) {
4618 env->crf[i] = (ccr >> (32 - ((i + 1) * 4))) & 0xf;
4619 }
4620
4621 if (!sig) {
4622 env->gpr[2] = save_r2;
4623 }
4624 /* Restore MSR. */
Riku Voipioc650c002014-04-23 13:53:45 +03004625 __get_user(msr, &frame->mc_gregs[TARGET_PT_MSR]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004626
4627 /* If doing signal return, restore the previous little-endian mode. */
4628 if (sig)
4629 env->msr = (env->msr & ~MSR_LE) | (msr & MSR_LE);
4630
4631 /* Restore Altivec registers if necessary. */
4632 if (env->insns_flags & PPC_ALTIVEC) {
4633 for (i = 0; i < ARRAY_SIZE(env->avr); i++) {
Anthony Liguoric227f092009-10-01 16:12:16 -05004634 ppc_avr_t *avr = &env->avr[i];
4635 ppc_avr_t *vreg = &frame->mc_vregs.altivec[i];
Nathan Froydbcd49332009-05-12 19:13:18 -07004636
Riku Voipioc650c002014-04-23 13:53:45 +03004637 __get_user(avr->u64[0], &vreg->u64[0]);
4638 __get_user(avr->u64[1], &vreg->u64[1]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004639 }
4640 /* Set MSR_VEC in the saved MSR value to indicate that
4641 frame->mc_vregs contains valid data. */
Riku Voipioc650c002014-04-23 13:53:45 +03004642 __get_user(env->spr[SPR_VRSAVE],
4643 (target_ulong *)(&frame->mc_vregs.altivec[32].u32[3]));
Nathan Froydbcd49332009-05-12 19:13:18 -07004644 }
4645
4646 /* Restore floating point registers. */
4647 if (env->insns_flags & PPC_FLOAT) {
4648 uint64_t fpscr;
4649 for (i = 0; i < ARRAY_SIZE(env->fpr); i++) {
Riku Voipioc650c002014-04-23 13:53:45 +03004650 __get_user(env->fpr[i], &frame->mc_fregs[i]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004651 }
Riku Voipioc650c002014-04-23 13:53:45 +03004652 __get_user(fpscr, &frame->mc_fregs[32]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004653 env->fpscr = (uint32_t) fpscr;
4654 }
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++) {
4660 uint32_t hi;
4661
Riku Voipioc650c002014-04-23 13:53:45 +03004662 __get_user(hi, &frame->mc_vregs.spe[i]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004663 env->gpr[i] = ((uint64_t)hi << 32) | ((uint32_t) env->gpr[i]);
4664 }
4665#else
4666 for (i = 0; i < ARRAY_SIZE(env->gprh); i++) {
Riku Voipioc650c002014-04-23 13:53:45 +03004667 __get_user(env->gprh[i], &frame->mc_vregs.spe[i]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004668 }
4669#endif
Riku Voipioc650c002014-04-23 13:53:45 +03004670 __get_user(env->spe_fscr, &frame->mc_vregs.spe[32]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004671 }
Nathan Froydbcd49332009-05-12 19:13:18 -07004672}
4673
4674static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01004675 target_sigset_t *set, CPUPPCState *env)
Nathan Froydbcd49332009-05-12 19:13:18 -07004676{
4677 struct target_sigframe *frame;
4678 struct target_sigcontext *sc;
4679 target_ulong frame_addr, newsp;
4680 int err = 0;
Tom Musta14585582014-06-30 08:13:42 -05004681#if defined(TARGET_PPC64)
4682 struct image_info *image = ((TaskState *)thread_cpu->opaque)->info;
4683#endif
Nathan Froydbcd49332009-05-12 19:13:18 -07004684
4685 frame_addr = get_sigframe(ka, env, sizeof(*frame));
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01004686 trace_user_setup_frame(env, frame_addr);
Nathan Froydbcd49332009-05-12 19:13:18 -07004687 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 1))
4688 goto sigsegv;
4689 sc = &frame->sctx;
4690
Riku Voipio1d8b5122014-04-23 10:26:05 +03004691 __put_user(ka->_sa_handler, &sc->handler);
4692 __put_user(set->sig[0], &sc->oldmask);
Tom Musta61e75fe2014-06-30 08:13:38 -05004693#if TARGET_ABI_BITS == 64
Riku Voipio1d8b5122014-04-23 10:26:05 +03004694 __put_user(set->sig[0] >> 32, &sc->_unused[3]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004695#else
Riku Voipio1d8b5122014-04-23 10:26:05 +03004696 __put_user(set->sig[1], &sc->_unused[3]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004697#endif
Riku Voipio1d8b5122014-04-23 10:26:05 +03004698 __put_user(h2g(&frame->mctx), &sc->regs);
4699 __put_user(sig, &sc->signal);
Nathan Froydbcd49332009-05-12 19:13:18 -07004700
4701 /* Save user regs. */
Tom Musta76781082014-06-30 08:13:37 -05004702 save_user_regs(env, &frame->mctx);
4703
4704 /* Construct the trampoline code on the stack. */
4705 encode_trampoline(TARGET_NR_sigreturn, (uint32_t *)&frame->mctx.tramp);
Nathan Froydbcd49332009-05-12 19:13:18 -07004706
4707 /* The kernel checks for the presence of a VDSO here. We don't
4708 emulate a vdso, so use a sigreturn system call. */
4709 env->lr = (target_ulong) h2g(frame->mctx.tramp);
4710
4711 /* Turn off all fp exceptions. */
4712 env->fpscr = 0;
4713
4714 /* Create a stack frame for the caller of the handler. */
4715 newsp = frame_addr - SIGNAL_FRAMESIZE;
Samuel Seaybeb526b2013-01-02 10:53:46 +00004716 err |= put_user(env->gpr[1], newsp, target_ulong);
Nathan Froydbcd49332009-05-12 19:13:18 -07004717
4718 if (err)
4719 goto sigsegv;
4720
4721 /* Set up registers for signal handler. */
4722 env->gpr[1] = newsp;
Peter Maydellb6e2c932015-01-08 12:19:43 +00004723 env->gpr[3] = sig;
Samuel Seay61993a62013-01-04 14:35:48 +00004724 env->gpr[4] = frame_addr + offsetof(struct target_sigframe, sctx);
Tom Musta8d6ab332014-06-30 08:13:39 -05004725
4726#if defined(TARGET_PPC64)
Tom Musta14585582014-06-30 08:13:42 -05004727 if (get_ppc64_abi(image) < 2) {
4728 /* ELFv1 PPC64 function pointers are pointers to OPD entries. */
4729 struct target_func_ptr *handler =
4730 (struct target_func_ptr *)g2h(ka->_sa_handler);
4731 env->nip = tswapl(handler->entry);
4732 env->gpr[2] = tswapl(handler->toc);
4733 } else {
4734 /* ELFv2 PPC64 function pointers are entry points, but R12
4735 * must also be set */
4736 env->nip = tswapl((target_ulong) ka->_sa_handler);
4737 env->gpr[12] = env->nip;
4738 }
Tom Musta8d6ab332014-06-30 08:13:39 -05004739#else
Nathan Froydbcd49332009-05-12 19:13:18 -07004740 env->nip = (target_ulong) ka->_sa_handler;
Tom Musta8d6ab332014-06-30 08:13:39 -05004741#endif
4742
Nathan Froydbcd49332009-05-12 19:13:18 -07004743 /* Signal handlers are entered in big-endian mode. */
4744 env->msr &= ~MSR_LE;
4745
4746 unlock_user_struct(frame, frame_addr, 1);
4747 return;
4748
4749sigsegv:
4750 unlock_user_struct(frame, frame_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02004751 force_sig(TARGET_SIGSEGV);
Nathan Froydbcd49332009-05-12 19:13:18 -07004752}
4753
4754static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05004755 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01004756 target_sigset_t *set, CPUPPCState *env)
Nathan Froydbcd49332009-05-12 19:13:18 -07004757{
4758 struct target_rt_sigframe *rt_sf;
Tom Musta61e75fe2014-06-30 08:13:38 -05004759 uint32_t *trampptr = 0;
4760 struct target_mcontext *mctx = 0;
Nathan Froydbcd49332009-05-12 19:13:18 -07004761 target_ulong rt_sf_addr, newsp = 0;
4762 int i, err = 0;
Tom Musta14585582014-06-30 08:13:42 -05004763#if defined(TARGET_PPC64)
4764 struct image_info *image = ((TaskState *)thread_cpu->opaque)->info;
4765#endif
Nathan Froydbcd49332009-05-12 19:13:18 -07004766
4767 rt_sf_addr = get_sigframe(ka, env, sizeof(*rt_sf));
4768 if (!lock_user_struct(VERIFY_WRITE, rt_sf, rt_sf_addr, 1))
4769 goto sigsegv;
4770
Peter Maydellf6c7a052015-01-08 12:19:48 +00004771 tswap_siginfo(&rt_sf->info, info);
Nathan Froydbcd49332009-05-12 19:13:18 -07004772
Riku Voipio1d8b5122014-04-23 10:26:05 +03004773 __put_user(0, &rt_sf->uc.tuc_flags);
4774 __put_user(0, &rt_sf->uc.tuc_link);
4775 __put_user((target_ulong)target_sigaltstack_used.ss_sp,
4776 &rt_sf->uc.tuc_stack.ss_sp);
4777 __put_user(sas_ss_flags(env->gpr[1]),
4778 &rt_sf->uc.tuc_stack.ss_flags);
4779 __put_user(target_sigaltstack_used.ss_size,
4780 &rt_sf->uc.tuc_stack.ss_size);
Tom Musta61e75fe2014-06-30 08:13:38 -05004781#if !defined(TARGET_PPC64)
Riku Voipio1d8b5122014-04-23 10:26:05 +03004782 __put_user(h2g (&rt_sf->uc.tuc_mcontext),
4783 &rt_sf->uc.tuc_regs);
Tom Musta61e75fe2014-06-30 08:13:38 -05004784#endif
Nathan Froydbcd49332009-05-12 19:13:18 -07004785 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03004786 __put_user(set->sig[i], &rt_sf->uc.tuc_sigmask.sig[i]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004787 }
4788
Tom Musta61e75fe2014-06-30 08:13:38 -05004789#if defined(TARGET_PPC64)
4790 mctx = &rt_sf->uc.tuc_sigcontext.mcontext;
4791 trampptr = &rt_sf->trampoline[0];
4792#else
4793 mctx = &rt_sf->uc.tuc_mcontext;
4794 trampptr = (uint32_t *)&rt_sf->uc.tuc_mcontext.tramp;
4795#endif
4796
4797 save_user_regs(env, mctx);
4798 encode_trampoline(TARGET_NR_rt_sigreturn, trampptr);
Nathan Froydbcd49332009-05-12 19:13:18 -07004799
4800 /* The kernel checks for the presence of a VDSO here. We don't
4801 emulate a vdso, so use a sigreturn system call. */
Tom Musta61e75fe2014-06-30 08:13:38 -05004802 env->lr = (target_ulong) h2g(trampptr);
Nathan Froydbcd49332009-05-12 19:13:18 -07004803
4804 /* Turn off all fp exceptions. */
4805 env->fpscr = 0;
4806
4807 /* Create a stack frame for the caller of the handler. */
4808 newsp = rt_sf_addr - (SIGNAL_FRAMESIZE + 16);
Tom Mustafbdc2002014-06-30 08:13:36 -05004809 err |= put_user(env->gpr[1], newsp, target_ulong);
Nathan Froydbcd49332009-05-12 19:13:18 -07004810
4811 if (err)
4812 goto sigsegv;
4813
4814 /* Set up registers for signal handler. */
4815 env->gpr[1] = newsp;
Peter Maydellb6e2c932015-01-08 12:19:43 +00004816 env->gpr[3] = (target_ulong) sig;
Nathan Froydbcd49332009-05-12 19:13:18 -07004817 env->gpr[4] = (target_ulong) h2g(&rt_sf->info);
4818 env->gpr[5] = (target_ulong) h2g(&rt_sf->uc);
4819 env->gpr[6] = (target_ulong) h2g(rt_sf);
Tom Musta8d6ab332014-06-30 08:13:39 -05004820
4821#if defined(TARGET_PPC64)
Tom Musta14585582014-06-30 08:13:42 -05004822 if (get_ppc64_abi(image) < 2) {
4823 /* ELFv1 PPC64 function pointers are pointers to OPD entries. */
4824 struct target_func_ptr *handler =
4825 (struct target_func_ptr *)g2h(ka->_sa_handler);
4826 env->nip = tswapl(handler->entry);
4827 env->gpr[2] = tswapl(handler->toc);
4828 } else {
4829 /* ELFv2 PPC64 function pointers are entry points, but R12
4830 * must also be set */
4831 env->nip = tswapl((target_ulong) ka->_sa_handler);
4832 env->gpr[12] = env->nip;
4833 }
Tom Musta8d6ab332014-06-30 08:13:39 -05004834#else
Nathan Froydbcd49332009-05-12 19:13:18 -07004835 env->nip = (target_ulong) ka->_sa_handler;
Tom Musta8d6ab332014-06-30 08:13:39 -05004836#endif
4837
Nathan Froydbcd49332009-05-12 19:13:18 -07004838 /* Signal handlers are entered in big-endian mode. */
4839 env->msr &= ~MSR_LE;
4840
4841 unlock_user_struct(rt_sf, rt_sf_addr, 1);
4842 return;
4843
4844sigsegv:
4845 unlock_user_struct(rt_sf, rt_sf_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02004846 force_sig(TARGET_SIGSEGV);
Nathan Froydbcd49332009-05-12 19:13:18 -07004847
4848}
4849
Andreas Färber05390242012-02-25 03:37:53 +01004850long do_sigreturn(CPUPPCState *env)
Nathan Froydbcd49332009-05-12 19:13:18 -07004851{
4852 struct target_sigcontext *sc = NULL;
4853 struct target_mcontext *sr = NULL;
Peter Maydellb04636f2013-07-29 12:00:31 +01004854 target_ulong sr_addr = 0, sc_addr;
Nathan Froydbcd49332009-05-12 19:13:18 -07004855 sigset_t blocked;
Anthony Liguoric227f092009-10-01 16:12:16 -05004856 target_sigset_t set;
Nathan Froydbcd49332009-05-12 19:13:18 -07004857
4858 sc_addr = env->gpr[1] + SIGNAL_FRAMESIZE;
4859 if (!lock_user_struct(VERIFY_READ, sc, sc_addr, 1))
4860 goto sigsegv;
4861
4862#if defined(TARGET_PPC64)
Tom Musta61e75fe2014-06-30 08:13:38 -05004863 set.sig[0] = sc->oldmask + ((uint64_t)(sc->_unused[3]) << 32);
Nathan Froydbcd49332009-05-12 19:13:18 -07004864#else
Riku Voipiof5f601a2014-04-23 13:00:17 +03004865 __get_user(set.sig[0], &sc->oldmask);
4866 __get_user(set.sig[1], &sc->_unused[3]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004867#endif
4868 target_to_host_sigset_internal(&blocked, &set);
Alex Barcelo1c275922014-03-14 14:36:55 +00004869 do_sigprocmask(SIG_SETMASK, &blocked, NULL);
Nathan Froydbcd49332009-05-12 19:13:18 -07004870
Riku Voipiof5f601a2014-04-23 13:00:17 +03004871 __get_user(sr_addr, &sc->regs);
Nathan Froydbcd49332009-05-12 19:13:18 -07004872 if (!lock_user_struct(VERIFY_READ, sr, sr_addr, 1))
4873 goto sigsegv;
Riku Voipioc650c002014-04-23 13:53:45 +03004874 restore_user_regs(env, sr, 1);
Nathan Froydbcd49332009-05-12 19:13:18 -07004875
4876 unlock_user_struct(sr, sr_addr, 1);
4877 unlock_user_struct(sc, sc_addr, 1);
4878 return -TARGET_QEMU_ESIGRETURN;
4879
4880sigsegv:
4881 unlock_user_struct(sr, sr_addr, 1);
4882 unlock_user_struct(sc, sc_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02004883 force_sig(TARGET_SIGSEGV);
Nathan Froydbcd49332009-05-12 19:13:18 -07004884 return 0;
4885}
4886
4887/* See arch/powerpc/kernel/signal_32.c. */
Andreas Färber05390242012-02-25 03:37:53 +01004888static int do_setcontext(struct target_ucontext *ucp, CPUPPCState *env, int sig)
Nathan Froydbcd49332009-05-12 19:13:18 -07004889{
4890 struct target_mcontext *mcp;
4891 target_ulong mcp_addr;
4892 sigset_t blocked;
Anthony Liguoric227f092009-10-01 16:12:16 -05004893 target_sigset_t set;
Nathan Froydbcd49332009-05-12 19:13:18 -07004894
Aurelien Jarno60e99242010-03-29 02:12:51 +02004895 if (copy_from_user(&set, h2g(ucp) + offsetof(struct target_ucontext, tuc_sigmask),
Nathan Froydbcd49332009-05-12 19:13:18 -07004896 sizeof (set)))
4897 return 1;
4898
Tom Musta19774ec2014-06-30 08:13:40 -05004899#if defined(TARGET_PPC64)
4900 mcp_addr = h2g(ucp) +
4901 offsetof(struct target_ucontext, tuc_sigcontext.mcontext);
4902#else
Riku Voipio9e918dc2014-04-23 14:05:09 +03004903 __get_user(mcp_addr, &ucp->tuc_regs);
Tom Musta19774ec2014-06-30 08:13:40 -05004904#endif
Nathan Froydbcd49332009-05-12 19:13:18 -07004905
4906 if (!lock_user_struct(VERIFY_READ, mcp, mcp_addr, 1))
4907 return 1;
4908
4909 target_to_host_sigset_internal(&blocked, &set);
Alex Barcelo1c275922014-03-14 14:36:55 +00004910 do_sigprocmask(SIG_SETMASK, &blocked, NULL);
Riku Voipioc650c002014-04-23 13:53:45 +03004911 restore_user_regs(env, mcp, sig);
Nathan Froydbcd49332009-05-12 19:13:18 -07004912
4913 unlock_user_struct(mcp, mcp_addr, 1);
4914 return 0;
Nathan Froydbcd49332009-05-12 19:13:18 -07004915}
4916
Andreas Färber05390242012-02-25 03:37:53 +01004917long do_rt_sigreturn(CPUPPCState *env)
Nathan Froydbcd49332009-05-12 19:13:18 -07004918{
4919 struct target_rt_sigframe *rt_sf = NULL;
4920 target_ulong rt_sf_addr;
4921
4922 rt_sf_addr = env->gpr[1] + SIGNAL_FRAMESIZE + 16;
4923 if (!lock_user_struct(VERIFY_READ, rt_sf, rt_sf_addr, 1))
4924 goto sigsegv;
4925
4926 if (do_setcontext(&rt_sf->uc, env, 1))
4927 goto sigsegv;
4928
4929 do_sigaltstack(rt_sf_addr
Aurelien Jarno60e99242010-03-29 02:12:51 +02004930 + offsetof(struct target_rt_sigframe, uc.tuc_stack),
Nathan Froydbcd49332009-05-12 19:13:18 -07004931 0, env->gpr[1]);
4932
4933 unlock_user_struct(rt_sf, rt_sf_addr, 1);
4934 return -TARGET_QEMU_ESIGRETURN;
4935
4936sigsegv:
4937 unlock_user_struct(rt_sf, rt_sf_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02004938 force_sig(TARGET_SIGSEGV);
Nathan Froydbcd49332009-05-12 19:13:18 -07004939 return 0;
4940}
4941
Laurent Vivier492a8742009-08-03 16:12:17 +02004942#elif defined(TARGET_M68K)
4943
4944struct target_sigcontext {
4945 abi_ulong sc_mask;
4946 abi_ulong sc_usp;
4947 abi_ulong sc_d0;
4948 abi_ulong sc_d1;
4949 abi_ulong sc_a0;
4950 abi_ulong sc_a1;
4951 unsigned short sc_sr;
4952 abi_ulong sc_pc;
4953};
4954
4955struct target_sigframe
4956{
4957 abi_ulong pretcode;
4958 int sig;
4959 int code;
4960 abi_ulong psc;
4961 char retcode[8];
4962 abi_ulong extramask[TARGET_NSIG_WORDS-1];
4963 struct target_sigcontext sc;
4964};
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01004965
Anthony Liguoric227f092009-10-01 16:12:16 -05004966typedef int target_greg_t;
Laurent Vivier71811552009-08-03 16:12:18 +02004967#define TARGET_NGREG 18
Anthony Liguoric227f092009-10-01 16:12:16 -05004968typedef target_greg_t target_gregset_t[TARGET_NGREG];
Laurent Vivier71811552009-08-03 16:12:18 +02004969
4970typedef struct target_fpregset {
4971 int f_fpcntl[3];
4972 int f_fpregs[8*3];
Anthony Liguoric227f092009-10-01 16:12:16 -05004973} target_fpregset_t;
Laurent Vivier71811552009-08-03 16:12:18 +02004974
4975struct target_mcontext {
4976 int version;
Anthony Liguoric227f092009-10-01 16:12:16 -05004977 target_gregset_t gregs;
4978 target_fpregset_t fpregs;
Laurent Vivier71811552009-08-03 16:12:18 +02004979};
4980
4981#define TARGET_MCONTEXT_VERSION 2
4982
4983struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02004984 abi_ulong tuc_flags;
4985 abi_ulong tuc_link;
4986 target_stack_t tuc_stack;
4987 struct target_mcontext tuc_mcontext;
4988 abi_long tuc_filler[80];
4989 target_sigset_t tuc_sigmask;
Laurent Vivier71811552009-08-03 16:12:18 +02004990};
4991
4992struct target_rt_sigframe
4993{
4994 abi_ulong pretcode;
4995 int sig;
4996 abi_ulong pinfo;
4997 abi_ulong puc;
4998 char retcode[8];
4999 struct target_siginfo info;
5000 struct target_ucontext uc;
5001};
Laurent Vivier492a8742009-08-03 16:12:17 +02005002
Riku Voipio41ecc722014-04-23 11:01:00 +03005003static void setup_sigcontext(struct target_sigcontext *sc, CPUM68KState *env,
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01005004 abi_ulong mask)
Laurent Vivier492a8742009-08-03 16:12:17 +02005005{
Riku Voipio1d8b5122014-04-23 10:26:05 +03005006 __put_user(mask, &sc->sc_mask);
5007 __put_user(env->aregs[7], &sc->sc_usp);
5008 __put_user(env->dregs[0], &sc->sc_d0);
5009 __put_user(env->dregs[1], &sc->sc_d1);
5010 __put_user(env->aregs[0], &sc->sc_a0);
5011 __put_user(env->aregs[1], &sc->sc_a1);
5012 __put_user(env->sr, &sc->sc_sr);
5013 __put_user(env->pc, &sc->sc_pc);
Laurent Vivier492a8742009-08-03 16:12:17 +02005014}
5015
Riku Voipio016d2e12014-04-23 11:19:48 +03005016static void
Andreas Färber05390242012-02-25 03:37:53 +01005017restore_sigcontext(CPUM68KState *env, struct target_sigcontext *sc, int *pd0)
Laurent Vivier492a8742009-08-03 16:12:17 +02005018{
Laurent Vivier492a8742009-08-03 16:12:17 +02005019 int temp;
5020
Riku Voipio1d8b5122014-04-23 10:26:05 +03005021 __get_user(env->aregs[7], &sc->sc_usp);
5022 __get_user(env->dregs[1], &sc->sc_d1);
5023 __get_user(env->aregs[0], &sc->sc_a0);
5024 __get_user(env->aregs[1], &sc->sc_a1);
5025 __get_user(env->pc, &sc->sc_pc);
5026 __get_user(temp, &sc->sc_sr);
Laurent Vivier492a8742009-08-03 16:12:17 +02005027 env->sr = (env->sr & 0xff00) | (temp & 0xff);
5028
5029 *pd0 = tswapl(sc->sc_d0);
Laurent Vivier492a8742009-08-03 16:12:17 +02005030}
5031
5032/*
5033 * Determine which stack to use..
5034 */
5035static inline abi_ulong
Andreas Färber05390242012-02-25 03:37:53 +01005036get_sigframe(struct target_sigaction *ka, CPUM68KState *regs,
5037 size_t frame_size)
Laurent Vivier492a8742009-08-03 16:12:17 +02005038{
5039 unsigned long sp;
5040
5041 sp = regs->aregs[7];
5042
5043 /* This is the X/Open sanctioned signal stack switching. */
5044 if ((ka->sa_flags & TARGET_SA_ONSTACK) && (sas_ss_flags (sp) == 0)) {
5045 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
5046 }
5047
5048 return ((sp - frame_size) & -8UL);
5049}
5050
5051static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01005052 target_sigset_t *set, CPUM68KState *env)
Laurent Vivier492a8742009-08-03 16:12:17 +02005053{
5054 struct target_sigframe *frame;
5055 abi_ulong frame_addr;
5056 abi_ulong retcode_addr;
5057 abi_ulong sc_addr;
Laurent Vivier492a8742009-08-03 16:12:17 +02005058 int i;
5059
5060 frame_addr = get_sigframe(ka, env, sizeof *frame);
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01005061 trace_user_setup_frame(env, frame_addr);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01005062 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
5063 goto give_sigsegv;
5064 }
Laurent Vivier492a8742009-08-03 16:12:17 +02005065
Riku Voipio1d8b5122014-04-23 10:26:05 +03005066 __put_user(sig, &frame->sig);
Laurent Vivier492a8742009-08-03 16:12:17 +02005067
5068 sc_addr = frame_addr + offsetof(struct target_sigframe, sc);
Riku Voipio1d8b5122014-04-23 10:26:05 +03005069 __put_user(sc_addr, &frame->psc);
Laurent Vivier492a8742009-08-03 16:12:17 +02005070
Riku Voipio41ecc722014-04-23 11:01:00 +03005071 setup_sigcontext(&frame->sc, env, set->sig[0]);
Laurent Vivier492a8742009-08-03 16:12:17 +02005072
5073 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
Riku Voipio0188fad2014-04-23 13:34:15 +03005074 __put_user(set->sig[i], &frame->extramask[i - 1]);
Laurent Vivier492a8742009-08-03 16:12:17 +02005075 }
5076
5077 /* Set up to return from userspace. */
5078
5079 retcode_addr = frame_addr + offsetof(struct target_sigframe, retcode);
Riku Voipio1d8b5122014-04-23 10:26:05 +03005080 __put_user(retcode_addr, &frame->pretcode);
Laurent Vivier492a8742009-08-03 16:12:17 +02005081
5082 /* moveq #,d0; trap #0 */
5083
Riku Voipio1d8b5122014-04-23 10:26:05 +03005084 __put_user(0x70004e40 + (TARGET_NR_sigreturn << 16),
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01005085 (uint32_t *)(frame->retcode));
Laurent Vivier492a8742009-08-03 16:12:17 +02005086
Laurent Vivier492a8742009-08-03 16:12:17 +02005087 /* Set up to return from userspace */
5088
5089 env->aregs[7] = frame_addr;
5090 env->pc = ka->_sa_handler;
5091
5092 unlock_user_struct(frame, frame_addr, 1);
5093 return;
5094
5095give_sigsegv:
Riku Voipio66393fb2009-12-04 15:16:32 +02005096 force_sig(TARGET_SIGSEGV);
Laurent Vivier492a8742009-08-03 16:12:17 +02005097}
5098
Laurent Vivier71811552009-08-03 16:12:18 +02005099static inline int target_rt_setup_ucontext(struct target_ucontext *uc,
Andreas Färber05390242012-02-25 03:37:53 +01005100 CPUM68KState *env)
Laurent Vivier71811552009-08-03 16:12:18 +02005101{
Aurelien Jarno60e99242010-03-29 02:12:51 +02005102 target_greg_t *gregs = uc->tuc_mcontext.gregs;
Laurent Vivier71811552009-08-03 16:12:18 +02005103
Riku Voipio1d8b5122014-04-23 10:26:05 +03005104 __put_user(TARGET_MCONTEXT_VERSION, &uc->tuc_mcontext.version);
5105 __put_user(env->dregs[0], &gregs[0]);
5106 __put_user(env->dregs[1], &gregs[1]);
5107 __put_user(env->dregs[2], &gregs[2]);
5108 __put_user(env->dregs[3], &gregs[3]);
5109 __put_user(env->dregs[4], &gregs[4]);
5110 __put_user(env->dregs[5], &gregs[5]);
5111 __put_user(env->dregs[6], &gregs[6]);
5112 __put_user(env->dregs[7], &gregs[7]);
5113 __put_user(env->aregs[0], &gregs[8]);
5114 __put_user(env->aregs[1], &gregs[9]);
5115 __put_user(env->aregs[2], &gregs[10]);
5116 __put_user(env->aregs[3], &gregs[11]);
5117 __put_user(env->aregs[4], &gregs[12]);
5118 __put_user(env->aregs[5], &gregs[13]);
5119 __put_user(env->aregs[6], &gregs[14]);
5120 __put_user(env->aregs[7], &gregs[15]);
5121 __put_user(env->pc, &gregs[16]);
5122 __put_user(env->sr, &gregs[17]);
Laurent Vivier71811552009-08-03 16:12:18 +02005123
Riku Voipio1d8b5122014-04-23 10:26:05 +03005124 return 0;
Laurent Vivier71811552009-08-03 16:12:18 +02005125}
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01005126
Andreas Färber05390242012-02-25 03:37:53 +01005127static inline int target_rt_restore_ucontext(CPUM68KState *env,
Laurent Vivier71811552009-08-03 16:12:18 +02005128 struct target_ucontext *uc,
5129 int *pd0)
5130{
5131 int temp;
Aurelien Jarno60e99242010-03-29 02:12:51 +02005132 target_greg_t *gregs = uc->tuc_mcontext.gregs;
Laurent Vivier71811552009-08-03 16:12:18 +02005133
Riku Voipio1d8b5122014-04-23 10:26:05 +03005134 __get_user(temp, &uc->tuc_mcontext.version);
Laurent Vivier71811552009-08-03 16:12:18 +02005135 if (temp != TARGET_MCONTEXT_VERSION)
5136 goto badframe;
5137
5138 /* restore passed registers */
Riku Voipio1d8b5122014-04-23 10:26:05 +03005139 __get_user(env->dregs[0], &gregs[0]);
5140 __get_user(env->dregs[1], &gregs[1]);
5141 __get_user(env->dregs[2], &gregs[2]);
5142 __get_user(env->dregs[3], &gregs[3]);
5143 __get_user(env->dregs[4], &gregs[4]);
5144 __get_user(env->dregs[5], &gregs[5]);
5145 __get_user(env->dregs[6], &gregs[6]);
5146 __get_user(env->dregs[7], &gregs[7]);
5147 __get_user(env->aregs[0], &gregs[8]);
5148 __get_user(env->aregs[1], &gregs[9]);
5149 __get_user(env->aregs[2], &gregs[10]);
5150 __get_user(env->aregs[3], &gregs[11]);
5151 __get_user(env->aregs[4], &gregs[12]);
5152 __get_user(env->aregs[5], &gregs[13]);
5153 __get_user(env->aregs[6], &gregs[14]);
5154 __get_user(env->aregs[7], &gregs[15]);
5155 __get_user(env->pc, &gregs[16]);
5156 __get_user(temp, &gregs[17]);
Laurent Vivier71811552009-08-03 16:12:18 +02005157 env->sr = (env->sr & 0xff00) | (temp & 0xff);
5158
5159 *pd0 = env->dregs[0];
Riku Voipio1d8b5122014-04-23 10:26:05 +03005160 return 0;
Laurent Vivier71811552009-08-03 16:12:18 +02005161
5162badframe:
5163 return 1;
5164}
5165
Laurent Vivier492a8742009-08-03 16:12:17 +02005166static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05005167 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01005168 target_sigset_t *set, CPUM68KState *env)
Laurent Vivier492a8742009-08-03 16:12:17 +02005169{
Laurent Vivier71811552009-08-03 16:12:18 +02005170 struct target_rt_sigframe *frame;
5171 abi_ulong frame_addr;
5172 abi_ulong retcode_addr;
5173 abi_ulong info_addr;
5174 abi_ulong uc_addr;
5175 int err = 0;
5176 int i;
5177
5178 frame_addr = get_sigframe(ka, env, sizeof *frame);
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01005179 trace_user_setup_rt_frame(env, frame_addr);
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01005180 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
5181 goto give_sigsegv;
5182 }
Laurent Vivier71811552009-08-03 16:12:18 +02005183
Riku Voipio1d8b5122014-04-23 10:26:05 +03005184 __put_user(sig, &frame->sig);
Laurent Vivier71811552009-08-03 16:12:18 +02005185
5186 info_addr = frame_addr + offsetof(struct target_rt_sigframe, info);
Riku Voipio1d8b5122014-04-23 10:26:05 +03005187 __put_user(info_addr, &frame->pinfo);
Laurent Vivier71811552009-08-03 16:12:18 +02005188
5189 uc_addr = frame_addr + offsetof(struct target_rt_sigframe, uc);
Riku Voipio1d8b5122014-04-23 10:26:05 +03005190 __put_user(uc_addr, &frame->puc);
Laurent Vivier71811552009-08-03 16:12:18 +02005191
Peter Maydellf6c7a052015-01-08 12:19:48 +00005192 tswap_siginfo(&frame->info, info);
Laurent Vivier71811552009-08-03 16:12:18 +02005193
5194 /* Create the ucontext */
5195
Riku Voipio1d8b5122014-04-23 10:26:05 +03005196 __put_user(0, &frame->uc.tuc_flags);
5197 __put_user(0, &frame->uc.tuc_link);
5198 __put_user(target_sigaltstack_used.ss_sp,
5199 &frame->uc.tuc_stack.ss_sp);
5200 __put_user(sas_ss_flags(env->aregs[7]),
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01005201 &frame->uc.tuc_stack.ss_flags);
Riku Voipio1d8b5122014-04-23 10:26:05 +03005202 __put_user(target_sigaltstack_used.ss_size,
5203 &frame->uc.tuc_stack.ss_size);
Laurent Vivier71811552009-08-03 16:12:18 +02005204 err |= target_rt_setup_ucontext(&frame->uc, env);
5205
5206 if (err)
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01005207 goto give_sigsegv;
Laurent Vivier71811552009-08-03 16:12:18 +02005208
5209 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
Riku Voipio0188fad2014-04-23 13:34:15 +03005210 __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
Laurent Vivier71811552009-08-03 16:12:18 +02005211 }
5212
5213 /* Set up to return from userspace. */
5214
5215 retcode_addr = frame_addr + offsetof(struct target_sigframe, retcode);
Riku Voipio1d8b5122014-04-23 10:26:05 +03005216 __put_user(retcode_addr, &frame->pretcode);
Laurent Vivier71811552009-08-03 16:12:18 +02005217
5218 /* moveq #,d0; notb d0; trap #0 */
5219
Riku Voipio1d8b5122014-04-23 10:26:05 +03005220 __put_user(0x70004600 + ((TARGET_NR_rt_sigreturn ^ 0xff) << 16),
Peter Maydell1669add2014-12-22 17:47:00 +00005221 (uint32_t *)(frame->retcode + 0));
5222 __put_user(0x4e40, (uint16_t *)(frame->retcode + 4));
Laurent Vivier71811552009-08-03 16:12:18 +02005223
5224 if (err)
5225 goto give_sigsegv;
5226
5227 /* Set up to return from userspace */
5228
5229 env->aregs[7] = frame_addr;
5230 env->pc = ka->_sa_handler;
5231
5232 unlock_user_struct(frame, frame_addr, 1);
5233 return;
5234
5235give_sigsegv:
5236 unlock_user_struct(frame, frame_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02005237 force_sig(TARGET_SIGSEGV);
Laurent Vivier492a8742009-08-03 16:12:17 +02005238}
5239
Andreas Färber05390242012-02-25 03:37:53 +01005240long do_sigreturn(CPUM68KState *env)
Laurent Vivier492a8742009-08-03 16:12:17 +02005241{
5242 struct target_sigframe *frame;
5243 abi_ulong frame_addr = env->aregs[7] - 4;
Anthony Liguoric227f092009-10-01 16:12:16 -05005244 target_sigset_t target_set;
Laurent Vivier492a8742009-08-03 16:12:17 +02005245 sigset_t set;
5246 int d0, i;
5247
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01005248 trace_user_do_sigreturn(env, frame_addr);
Laurent Vivier492a8742009-08-03 16:12:17 +02005249 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
5250 goto badframe;
5251
5252 /* set blocked signals */
5253
Riku Voipiof5f601a2014-04-23 13:00:17 +03005254 __get_user(target_set.sig[0], &frame->sc.sc_mask);
Laurent Vivier492a8742009-08-03 16:12:17 +02005255
5256 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
Riku Voipiof5f601a2014-04-23 13:00:17 +03005257 __get_user(target_set.sig[i], &frame->extramask[i - 1]);
Laurent Vivier492a8742009-08-03 16:12:17 +02005258 }
5259
5260 target_to_host_sigset_internal(&set, &target_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00005261 do_sigprocmask(SIG_SETMASK, &set, NULL);
Laurent Vivier492a8742009-08-03 16:12:17 +02005262
5263 /* restore registers */
5264
Riku Voipio016d2e12014-04-23 11:19:48 +03005265 restore_sigcontext(env, &frame->sc, &d0);
Laurent Vivier492a8742009-08-03 16:12:17 +02005266
5267 unlock_user_struct(frame, frame_addr, 0);
5268 return d0;
5269
5270badframe:
Laurent Vivier492a8742009-08-03 16:12:17 +02005271 force_sig(TARGET_SIGSEGV);
5272 return 0;
5273}
5274
Andreas Färber05390242012-02-25 03:37:53 +01005275long do_rt_sigreturn(CPUM68KState *env)
Laurent Vivier492a8742009-08-03 16:12:17 +02005276{
Laurent Vivier71811552009-08-03 16:12:18 +02005277 struct target_rt_sigframe *frame;
5278 abi_ulong frame_addr = env->aregs[7] - 4;
Anthony Liguoric227f092009-10-01 16:12:16 -05005279 target_sigset_t target_set;
Laurent Vivier71811552009-08-03 16:12:18 +02005280 sigset_t set;
5281 int d0;
5282
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01005283 trace_user_do_rt_sigreturn(env, frame_addr);
Laurent Vivier71811552009-08-03 16:12:18 +02005284 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
5285 goto badframe;
5286
5287 target_to_host_sigset_internal(&set, &target_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00005288 do_sigprocmask(SIG_SETMASK, &set, NULL);
Laurent Vivier71811552009-08-03 16:12:18 +02005289
5290 /* restore registers */
5291
5292 if (target_rt_restore_ucontext(env, &frame->uc, &d0))
5293 goto badframe;
5294
5295 if (do_sigaltstack(frame_addr +
Aurelien Jarno60e99242010-03-29 02:12:51 +02005296 offsetof(struct target_rt_sigframe, uc.tuc_stack),
Laurent Vivier71811552009-08-03 16:12:18 +02005297 0, get_sp_from_cpustate(env)) == -EFAULT)
5298 goto badframe;
5299
5300 unlock_user_struct(frame, frame_addr, 0);
5301 return d0;
5302
5303badframe:
5304 unlock_user_struct(frame, frame_addr, 0);
5305 force_sig(TARGET_SIGSEGV);
5306 return 0;
Laurent Vivier492a8742009-08-03 16:12:17 +02005307}
5308
Richard Henderson6049f4f2009-12-27 18:30:03 -08005309#elif defined(TARGET_ALPHA)
5310
5311struct target_sigcontext {
5312 abi_long sc_onstack;
5313 abi_long sc_mask;
5314 abi_long sc_pc;
5315 abi_long sc_ps;
5316 abi_long sc_regs[32];
5317 abi_long sc_ownedfp;
5318 abi_long sc_fpregs[32];
5319 abi_ulong sc_fpcr;
5320 abi_ulong sc_fp_control;
5321 abi_ulong sc_reserved1;
5322 abi_ulong sc_reserved2;
5323 abi_ulong sc_ssize;
5324 abi_ulong sc_sbase;
5325 abi_ulong sc_traparg_a0;
5326 abi_ulong sc_traparg_a1;
5327 abi_ulong sc_traparg_a2;
5328 abi_ulong sc_fp_trap_pc;
5329 abi_ulong sc_fp_trigger_sum;
5330 abi_ulong sc_fp_trigger_inst;
5331};
5332
5333struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02005334 abi_ulong tuc_flags;
5335 abi_ulong tuc_link;
5336 abi_ulong tuc_osf_sigmask;
5337 target_stack_t tuc_stack;
5338 struct target_sigcontext tuc_mcontext;
5339 target_sigset_t tuc_sigmask;
Richard Henderson6049f4f2009-12-27 18:30:03 -08005340};
5341
5342struct target_sigframe {
5343 struct target_sigcontext sc;
5344 unsigned int retcode[3];
5345};
5346
5347struct target_rt_sigframe {
5348 target_siginfo_t info;
5349 struct target_ucontext uc;
5350 unsigned int retcode[3];
5351};
5352
5353#define INSN_MOV_R30_R16 0x47fe0410
5354#define INSN_LDI_R0 0x201f0000
5355#define INSN_CALLSYS 0x00000083
5356
Riku Voipio41ecc722014-04-23 11:01:00 +03005357static void setup_sigcontext(struct target_sigcontext *sc, CPUAlphaState *env,
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01005358 abi_ulong frame_addr, target_sigset_t *set)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005359{
Riku Voipio41ecc722014-04-23 11:01:00 +03005360 int i;
Richard Henderson6049f4f2009-12-27 18:30:03 -08005361
Riku Voipio1d8b5122014-04-23 10:26:05 +03005362 __put_user(on_sig_stack(frame_addr), &sc->sc_onstack);
5363 __put_user(set->sig[0], &sc->sc_mask);
5364 __put_user(env->pc, &sc->sc_pc);
5365 __put_user(8, &sc->sc_ps);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005366
5367 for (i = 0; i < 31; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03005368 __put_user(env->ir[i], &sc->sc_regs[i]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005369 }
Riku Voipio1d8b5122014-04-23 10:26:05 +03005370 __put_user(0, &sc->sc_regs[31]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005371
5372 for (i = 0; i < 31; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03005373 __put_user(env->fir[i], &sc->sc_fpregs[i]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005374 }
Riku Voipio1d8b5122014-04-23 10:26:05 +03005375 __put_user(0, &sc->sc_fpregs[31]);
5376 __put_user(cpu_alpha_load_fpcr(env), &sc->sc_fpcr);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005377
Riku Voipio1d8b5122014-04-23 10:26:05 +03005378 __put_user(0, &sc->sc_traparg_a0); /* FIXME */
5379 __put_user(0, &sc->sc_traparg_a1); /* FIXME */
5380 __put_user(0, &sc->sc_traparg_a2); /* FIXME */
Richard Henderson6049f4f2009-12-27 18:30:03 -08005381}
5382
Riku Voipio016d2e12014-04-23 11:19:48 +03005383static void restore_sigcontext(CPUAlphaState *env,
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01005384 struct target_sigcontext *sc)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005385{
5386 uint64_t fpcr;
Riku Voipio016d2e12014-04-23 11:19:48 +03005387 int i;
Richard Henderson6049f4f2009-12-27 18:30:03 -08005388
Riku Voipio1d8b5122014-04-23 10:26:05 +03005389 __get_user(env->pc, &sc->sc_pc);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005390
5391 for (i = 0; i < 31; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03005392 __get_user(env->ir[i], &sc->sc_regs[i]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005393 }
5394 for (i = 0; i < 31; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03005395 __get_user(env->fir[i], &sc->sc_fpregs[i]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005396 }
5397
Riku Voipio1d8b5122014-04-23 10:26:05 +03005398 __get_user(fpcr, &sc->sc_fpcr);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005399 cpu_alpha_store_fpcr(env, fpcr);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005400}
5401
5402static inline abi_ulong get_sigframe(struct target_sigaction *sa,
Andreas Färber05390242012-02-25 03:37:53 +01005403 CPUAlphaState *env,
5404 unsigned long framesize)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005405{
5406 abi_ulong sp = env->ir[IR_SP];
5407
5408 /* This is the X/Open sanctioned signal stack switching. */
5409 if ((sa->sa_flags & TARGET_SA_ONSTACK) != 0 && !sas_ss_flags(sp)) {
5410 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
5411 }
5412 return (sp - framesize) & -32;
5413}
5414
5415static void setup_frame(int sig, struct target_sigaction *ka,
Andreas Färber05390242012-02-25 03:37:53 +01005416 target_sigset_t *set, CPUAlphaState *env)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005417{
5418 abi_ulong frame_addr, r26;
5419 struct target_sigframe *frame;
5420 int err = 0;
5421
5422 frame_addr = get_sigframe(ka, env, sizeof(*frame));
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01005423 trace_user_setup_frame(env, frame_addr);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005424 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
5425 goto give_sigsegv;
5426 }
5427
Riku Voipio41ecc722014-04-23 11:01:00 +03005428 setup_sigcontext(&frame->sc, env, frame_addr, set);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005429
5430 if (ka->sa_restorer) {
5431 r26 = ka->sa_restorer;
5432 } else {
Riku Voipio1d8b5122014-04-23 10:26:05 +03005433 __put_user(INSN_MOV_R30_R16, &frame->retcode[0]);
5434 __put_user(INSN_LDI_R0 + TARGET_NR_sigreturn,
5435 &frame->retcode[1]);
5436 __put_user(INSN_CALLSYS, &frame->retcode[2]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005437 /* imb() */
5438 r26 = frame_addr;
5439 }
5440
5441 unlock_user_struct(frame, frame_addr, 1);
5442
5443 if (err) {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01005444give_sigsegv:
Richard Henderson6049f4f2009-12-27 18:30:03 -08005445 if (sig == TARGET_SIGSEGV) {
5446 ka->_sa_handler = TARGET_SIG_DFL;
5447 }
5448 force_sig(TARGET_SIGSEGV);
5449 }
5450
5451 env->ir[IR_RA] = r26;
5452 env->ir[IR_PV] = env->pc = ka->_sa_handler;
5453 env->ir[IR_A0] = sig;
5454 env->ir[IR_A1] = 0;
5455 env->ir[IR_A2] = frame_addr + offsetof(struct target_sigframe, sc);
5456 env->ir[IR_SP] = frame_addr;
5457}
5458
5459static void setup_rt_frame(int sig, struct target_sigaction *ka,
5460 target_siginfo_t *info,
Andreas Färber05390242012-02-25 03:37:53 +01005461 target_sigset_t *set, CPUAlphaState *env)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005462{
5463 abi_ulong frame_addr, r26;
5464 struct target_rt_sigframe *frame;
5465 int i, err = 0;
5466
5467 frame_addr = get_sigframe(ka, env, sizeof(*frame));
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01005468 trace_user_setup_rt_frame(env, frame_addr);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005469 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
5470 goto give_sigsegv;
5471 }
5472
Peter Maydellf6c7a052015-01-08 12:19:48 +00005473 tswap_siginfo(&frame->info, info);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005474
Riku Voipio1d8b5122014-04-23 10:26:05 +03005475 __put_user(0, &frame->uc.tuc_flags);
5476 __put_user(0, &frame->uc.tuc_link);
5477 __put_user(set->sig[0], &frame->uc.tuc_osf_sigmask);
5478 __put_user(target_sigaltstack_used.ss_sp,
5479 &frame->uc.tuc_stack.ss_sp);
5480 __put_user(sas_ss_flags(env->ir[IR_SP]),
5481 &frame->uc.tuc_stack.ss_flags);
5482 __put_user(target_sigaltstack_used.ss_size,
5483 &frame->uc.tuc_stack.ss_size);
Riku Voipio41ecc722014-04-23 11:01:00 +03005484 setup_sigcontext(&frame->uc.tuc_mcontext, env, frame_addr, set);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005485 for (i = 0; i < TARGET_NSIG_WORDS; ++i) {
Riku Voipio1d8b5122014-04-23 10:26:05 +03005486 __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005487 }
5488
5489 if (ka->sa_restorer) {
5490 r26 = ka->sa_restorer;
5491 } else {
Riku Voipio1d8b5122014-04-23 10:26:05 +03005492 __put_user(INSN_MOV_R30_R16, &frame->retcode[0]);
5493 __put_user(INSN_LDI_R0 + TARGET_NR_rt_sigreturn,
5494 &frame->retcode[1]);
5495 __put_user(INSN_CALLSYS, &frame->retcode[2]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005496 /* imb(); */
5497 r26 = frame_addr;
5498 }
5499
5500 if (err) {
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01005501give_sigsegv:
5502 if (sig == TARGET_SIGSEGV) {
Richard Henderson6049f4f2009-12-27 18:30:03 -08005503 ka->_sa_handler = TARGET_SIG_DFL;
5504 }
5505 force_sig(TARGET_SIGSEGV);
5506 }
5507
5508 env->ir[IR_RA] = r26;
5509 env->ir[IR_PV] = env->pc = ka->_sa_handler;
5510 env->ir[IR_A0] = sig;
5511 env->ir[IR_A1] = frame_addr + offsetof(struct target_rt_sigframe, info);
5512 env->ir[IR_A2] = frame_addr + offsetof(struct target_rt_sigframe, uc);
5513 env->ir[IR_SP] = frame_addr;
5514}
5515
Andreas Färber05390242012-02-25 03:37:53 +01005516long do_sigreturn(CPUAlphaState *env)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005517{
5518 struct target_sigcontext *sc;
5519 abi_ulong sc_addr = env->ir[IR_A0];
5520 target_sigset_t target_set;
5521 sigset_t set;
5522
5523 if (!lock_user_struct(VERIFY_READ, sc, sc_addr, 1)) {
5524 goto badframe;
5525 }
5526
5527 target_sigemptyset(&target_set);
Riku Voipiof5f601a2014-04-23 13:00:17 +03005528 __get_user(target_set.sig[0], &sc->sc_mask);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005529
5530 target_to_host_sigset_internal(&set, &target_set);
Alex Barcelo1c275922014-03-14 14:36:55 +00005531 do_sigprocmask(SIG_SETMASK, &set, NULL);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005532
Riku Voipio016d2e12014-04-23 11:19:48 +03005533 restore_sigcontext(env, sc);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005534 unlock_user_struct(sc, sc_addr, 0);
5535 return env->ir[IR_V0];
5536
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01005537badframe:
Richard Henderson6049f4f2009-12-27 18:30:03 -08005538 force_sig(TARGET_SIGSEGV);
5539}
5540
Andreas Färber05390242012-02-25 03:37:53 +01005541long do_rt_sigreturn(CPUAlphaState *env)
Richard Henderson6049f4f2009-12-27 18:30:03 -08005542{
5543 abi_ulong frame_addr = env->ir[IR_A0];
5544 struct target_rt_sigframe *frame;
5545 sigset_t set;
5546
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01005547 trace_user_do_rt_sigreturn(env, frame_addr);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005548 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
5549 goto badframe;
5550 }
Aurelien Jarno60e99242010-03-29 02:12:51 +02005551 target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
Alex Barcelo1c275922014-03-14 14:36:55 +00005552 do_sigprocmask(SIG_SETMASK, &set, NULL);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005553
Riku Voipio016d2e12014-04-23 11:19:48 +03005554 restore_sigcontext(env, &frame->uc.tuc_mcontext);
Richard Henderson6049f4f2009-12-27 18:30:03 -08005555 if (do_sigaltstack(frame_addr + offsetof(struct target_rt_sigframe,
Aurelien Jarno60e99242010-03-29 02:12:51 +02005556 uc.tuc_stack),
Richard Henderson6049f4f2009-12-27 18:30:03 -08005557 0, env->ir[IR_SP]) == -EFAULT) {
5558 goto badframe;
5559 }
5560
5561 unlock_user_struct(frame, frame_addr, 0);
5562 return env->ir[IR_V0];
5563
5564
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01005565badframe:
Richard Henderson6049f4f2009-12-27 18:30:03 -08005566 unlock_user_struct(frame, frame_addr, 0);
5567 force_sig(TARGET_SIGSEGV);
5568}
5569
Chen Gangbf0f60a2015-09-27 08:10:18 +08005570#elif defined(TARGET_TILEGX)
5571
5572struct target_sigcontext {
5573 union {
5574 /* General-purpose registers. */
5575 abi_ulong gregs[56];
5576 struct {
5577 abi_ulong __gregs[53];
5578 abi_ulong tp; /* Aliases gregs[TREG_TP]. */
5579 abi_ulong sp; /* Aliases gregs[TREG_SP]. */
5580 abi_ulong lr; /* Aliases gregs[TREG_LR]. */
5581 };
5582 };
5583 abi_ulong pc; /* Program counter. */
5584 abi_ulong ics; /* In Interrupt Critical Section? */
5585 abi_ulong faultnum; /* Fault number. */
5586 abi_ulong pad[5];
5587};
5588
5589struct target_ucontext {
5590 abi_ulong tuc_flags;
5591 abi_ulong tuc_link;
5592 target_stack_t tuc_stack;
5593 struct target_sigcontext tuc_mcontext;
5594 target_sigset_t tuc_sigmask; /* mask last for extensibility */
5595};
5596
5597struct target_rt_sigframe {
5598 unsigned char save_area[16]; /* caller save area */
5599 struct target_siginfo info;
5600 struct target_ucontext uc;
5601};
5602
5603static void setup_sigcontext(struct target_sigcontext *sc,
5604 CPUArchState *env, int signo)
5605{
5606 int i;
5607
5608 for (i = 0; i < TILEGX_R_COUNT; ++i) {
5609 __put_user(env->regs[i], &sc->gregs[i]);
5610 }
5611
5612 __put_user(env->pc, &sc->pc);
5613 __put_user(0, &sc->ics);
5614 __put_user(signo, &sc->faultnum);
5615}
5616
5617static void restore_sigcontext(CPUTLGState *env, struct target_sigcontext *sc)
5618{
5619 int i;
5620
5621 for (i = 0; i < TILEGX_R_COUNT; ++i) {
5622 __get_user(env->regs[i], &sc->gregs[i]);
5623 }
5624
5625 __get_user(env->pc, &sc->pc);
5626}
5627
5628static abi_ulong get_sigframe(struct target_sigaction *ka, CPUArchState *env,
5629 size_t frame_size)
5630{
5631 unsigned long sp = env->regs[TILEGX_R_SP];
5632
5633 if (on_sig_stack(sp) && !likely(on_sig_stack(sp - frame_size))) {
5634 return -1UL;
5635 }
5636
5637 if ((ka->sa_flags & SA_ONSTACK) && !sas_ss_flags(sp)) {
5638 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
5639 }
5640
5641 sp -= frame_size;
5642 sp &= -16UL;
5643 return sp;
5644}
5645
5646static void setup_rt_frame(int sig, struct target_sigaction *ka,
5647 target_siginfo_t *info,
5648 target_sigset_t *set, CPUArchState *env)
5649{
5650 abi_ulong frame_addr;
5651 struct target_rt_sigframe *frame;
5652 unsigned long restorer;
5653
5654 frame_addr = get_sigframe(ka, env, sizeof(*frame));
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01005655 trace_user_setup_rt_frame(env, frame_addr);
Chen Gangbf0f60a2015-09-27 08:10:18 +08005656 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
5657 goto give_sigsegv;
5658 }
5659
5660 /* Always write at least the signal number for the stack backtracer. */
5661 if (ka->sa_flags & TARGET_SA_SIGINFO) {
5662 /* At sigreturn time, restore the callee-save registers too. */
5663 tswap_siginfo(&frame->info, info);
5664 /* regs->flags |= PT_FLAGS_RESTORE_REGS; FIXME: we can skip it? */
5665 } else {
5666 __put_user(info->si_signo, &frame->info.si_signo);
5667 }
5668
5669 /* Create the ucontext. */
5670 __put_user(0, &frame->uc.tuc_flags);
5671 __put_user(0, &frame->uc.tuc_link);
5672 __put_user(target_sigaltstack_used.ss_sp, &frame->uc.tuc_stack.ss_sp);
5673 __put_user(sas_ss_flags(env->regs[TILEGX_R_SP]),
5674 &frame->uc.tuc_stack.ss_flags);
5675 __put_user(target_sigaltstack_used.ss_size, &frame->uc.tuc_stack.ss_size);
5676 setup_sigcontext(&frame->uc.tuc_mcontext, env, info->si_signo);
5677
5678 restorer = (unsigned long) do_rt_sigreturn;
5679 if (ka->sa_flags & TARGET_SA_RESTORER) {
5680 restorer = (unsigned long) ka->sa_restorer;
5681 }
5682 env->pc = (unsigned long) ka->_sa_handler;
5683 env->regs[TILEGX_R_SP] = (unsigned long) frame;
5684 env->regs[TILEGX_R_LR] = restorer;
5685 env->regs[0] = (unsigned long) sig;
5686 env->regs[1] = (unsigned long) &frame->info;
5687 env->regs[2] = (unsigned long) &frame->uc;
5688 /* regs->flags |= PT_FLAGS_CALLER_SAVES; FIXME: we can skip it? */
5689
5690 unlock_user_struct(frame, frame_addr, 1);
5691 return;
5692
5693give_sigsegv:
5694 if (sig == TARGET_SIGSEGV) {
5695 ka->_sa_handler = TARGET_SIG_DFL;
5696 }
5697 force_sig(TARGET_SIGSEGV /* , current */);
5698}
5699
5700long do_rt_sigreturn(CPUTLGState *env)
5701{
5702 abi_ulong frame_addr = env->regs[TILEGX_R_SP];
5703 struct target_rt_sigframe *frame;
5704 sigset_t set;
5705
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01005706 trace_user_do_rt_sigreturn(env, frame_addr);
Chen Gangbf0f60a2015-09-27 08:10:18 +08005707 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
5708 goto badframe;
5709 }
5710 target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
5711 do_sigprocmask(SIG_SETMASK, &set, NULL);
5712
5713 restore_sigcontext(env, &frame->uc.tuc_mcontext);
5714 if (do_sigaltstack(frame_addr + offsetof(struct target_rt_sigframe,
5715 uc.tuc_stack),
5716 0, env->regs[TILEGX_R_SP]) == -EFAULT) {
5717 goto badframe;
5718 }
5719
5720 unlock_user_struct(frame, frame_addr, 0);
5721 return env->regs[TILEGX_R_RE];
5722
5723
5724 badframe:
5725 unlock_user_struct(frame, frame_addr, 0);
5726 force_sig(TARGET_SIGSEGV);
5727}
5728
bellardb346ff42003-06-15 20:05:50 +00005729#else
5730
pbrook624f7972008-05-31 16:11:38 +00005731static void setup_frame(int sig, struct target_sigaction *ka,
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01005732 target_sigset_t *set, CPUArchState *env)
bellardb346ff42003-06-15 20:05:50 +00005733{
5734 fprintf(stderr, "setup_frame: not implemented\n");
5735}
5736
pbrook624f7972008-05-31 16:11:38 +00005737static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05005738 target_siginfo_t *info,
Timothy E Baldwinda7c8642016-05-12 18:47:27 +01005739 target_sigset_t *set, CPUArchState *env)
bellardb346ff42003-06-15 20:05:50 +00005740{
5741 fprintf(stderr, "setup_rt_frame: not implemented\n");
5742}
5743
Andreas Färber9349b4f2012-03-14 01:38:32 +01005744long do_sigreturn(CPUArchState *env)
bellardb346ff42003-06-15 20:05:50 +00005745{
5746 fprintf(stderr, "do_sigreturn: not implemented\n");
bellardf8b0aa22007-11-11 23:03:42 +00005747 return -TARGET_ENOSYS;
bellardb346ff42003-06-15 20:05:50 +00005748}
5749
Andreas Färber9349b4f2012-03-14 01:38:32 +01005750long do_rt_sigreturn(CPUArchState *env)
bellardb346ff42003-06-15 20:05:50 +00005751{
5752 fprintf(stderr, "do_rt_sigreturn: not implemented\n");
bellardf8b0aa22007-11-11 23:03:42 +00005753 return -TARGET_ENOSYS;
bellardb346ff42003-06-15 20:05:50 +00005754}
5755
bellard66fb9762003-03-23 01:06:05 +00005756#endif
5757
Andreas Färber9349b4f2012-03-14 01:38:32 +01005758void process_pending_signals(CPUArchState *cpu_env)
bellard66fb9762003-03-23 01:06:05 +00005759{
Andreas Färberdb6b81d2013-06-27 19:49:31 +02005760 CPUState *cpu = ENV_GET_CPU(cpu_env);
bellard66fb9762003-03-23 01:06:05 +00005761 int sig;
blueswir1992f48a2007-10-14 16:27:31 +00005762 abi_ulong handler;
bellard9de5e442003-03-23 16:49:39 +00005763 sigset_t set, old_set;
Anthony Liguoric227f092009-10-01 16:12:16 -05005764 target_sigset_t target_old_set;
pbrook624f7972008-05-31 16:11:38 +00005765 struct emulated_sigtable *k;
5766 struct target_sigaction *sa;
bellard66fb9762003-03-23 01:06:05 +00005767 struct sigqueue *q;
Andreas Färber0429a972013-08-26 18:14:44 +02005768 TaskState *ts = cpu->opaque;
ths3b46e622007-09-17 08:09:54 +00005769
pbrook624f7972008-05-31 16:11:38 +00005770 if (!ts->signal_pending)
bellard31e31b82003-02-18 22:55:36 +00005771 return;
5772
pbrook624f7972008-05-31 16:11:38 +00005773 /* FIXME: This is not threadsafe. */
5774 k = ts->sigtab;
bellard66fb9762003-03-23 01:06:05 +00005775 for(sig = 1; sig <= TARGET_NSIG; sig++) {
5776 if (k->pending)
bellard31e31b82003-02-18 22:55:36 +00005777 goto handle_signal;
bellard66fb9762003-03-23 01:06:05 +00005778 k++;
bellard31e31b82003-02-18 22:55:36 +00005779 }
5780 /* if no signal is pending, just return */
pbrook624f7972008-05-31 16:11:38 +00005781 ts->signal_pending = 0;
bellard31e31b82003-02-18 22:55:36 +00005782 return;
bellard66fb9762003-03-23 01:06:05 +00005783
bellard31e31b82003-02-18 22:55:36 +00005784 handle_signal:
Paolo Bonzinic8ee0a42015-11-13 13:52:21 +01005785 trace_user_handle_signal(cpu_env, sig);
bellard66fb9762003-03-23 01:06:05 +00005786 /* dequeue signal */
5787 q = k->first;
5788 k->first = q->next;
5789 if (!k->first)
5790 k->pending = 0;
ths3b46e622007-09-17 08:09:54 +00005791
Andreas Färberdb6b81d2013-06-27 19:49:31 +02005792 sig = gdb_handlesig(cpu, sig);
bellard1fddef42005-04-17 19:16:13 +00005793 if (!sig) {
aurel32ca587a82008-12-18 22:44:13 +00005794 sa = NULL;
5795 handler = TARGET_SIG_IGN;
5796 } else {
5797 sa = &sigact_table[sig - 1];
5798 handler = sa->_sa_handler;
bellard1fddef42005-04-17 19:16:13 +00005799 }
bellard66fb9762003-03-23 01:06:05 +00005800
Peter Maydella7ec0f92014-03-14 14:36:56 +00005801 if (ts->sigsegv_blocked && sig == TARGET_SIGSEGV) {
5802 /* Guest has blocked SIGSEGV but we got one anyway. Assume this
5803 * is a forced SIGSEGV (ie one the kernel handles via force_sig_info
5804 * because it got a real MMU fault), and treat as if default handler.
5805 */
5806 handler = TARGET_SIG_DFL;
5807 }
5808
bellard66fb9762003-03-23 01:06:05 +00005809 if (handler == TARGET_SIG_DFL) {
aurel32ca587a82008-12-18 22:44:13 +00005810 /* default handler : ignore some signal. The other are job control or fatal */
5811 if (sig == TARGET_SIGTSTP || sig == TARGET_SIGTTIN || sig == TARGET_SIGTTOU) {
5812 kill(getpid(),SIGSTOP);
5813 } else if (sig != TARGET_SIGCHLD &&
5814 sig != TARGET_SIGURG &&
5815 sig != TARGET_SIGWINCH &&
5816 sig != TARGET_SIGCONT) {
bellard66fb9762003-03-23 01:06:05 +00005817 force_sig(sig);
5818 }
5819 } else if (handler == TARGET_SIG_IGN) {
5820 /* ignore sig */
5821 } else if (handler == TARGET_SIG_ERR) {
5822 force_sig(sig);
5823 } else {
bellard9de5e442003-03-23 16:49:39 +00005824 /* compute the blocked signals during the handler execution */
pbrook624f7972008-05-31 16:11:38 +00005825 target_to_host_sigset(&set, &sa->sa_mask);
bellard9de5e442003-03-23 16:49:39 +00005826 /* SA_NODEFER indicates that the current signal should not be
5827 blocked during the handler */
pbrook624f7972008-05-31 16:11:38 +00005828 if (!(sa->sa_flags & TARGET_SA_NODEFER))
bellard9de5e442003-03-23 16:49:39 +00005829 sigaddset(&set, target_to_host_signal(sig));
ths3b46e622007-09-17 08:09:54 +00005830
bellard9de5e442003-03-23 16:49:39 +00005831 /* block signals in the handler using Linux */
Alex Barcelo1c275922014-03-14 14:36:55 +00005832 do_sigprocmask(SIG_BLOCK, &set, &old_set);
bellard9de5e442003-03-23 16:49:39 +00005833 /* save the previous blocked signal state to restore it at the
5834 end of the signal execution (see do_sigreturn) */
bellard92319442004-06-19 16:58:13 +00005835 host_to_target_sigset_internal(&target_old_set, &old_set);
bellard9de5e442003-03-23 16:49:39 +00005836
bellardbc8a22c2003-03-30 21:02:40 +00005837 /* if the CPU is in VM86 mode, we restore the 32 bit values */
j_mayer84409dd2007-04-06 08:56:50 +00005838#if defined(TARGET_I386) && !defined(TARGET_X86_64)
bellardbc8a22c2003-03-30 21:02:40 +00005839 {
5840 CPUX86State *env = cpu_env;
5841 if (env->eflags & VM_MASK)
5842 save_v86_state(env);
5843 }
5844#endif
bellard9de5e442003-03-23 16:49:39 +00005845 /* prepare the stack frame of the virtual CPU */
Chen Gangd0924a22015-09-12 23:32:30 +08005846#if defined(TARGET_ABI_MIPSN32) || defined(TARGET_ABI_MIPSN64) \
Chen Gangbf0f60a2015-09-27 08:10:18 +08005847 || defined(TARGET_OPENRISC) || defined(TARGET_TILEGX)
Richard Hendersonff970902013-02-10 10:30:42 -08005848 /* These targets do not have traditional signals. */
5849 setup_rt_frame(sig, sa, &q->info, &target_old_set, cpu_env);
5850#else
pbrook624f7972008-05-31 16:11:38 +00005851 if (sa->sa_flags & TARGET_SA_SIGINFO)
5852 setup_rt_frame(sig, sa, &q->info, &target_old_set, cpu_env);
bellard66fb9762003-03-23 01:06:05 +00005853 else
pbrook624f7972008-05-31 16:11:38 +00005854 setup_frame(sig, sa, &target_old_set, cpu_env);
Richard Hendersonff970902013-02-10 10:30:42 -08005855#endif
pbrook624f7972008-05-31 16:11:38 +00005856 if (sa->sa_flags & TARGET_SA_RESETHAND)
5857 sa->_sa_handler = TARGET_SIG_DFL;
bellard31e31b82003-02-18 22:55:36 +00005858 }
bellard66fb9762003-03-23 01:06:05 +00005859 if (q != &k->info)
pbrook624f7972008-05-31 16:11:38 +00005860 free_sigqueue(cpu_env, q);
bellard31e31b82003-02-18 22:55:36 +00005861}