blob: 0664770c94fef3498c86afad41d743dbb340251e [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 */
19#include <stdlib.h>
20#include <stdio.h>
bellard66fb9762003-03-23 01:06:05 +000021#include <string.h>
bellard31e31b82003-02-18 22:55:36 +000022#include <stdarg.h>
bellard2677e102003-04-10 00:03:27 +000023#include <unistd.h>
bellard31e31b82003-02-18 22:55:36 +000024#include <signal.h>
bellard66fb9762003-03-23 01:06:05 +000025#include <errno.h>
aurel32603e4fd2009-04-15 16:18:38 +000026#include <assert.h>
bellard31e31b82003-02-18 22:55:36 +000027#include <sys/ucontext.h>
Mika Westerbergedf8e2a2009-04-07 09:57:11 +030028#include <sys/resource.h>
bellard31e31b82003-02-18 22:55:36 +000029
bellard3ef693a2003-03-23 20:17:16 +000030#include "qemu.h"
blueswir17d99a002009-01-14 19:00:36 +000031#include "qemu-common.h"
blueswir1992f48a2007-10-14 16:27:31 +000032#include "target_signal.h"
bellard66fb9762003-03-23 01:06:05 +000033
34//#define DEBUG_SIGNAL
35
blueswir1249c4c32008-10-05 11:09:37 +000036static struct target_sigaltstack target_sigaltstack_used = {
thsa04e1342007-09-27 13:57:58 +000037 .ss_sp = 0,
38 .ss_size = 0,
39 .ss_flags = TARGET_SS_DISABLE,
40};
41
pbrook624f7972008-05-31 16:11:38 +000042static struct target_sigaction sigact_table[TARGET_NSIG];
bellard31e31b82003-02-18 22:55:36 +000043
ths5fafdf22007-09-16 21:08:06 +000044static void host_signal_handler(int host_signum, siginfo_t *info,
bellard66fb9762003-03-23 01:06:05 +000045 void *puc);
46
Arnaud Patard3ca05582009-03-30 01:18:20 +020047static uint8_t host_to_target_signal_table[_NSIG] = {
bellard9e5f5282003-07-13 17:33:54 +000048 [SIGHUP] = TARGET_SIGHUP,
49 [SIGINT] = TARGET_SIGINT,
50 [SIGQUIT] = TARGET_SIGQUIT,
51 [SIGILL] = TARGET_SIGILL,
52 [SIGTRAP] = TARGET_SIGTRAP,
53 [SIGABRT] = TARGET_SIGABRT,
bellard01e3b762003-09-30 21:10:14 +000054/* [SIGIOT] = TARGET_SIGIOT,*/
bellard9e5f5282003-07-13 17:33:54 +000055 [SIGBUS] = TARGET_SIGBUS,
56 [SIGFPE] = TARGET_SIGFPE,
57 [SIGKILL] = TARGET_SIGKILL,
58 [SIGUSR1] = TARGET_SIGUSR1,
59 [SIGSEGV] = TARGET_SIGSEGV,
60 [SIGUSR2] = TARGET_SIGUSR2,
61 [SIGPIPE] = TARGET_SIGPIPE,
62 [SIGALRM] = TARGET_SIGALRM,
63 [SIGTERM] = TARGET_SIGTERM,
64#ifdef SIGSTKFLT
65 [SIGSTKFLT] = TARGET_SIGSTKFLT,
66#endif
67 [SIGCHLD] = TARGET_SIGCHLD,
68 [SIGCONT] = TARGET_SIGCONT,
69 [SIGSTOP] = TARGET_SIGSTOP,
70 [SIGTSTP] = TARGET_SIGTSTP,
71 [SIGTTIN] = TARGET_SIGTTIN,
72 [SIGTTOU] = TARGET_SIGTTOU,
73 [SIGURG] = TARGET_SIGURG,
74 [SIGXCPU] = TARGET_SIGXCPU,
75 [SIGXFSZ] = TARGET_SIGXFSZ,
76 [SIGVTALRM] = TARGET_SIGVTALRM,
77 [SIGPROF] = TARGET_SIGPROF,
78 [SIGWINCH] = TARGET_SIGWINCH,
79 [SIGIO] = TARGET_SIGIO,
80 [SIGPWR] = TARGET_SIGPWR,
81 [SIGSYS] = TARGET_SIGSYS,
82 /* next signals stay the same */
pbrook624f7972008-05-31 16:11:38 +000083 /* Nasty hack: Reverse SIGRTMIN and SIGRTMAX to avoid overlap with
84 host libpthread signals. This assumes noone actually uses SIGRTMAX :-/
85 To fix this properly we need to do manual signal delivery multiplexed
86 over a single host signal. */
87 [__SIGRTMIN] = __SIGRTMAX,
88 [__SIGRTMAX] = __SIGRTMIN,
bellard9e5f5282003-07-13 17:33:54 +000089};
Arnaud Patard3ca05582009-03-30 01:18:20 +020090static uint8_t target_to_host_signal_table[_NSIG];
bellard9e5f5282003-07-13 17:33:54 +000091
thsa04e1342007-09-27 13:57:58 +000092static inline int on_sig_stack(unsigned long sp)
93{
94 return (sp - target_sigaltstack_used.ss_sp
95 < target_sigaltstack_used.ss_size);
96}
97
98static inline int sas_ss_flags(unsigned long sp)
99{
100 return (target_sigaltstack_used.ss_size == 0 ? SS_DISABLE
101 : on_sig_stack(sp) ? SS_ONSTACK : 0);
102}
103
pbrook1d9d8b52009-04-16 15:17:02 +0000104int host_to_target_signal(int sig)
bellard31e31b82003-02-18 22:55:36 +0000105{
Arnaud Patard3ca05582009-03-30 01:18:20 +0200106 if (sig >= _NSIG)
pbrook4cb05962008-05-30 18:05:19 +0000107 return sig;
bellard9e5f5282003-07-13 17:33:54 +0000108 return host_to_target_signal_table[sig];
bellard31e31b82003-02-18 22:55:36 +0000109}
110
pbrook4cb05962008-05-30 18:05:19 +0000111int target_to_host_signal(int sig)
bellard31e31b82003-02-18 22:55:36 +0000112{
Arnaud Patard3ca05582009-03-30 01:18:20 +0200113 if (sig >= _NSIG)
pbrook4cb05962008-05-30 18:05:19 +0000114 return sig;
bellard9e5f5282003-07-13 17:33:54 +0000115 return target_to_host_signal_table[sig];
bellard31e31b82003-02-18 22:55:36 +0000116}
117
Anthony Liguoric227f092009-10-01 16:12:16 -0500118static inline void target_sigemptyset(target_sigset_t *set)
pbrookf5545b52008-05-30 22:37:07 +0000119{
120 memset(set, 0, sizeof(*set));
121}
122
Anthony Liguoric227f092009-10-01 16:12:16 -0500123static inline void target_sigaddset(target_sigset_t *set, int signum)
pbrookf5545b52008-05-30 22:37:07 +0000124{
125 signum--;
126 abi_ulong mask = (abi_ulong)1 << (signum % TARGET_NSIG_BPW);
127 set->sig[signum / TARGET_NSIG_BPW] |= mask;
128}
129
Anthony Liguoric227f092009-10-01 16:12:16 -0500130static inline int target_sigismember(const target_sigset_t *set, int signum)
pbrookf5545b52008-05-30 22:37:07 +0000131{
132 signum--;
133 abi_ulong mask = (abi_ulong)1 << (signum % TARGET_NSIG_BPW);
134 return ((set->sig[signum / TARGET_NSIG_BPW] & mask) != 0);
135}
136
Anthony Liguoric227f092009-10-01 16:12:16 -0500137static void host_to_target_sigset_internal(target_sigset_t *d,
bellard92319442004-06-19 16:58:13 +0000138 const sigset_t *s)
bellard66fb9762003-03-23 01:06:05 +0000139{
140 int i;
pbrookf5545b52008-05-30 22:37:07 +0000141 target_sigemptyset(d);
142 for (i = 1; i <= TARGET_NSIG; i++) {
143 if (sigismember(s, i)) {
144 target_sigaddset(d, host_to_target_signal(i));
145 }
bellard9e5f5282003-07-13 17:33:54 +0000146 }
bellard66fb9762003-03-23 01:06:05 +0000147}
148
Anthony Liguoric227f092009-10-01 16:12:16 -0500149void host_to_target_sigset(target_sigset_t *d, const sigset_t *s)
bellard92319442004-06-19 16:58:13 +0000150{
Anthony Liguoric227f092009-10-01 16:12:16 -0500151 target_sigset_t d1;
bellard92319442004-06-19 16:58:13 +0000152 int i;
153
154 host_to_target_sigset_internal(&d1, s);
155 for(i = 0;i < TARGET_NSIG_WORDS; i++)
pbrook53a59602006-03-25 19:31:22 +0000156 d->sig[i] = tswapl(d1.sig[i]);
bellard92319442004-06-19 16:58:13 +0000157}
158
blueswir18fcd3692008-08-17 20:26:25 +0000159static void target_to_host_sigset_internal(sigset_t *d,
Anthony Liguoric227f092009-10-01 16:12:16 -0500160 const target_sigset_t *s)
bellard66fb9762003-03-23 01:06:05 +0000161{
162 int i;
pbrookf5545b52008-05-30 22:37:07 +0000163 sigemptyset(d);
164 for (i = 1; i <= TARGET_NSIG; i++) {
165 if (target_sigismember(s, i)) {
166 sigaddset(d, target_to_host_signal(i));
167 }
168 }
bellard66fb9762003-03-23 01:06:05 +0000169}
170
Anthony Liguoric227f092009-10-01 16:12:16 -0500171void target_to_host_sigset(sigset_t *d, const target_sigset_t *s)
bellard92319442004-06-19 16:58:13 +0000172{
Anthony Liguoric227f092009-10-01 16:12:16 -0500173 target_sigset_t s1;
bellard92319442004-06-19 16:58:13 +0000174 int i;
175
176 for(i = 0;i < TARGET_NSIG_WORDS; i++)
pbrook53a59602006-03-25 19:31:22 +0000177 s1.sig[i] = tswapl(s->sig[i]);
bellard92319442004-06-19 16:58:13 +0000178 target_to_host_sigset_internal(d, &s1);
179}
ths3b46e622007-09-17 08:09:54 +0000180
blueswir1992f48a2007-10-14 16:27:31 +0000181void host_to_target_old_sigset(abi_ulong *old_sigset,
bellard66fb9762003-03-23 01:06:05 +0000182 const sigset_t *sigset)
183{
Anthony Liguoric227f092009-10-01 16:12:16 -0500184 target_sigset_t d;
bellard9e5f5282003-07-13 17:33:54 +0000185 host_to_target_sigset(&d, sigset);
186 *old_sigset = d.sig[0];
bellard66fb9762003-03-23 01:06:05 +0000187}
188
ths5fafdf22007-09-16 21:08:06 +0000189void target_to_host_old_sigset(sigset_t *sigset,
blueswir1992f48a2007-10-14 16:27:31 +0000190 const abi_ulong *old_sigset)
bellard66fb9762003-03-23 01:06:05 +0000191{
Anthony Liguoric227f092009-10-01 16:12:16 -0500192 target_sigset_t d;
bellard9e5f5282003-07-13 17:33:54 +0000193 int i;
194
195 d.sig[0] = *old_sigset;
196 for(i = 1;i < TARGET_NSIG_WORDS; i++)
197 d.sig[i] = 0;
198 target_to_host_sigset(sigset, &d);
bellard66fb9762003-03-23 01:06:05 +0000199}
200
bellard9de5e442003-03-23 16:49:39 +0000201/* siginfo conversion */
202
Anthony Liguoric227f092009-10-01 16:12:16 -0500203static inline void host_to_target_siginfo_noswap(target_siginfo_t *tinfo,
bellard9de5e442003-03-23 16:49:39 +0000204 const siginfo_t *info)
bellard66fb9762003-03-23 01:06:05 +0000205{
bellard9de5e442003-03-23 16:49:39 +0000206 int sig;
207 sig = host_to_target_signal(info->si_signo);
208 tinfo->si_signo = sig;
209 tinfo->si_errno = 0;
pbrookafd7cd92008-05-31 12:14:21 +0000210 tinfo->si_code = info->si_code;
ths5fafdf22007-09-16 21:08:06 +0000211 if (sig == SIGILL || sig == SIGFPE || sig == SIGSEGV ||
bellard447db212003-05-10 15:10:36 +0000212 sig == SIGBUS || sig == SIGTRAP) {
bellard9de5e442003-03-23 16:49:39 +0000213 /* should never come here, but who knows. The information for
214 the target is irrelevant */
215 tinfo->_sifields._sigfault._addr = 0;
ths7f7f7c82007-07-12 11:02:46 +0000216 } else if (sig == SIGIO) {
217 tinfo->_sifields._sigpoll._fd = info->si_fd;
bellard9de5e442003-03-23 16:49:39 +0000218 } else if (sig >= TARGET_SIGRTMIN) {
219 tinfo->_sifields._rt._pid = info->si_pid;
220 tinfo->_sifields._rt._uid = info->si_uid;
221 /* XXX: potential problem if 64 bit */
ths5fafdf22007-09-16 21:08:06 +0000222 tinfo->_sifields._rt._sigval.sival_ptr =
bellard459a4012007-11-11 19:45:10 +0000223 (abi_ulong)(unsigned long)info->si_value.sival_ptr;
bellard9de5e442003-03-23 16:49:39 +0000224 }
bellard66fb9762003-03-23 01:06:05 +0000225}
226
Anthony Liguoric227f092009-10-01 16:12:16 -0500227static void tswap_siginfo(target_siginfo_t *tinfo,
228 const target_siginfo_t *info)
bellard9de5e442003-03-23 16:49:39 +0000229{
230 int sig;
231 sig = info->si_signo;
232 tinfo->si_signo = tswap32(sig);
233 tinfo->si_errno = tswap32(info->si_errno);
234 tinfo->si_code = tswap32(info->si_code);
ths5fafdf22007-09-16 21:08:06 +0000235 if (sig == SIGILL || sig == SIGFPE || sig == SIGSEGV ||
bellard447db212003-05-10 15:10:36 +0000236 sig == SIGBUS || sig == SIGTRAP) {
ths5fafdf22007-09-16 21:08:06 +0000237 tinfo->_sifields._sigfault._addr =
bellard9de5e442003-03-23 16:49:39 +0000238 tswapl(info->_sifields._sigfault._addr);
ths7f7f7c82007-07-12 11:02:46 +0000239 } else if (sig == SIGIO) {
240 tinfo->_sifields._sigpoll._fd = tswap32(info->_sifields._sigpoll._fd);
bellard9de5e442003-03-23 16:49:39 +0000241 } else if (sig >= TARGET_SIGRTMIN) {
242 tinfo->_sifields._rt._pid = tswap32(info->_sifields._rt._pid);
243 tinfo->_sifields._rt._uid = tswap32(info->_sifields._rt._uid);
ths5fafdf22007-09-16 21:08:06 +0000244 tinfo->_sifields._rt._sigval.sival_ptr =
bellard9de5e442003-03-23 16:49:39 +0000245 tswapl(info->_sifields._rt._sigval.sival_ptr);
246 }
247}
248
249
Anthony Liguoric227f092009-10-01 16:12:16 -0500250void host_to_target_siginfo(target_siginfo_t *tinfo, const siginfo_t *info)
bellard9de5e442003-03-23 16:49:39 +0000251{
252 host_to_target_siginfo_noswap(tinfo, info);
253 tswap_siginfo(tinfo, tinfo);
254}
255
256/* XXX: we support only POSIX RT signals are used. */
thsaa1f17c2007-07-11 22:48:58 +0000257/* XXX: find a solution for 64 bit (additional malloced data is needed) */
Anthony Liguoric227f092009-10-01 16:12:16 -0500258void target_to_host_siginfo(siginfo_t *info, const target_siginfo_t *tinfo)
bellard66fb9762003-03-23 01:06:05 +0000259{
260 info->si_signo = tswap32(tinfo->si_signo);
261 info->si_errno = tswap32(tinfo->si_errno);
262 info->si_code = tswap32(tinfo->si_code);
bellard9de5e442003-03-23 16:49:39 +0000263 info->si_pid = tswap32(tinfo->_sifields._rt._pid);
264 info->si_uid = tswap32(tinfo->_sifields._rt._uid);
ths5fafdf22007-09-16 21:08:06 +0000265 info->si_value.sival_ptr =
bellard459a4012007-11-11 19:45:10 +0000266 (void *)(long)tswapl(tinfo->_sifields._rt._sigval.sival_ptr);
bellard66fb9762003-03-23 01:06:05 +0000267}
268
aurel32ca587a82008-12-18 22:44:13 +0000269static int fatal_signal (int sig)
270{
271 switch (sig) {
272 case TARGET_SIGCHLD:
273 case TARGET_SIGURG:
274 case TARGET_SIGWINCH:
275 /* Ignored by default. */
276 return 0;
277 case TARGET_SIGCONT:
278 case TARGET_SIGSTOP:
279 case TARGET_SIGTSTP:
280 case TARGET_SIGTTIN:
281 case TARGET_SIGTTOU:
282 /* Job control signals. */
283 return 0;
284 default:
285 return 1;
286 }
287}
288
Mika Westerbergedf8e2a2009-04-07 09:57:11 +0300289/* returns 1 if given signal should dump core if not handled */
290static int core_dump_signal(int sig)
291{
292 switch (sig) {
293 case TARGET_SIGABRT:
294 case TARGET_SIGFPE:
295 case TARGET_SIGILL:
296 case TARGET_SIGQUIT:
297 case TARGET_SIGSEGV:
298 case TARGET_SIGTRAP:
299 case TARGET_SIGBUS:
300 return (1);
301 default:
302 return (0);
303 }
304}
305
bellard31e31b82003-02-18 22:55:36 +0000306void signal_init(void)
307{
308 struct sigaction act;
pbrook624f7972008-05-31 16:11:38 +0000309 struct sigaction oact;
bellard9e5f5282003-07-13 17:33:54 +0000310 int i, j;
pbrook624f7972008-05-31 16:11:38 +0000311 int host_sig;
bellard31e31b82003-02-18 22:55:36 +0000312
bellard9e5f5282003-07-13 17:33:54 +0000313 /* generate signal conversion tables */
Arnaud Patard3ca05582009-03-30 01:18:20 +0200314 for(i = 1; i < _NSIG; i++) {
bellard9e5f5282003-07-13 17:33:54 +0000315 if (host_to_target_signal_table[i] == 0)
316 host_to_target_signal_table[i] = i;
317 }
Arnaud Patard3ca05582009-03-30 01:18:20 +0200318 for(i = 1; i < _NSIG; i++) {
bellard9e5f5282003-07-13 17:33:54 +0000319 j = host_to_target_signal_table[i];
320 target_to_host_signal_table[j] = i;
321 }
ths3b46e622007-09-17 08:09:54 +0000322
bellard9de5e442003-03-23 16:49:39 +0000323 /* set all host signal handlers. ALL signals are blocked during
324 the handlers to serialize them. */
pbrook624f7972008-05-31 16:11:38 +0000325 memset(sigact_table, 0, sizeof(sigact_table));
326
bellard9de5e442003-03-23 16:49:39 +0000327 sigfillset(&act.sa_mask);
bellard31e31b82003-02-18 22:55:36 +0000328 act.sa_flags = SA_SIGINFO;
329 act.sa_sigaction = host_signal_handler;
pbrook624f7972008-05-31 16:11:38 +0000330 for(i = 1; i <= TARGET_NSIG; i++) {
331 host_sig = target_to_host_signal(i);
332 sigaction(host_sig, NULL, &oact);
333 if (oact.sa_sigaction == (void *)SIG_IGN) {
334 sigact_table[i - 1]._sa_handler = TARGET_SIG_IGN;
335 } else if (oact.sa_sigaction == (void *)SIG_DFL) {
336 sigact_table[i - 1]._sa_handler = TARGET_SIG_DFL;
337 }
338 /* If there's already a handler installed then something has
339 gone horribly wrong, so don't even try to handle that case. */
aurel32ca587a82008-12-18 22:44:13 +0000340 /* Install some handlers for our own use. We need at least
341 SIGSEGV and SIGBUS, to detect exceptions. We can not just
342 trap all signals because it affects syscall interrupt
343 behavior. But do trap all default-fatal signals. */
344 if (fatal_signal (i))
pbrook624f7972008-05-31 16:11:38 +0000345 sigaction(host_sig, &act, NULL);
bellard31e31b82003-02-18 22:55:36 +0000346 }
bellard31e31b82003-02-18 22:55:36 +0000347}
348
bellard66fb9762003-03-23 01:06:05 +0000349/* signal queue handling */
350
pbrook624f7972008-05-31 16:11:38 +0000351static inline struct sigqueue *alloc_sigqueue(CPUState *env)
bellard66fb9762003-03-23 01:06:05 +0000352{
pbrook624f7972008-05-31 16:11:38 +0000353 TaskState *ts = env->opaque;
354 struct sigqueue *q = ts->first_free;
bellard66fb9762003-03-23 01:06:05 +0000355 if (!q)
356 return NULL;
pbrook624f7972008-05-31 16:11:38 +0000357 ts->first_free = q->next;
bellard66fb9762003-03-23 01:06:05 +0000358 return q;
359}
360
pbrook624f7972008-05-31 16:11:38 +0000361static inline void free_sigqueue(CPUState *env, struct sigqueue *q)
bellard66fb9762003-03-23 01:06:05 +0000362{
pbrook624f7972008-05-31 16:11:38 +0000363 TaskState *ts = env->opaque;
364 q->next = ts->first_free;
365 ts->first_free = q;
bellard66fb9762003-03-23 01:06:05 +0000366}
367
bellard9de5e442003-03-23 16:49:39 +0000368/* abort execution with signal */
Riku Voipio66393fb2009-12-04 15:16:32 +0200369static void QEMU_NORETURN force_sig(int target_sig)
bellard66fb9762003-03-23 01:06:05 +0000370{
Mika Westerbergedf8e2a2009-04-07 09:57:11 +0300371 TaskState *ts = (TaskState *)thread_env->opaque;
372 int host_sig, core_dumped = 0;
aurel32603e4fd2009-04-15 16:18:38 +0000373 struct sigaction act;
Riku Voipio66393fb2009-12-04 15:16:32 +0200374 host_sig = target_to_host_signal(target_sig);
375 gdb_signalled(thread_env, target_sig);
aurel32603e4fd2009-04-15 16:18:38 +0000376
Mika Westerbergedf8e2a2009-04-07 09:57:11 +0300377 /* dump core if supported by target binary format */
Riku Voipio66393fb2009-12-04 15:16:32 +0200378 if (core_dump_signal(target_sig) && (ts->bprm->core_dump != NULL)) {
Mika Westerbergedf8e2a2009-04-07 09:57:11 +0300379 stop_all_tasks();
380 core_dumped =
Riku Voipio66393fb2009-12-04 15:16:32 +0200381 ((*ts->bprm->core_dump)(target_sig, thread_env) == 0);
Mika Westerbergedf8e2a2009-04-07 09:57:11 +0300382 }
383 if (core_dumped) {
384 /* we already dumped the core of target process, we don't want
385 * a coredump of qemu itself */
386 struct rlimit nodump;
387 getrlimit(RLIMIT_CORE, &nodump);
388 nodump.rlim_cur=0;
389 setrlimit(RLIMIT_CORE, &nodump);
390 (void) fprintf(stderr, "qemu: uncaught target signal %d (%s) - %s\n",
Riku Voipio66393fb2009-12-04 15:16:32 +0200391 target_sig, strsignal(host_sig), "core dumped" );
Mika Westerbergedf8e2a2009-04-07 09:57:11 +0300392 }
393
aurel32603e4fd2009-04-15 16:18:38 +0000394 /* The proper exit code for dieing from an uncaught signal is
395 * -<signal>. The kernel doesn't allow exit() or _exit() to pass
396 * a negative value. To get the proper exit code we need to
397 * actually die from an uncaught signal. Here the default signal
398 * handler is installed, we send ourself a signal and we wait for
399 * it to arrive. */
400 sigfillset(&act.sa_mask);
401 act.sa_handler = SIG_DFL;
402 sigaction(host_sig, &act, NULL);
403
404 /* For some reason raise(host_sig) doesn't send the signal when
405 * statically linked on x86-64. */
406 kill(getpid(), host_sig);
407
408 /* Make sure the signal isn't masked (just reuse the mask inside
409 of act) */
410 sigdelset(&act.sa_mask, host_sig);
411 sigsuspend(&act.sa_mask);
412
413 /* unreachable */
Blue Swirla6c6f762010-03-13 14:18:50 +0000414 abort();
bellard66fb9762003-03-23 01:06:05 +0000415}
416
bellard9de5e442003-03-23 16:49:39 +0000417/* queue a signal so that it will be send to the virtual CPU as soon
418 as possible */
Anthony Liguoric227f092009-10-01 16:12:16 -0500419int queue_signal(CPUState *env, int sig, target_siginfo_t *info)
bellard31e31b82003-02-18 22:55:36 +0000420{
pbrook624f7972008-05-31 16:11:38 +0000421 TaskState *ts = env->opaque;
422 struct emulated_sigtable *k;
bellard9de5e442003-03-23 16:49:39 +0000423 struct sigqueue *q, **pq;
blueswir1992f48a2007-10-14 16:27:31 +0000424 abi_ulong handler;
aurel32ca587a82008-12-18 22:44:13 +0000425 int queue;
bellard66fb9762003-03-23 01:06:05 +0000426
bellard9de5e442003-03-23 16:49:39 +0000427#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000428 fprintf(stderr, "queue_signal: sig=%d\n",
bellard9de5e442003-03-23 16:49:39 +0000429 sig);
bellard66fb9762003-03-23 01:06:05 +0000430#endif
pbrook624f7972008-05-31 16:11:38 +0000431 k = &ts->sigtab[sig - 1];
aurel32ca587a82008-12-18 22:44:13 +0000432 queue = gdb_queuesig ();
pbrook624f7972008-05-31 16:11:38 +0000433 handler = sigact_table[sig - 1]._sa_handler;
aurel32ca587a82008-12-18 22:44:13 +0000434 if (!queue && handler == TARGET_SIG_DFL) {
ths60b19692008-11-27 15:47:15 +0000435 if (sig == TARGET_SIGTSTP || sig == TARGET_SIGTTIN || sig == TARGET_SIGTTOU) {
436 kill(getpid(),SIGSTOP);
437 return 0;
438 } else
bellard66fb9762003-03-23 01:06:05 +0000439 /* default handler : ignore some signal. The other are fatal */
ths5fafdf22007-09-16 21:08:06 +0000440 if (sig != TARGET_SIGCHLD &&
441 sig != TARGET_SIGURG &&
ths60b19692008-11-27 15:47:15 +0000442 sig != TARGET_SIGWINCH &&
443 sig != TARGET_SIGCONT) {
bellard66fb9762003-03-23 01:06:05 +0000444 force_sig(sig);
bellard9de5e442003-03-23 16:49:39 +0000445 } else {
446 return 0; /* indicate ignored */
bellard66fb9762003-03-23 01:06:05 +0000447 }
aurel32ca587a82008-12-18 22:44:13 +0000448 } else if (!queue && handler == TARGET_SIG_IGN) {
bellard66fb9762003-03-23 01:06:05 +0000449 /* ignore signal */
bellard9de5e442003-03-23 16:49:39 +0000450 return 0;
aurel32ca587a82008-12-18 22:44:13 +0000451 } else if (!queue && handler == TARGET_SIG_ERR) {
bellard66fb9762003-03-23 01:06:05 +0000452 force_sig(sig);
453 } else {
bellard9de5e442003-03-23 16:49:39 +0000454 pq = &k->first;
455 if (sig < TARGET_SIGRTMIN) {
456 /* if non real time signal, we queue exactly one signal */
457 if (!k->pending)
458 q = &k->info;
459 else
460 return 0;
461 } else {
462 if (!k->pending) {
463 /* first signal */
464 q = &k->info;
465 } else {
pbrook624f7972008-05-31 16:11:38 +0000466 q = alloc_sigqueue(env);
bellard9de5e442003-03-23 16:49:39 +0000467 if (!q)
468 return -EAGAIN;
469 while (*pq != NULL)
470 pq = &(*pq)->next;
471 }
472 }
473 *pq = q;
474 q->info = *info;
475 q->next = NULL;
476 k->pending = 1;
477 /* signal that a new signal is pending */
pbrook624f7972008-05-31 16:11:38 +0000478 ts->signal_pending = 1;
bellard9de5e442003-03-23 16:49:39 +0000479 return 1; /* indicates that the signal was queued */
480 }
481}
482
ths5fafdf22007-09-16 21:08:06 +0000483static void host_signal_handler(int host_signum, siginfo_t *info,
bellard9de5e442003-03-23 16:49:39 +0000484 void *puc)
485{
486 int sig;
Anthony Liguoric227f092009-10-01 16:12:16 -0500487 target_siginfo_t tinfo;
bellard9de5e442003-03-23 16:49:39 +0000488
489 /* the CPU emulator uses some host signals to detect exceptions,
aurel32eaa449b2009-01-03 13:14:52 +0000490 we forward to it some signals */
aurel32ca587a82008-12-18 22:44:13 +0000491 if ((host_signum == SIGSEGV || host_signum == SIGBUS)
aurel32eaa449b2009-01-03 13:14:52 +0000492 && info->si_code > 0) {
bellardb346ff42003-06-15 20:05:50 +0000493 if (cpu_signal_handler(host_signum, info, puc))
bellard9de5e442003-03-23 16:49:39 +0000494 return;
495 }
496
497 /* get target signal number */
498 sig = host_to_target_signal(host_signum);
499 if (sig < 1 || sig > TARGET_NSIG)
500 return;
501#if defined(DEBUG_SIGNAL)
bellardbc8a22c2003-03-30 21:02:40 +0000502 fprintf(stderr, "qemu: got signal %d\n", sig);
bellard9de5e442003-03-23 16:49:39 +0000503#endif
504 host_to_target_siginfo_noswap(&tinfo, info);
pbrookd5975362008-06-07 20:50:51 +0000505 if (queue_signal(thread_env, sig, &tinfo) == 1) {
bellard9de5e442003-03-23 16:49:39 +0000506 /* interrupt the virtual CPU as soon as possible */
aurel323098dba2009-03-07 21:28:24 +0000507 cpu_exit(thread_env);
bellard66fb9762003-03-23 01:06:05 +0000508 }
bellard31e31b82003-02-18 22:55:36 +0000509}
510
ths0da46a62007-10-20 20:23:07 +0000511/* do_sigaltstack() returns target values and errnos. */
bellard579a97f2007-11-11 14:26:47 +0000512/* compare linux/kernel/signal.c:do_sigaltstack() */
513abi_long do_sigaltstack(abi_ulong uss_addr, abi_ulong uoss_addr, abi_ulong sp)
thsa04e1342007-09-27 13:57:58 +0000514{
515 int ret;
516 struct target_sigaltstack oss;
517
518 /* XXX: test errors */
bellard579a97f2007-11-11 14:26:47 +0000519 if(uoss_addr)
thsa04e1342007-09-27 13:57:58 +0000520 {
521 __put_user(target_sigaltstack_used.ss_sp, &oss.ss_sp);
522 __put_user(target_sigaltstack_used.ss_size, &oss.ss_size);
523 __put_user(sas_ss_flags(sp), &oss.ss_flags);
524 }
525
bellard579a97f2007-11-11 14:26:47 +0000526 if(uss_addr)
thsa04e1342007-09-27 13:57:58 +0000527 {
bellard579a97f2007-11-11 14:26:47 +0000528 struct target_sigaltstack *uss;
529 struct target_sigaltstack ss;
thsa04e1342007-09-27 13:57:58 +0000530
ths0da46a62007-10-20 20:23:07 +0000531 ret = -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +0000532 if (!lock_user_struct(VERIFY_READ, uss, uss_addr, 1)
thsa04e1342007-09-27 13:57:58 +0000533 || __get_user(ss.ss_sp, &uss->ss_sp)
534 || __get_user(ss.ss_size, &uss->ss_size)
535 || __get_user(ss.ss_flags, &uss->ss_flags))
536 goto out;
bellard579a97f2007-11-11 14:26:47 +0000537 unlock_user_struct(uss, uss_addr, 0);
thsa04e1342007-09-27 13:57:58 +0000538
ths0da46a62007-10-20 20:23:07 +0000539 ret = -TARGET_EPERM;
thsa04e1342007-09-27 13:57:58 +0000540 if (on_sig_stack(sp))
541 goto out;
542
ths0da46a62007-10-20 20:23:07 +0000543 ret = -TARGET_EINVAL;
thsa04e1342007-09-27 13:57:58 +0000544 if (ss.ss_flags != TARGET_SS_DISABLE
545 && ss.ss_flags != TARGET_SS_ONSTACK
546 && ss.ss_flags != 0)
547 goto out;
548
549 if (ss.ss_flags == TARGET_SS_DISABLE) {
550 ss.ss_size = 0;
551 ss.ss_sp = 0;
552 } else {
ths0da46a62007-10-20 20:23:07 +0000553 ret = -TARGET_ENOMEM;
thsa04e1342007-09-27 13:57:58 +0000554 if (ss.ss_size < MINSIGSTKSZ)
555 goto out;
556 }
557
558 target_sigaltstack_used.ss_sp = ss.ss_sp;
559 target_sigaltstack_used.ss_size = ss.ss_size;
560 }
561
bellard579a97f2007-11-11 14:26:47 +0000562 if (uoss_addr) {
ths0da46a62007-10-20 20:23:07 +0000563 ret = -TARGET_EFAULT;
bellard579a97f2007-11-11 14:26:47 +0000564 if (copy_to_user(uoss_addr, &oss, sizeof(oss)))
thsa04e1342007-09-27 13:57:58 +0000565 goto out;
thsa04e1342007-09-27 13:57:58 +0000566 }
567
568 ret = 0;
569out:
570 return ret;
571}
572
ths0da46a62007-10-20 20:23:07 +0000573/* do_sigaction() return host values and errnos */
bellard66fb9762003-03-23 01:06:05 +0000574int do_sigaction(int sig, const struct target_sigaction *act,
575 struct target_sigaction *oact)
bellard31e31b82003-02-18 22:55:36 +0000576{
pbrook624f7972008-05-31 16:11:38 +0000577 struct target_sigaction *k;
bellard773b93e2004-01-04 17:15:59 +0000578 struct sigaction act1;
579 int host_sig;
ths0da46a62007-10-20 20:23:07 +0000580 int ret = 0;
bellard31e31b82003-02-18 22:55:36 +0000581
ths2a913eb2008-11-27 15:46:25 +0000582 if (sig < 1 || sig > TARGET_NSIG || sig == TARGET_SIGKILL || sig == TARGET_SIGSTOP)
bellard66fb9762003-03-23 01:06:05 +0000583 return -EINVAL;
584 k = &sigact_table[sig - 1];
bellard773b93e2004-01-04 17:15:59 +0000585#if defined(DEBUG_SIGNAL)
Blue Swirl0bf9e312009-07-20 17:19:25 +0000586 fprintf(stderr, "sigaction sig=%d act=0x%p, oact=0x%p\n",
587 sig, act, oact);
bellard66fb9762003-03-23 01:06:05 +0000588#endif
589 if (oact) {
pbrook624f7972008-05-31 16:11:38 +0000590 oact->_sa_handler = tswapl(k->_sa_handler);
591 oact->sa_flags = tswapl(k->sa_flags);
ths388bb212007-05-13 13:58:00 +0000592#if !defined(TARGET_MIPS)
pbrook624f7972008-05-31 16:11:38 +0000593 oact->sa_restorer = tswapl(k->sa_restorer);
ths388bb212007-05-13 13:58:00 +0000594#endif
pbrook624f7972008-05-31 16:11:38 +0000595 oact->sa_mask = k->sa_mask;
bellard66fb9762003-03-23 01:06:05 +0000596 }
597 if (act) {
pbrook624f7972008-05-31 16:11:38 +0000598 /* FIXME: This is not threadsafe. */
599 k->_sa_handler = tswapl(act->_sa_handler);
600 k->sa_flags = tswapl(act->sa_flags);
ths388bb212007-05-13 13:58:00 +0000601#if !defined(TARGET_MIPS)
pbrook624f7972008-05-31 16:11:38 +0000602 k->sa_restorer = tswapl(act->sa_restorer);
ths388bb212007-05-13 13:58:00 +0000603#endif
pbrook624f7972008-05-31 16:11:38 +0000604 k->sa_mask = act->sa_mask;
bellard773b93e2004-01-04 17:15:59 +0000605
606 /* we update the host linux signal state */
607 host_sig = target_to_host_signal(sig);
608 if (host_sig != SIGSEGV && host_sig != SIGBUS) {
609 sigfillset(&act1.sa_mask);
610 act1.sa_flags = SA_SIGINFO;
pbrook624f7972008-05-31 16:11:38 +0000611 if (k->sa_flags & TARGET_SA_RESTART)
bellard773b93e2004-01-04 17:15:59 +0000612 act1.sa_flags |= SA_RESTART;
613 /* NOTE: it is important to update the host kernel signal
614 ignore state to avoid getting unexpected interrupted
615 syscalls */
pbrook624f7972008-05-31 16:11:38 +0000616 if (k->_sa_handler == TARGET_SIG_IGN) {
bellard773b93e2004-01-04 17:15:59 +0000617 act1.sa_sigaction = (void *)SIG_IGN;
pbrook624f7972008-05-31 16:11:38 +0000618 } else if (k->_sa_handler == TARGET_SIG_DFL) {
aurel32ca587a82008-12-18 22:44:13 +0000619 if (fatal_signal (sig))
620 act1.sa_sigaction = host_signal_handler;
621 else
622 act1.sa_sigaction = (void *)SIG_DFL;
bellard773b93e2004-01-04 17:15:59 +0000623 } else {
624 act1.sa_sigaction = host_signal_handler;
625 }
ths0da46a62007-10-20 20:23:07 +0000626 ret = sigaction(host_sig, &act1, NULL);
bellard773b93e2004-01-04 17:15:59 +0000627 }
bellard66fb9762003-03-23 01:06:05 +0000628 }
ths0da46a62007-10-20 20:23:07 +0000629 return ret;
bellard66fb9762003-03-23 01:06:05 +0000630}
bellard31e31b82003-02-18 22:55:36 +0000631
Anthony Liguoric227f092009-10-01 16:12:16 -0500632static inline int copy_siginfo_to_user(target_siginfo_t *tinfo,
633 const target_siginfo_t *info)
bellard43fff232003-07-09 19:31:39 +0000634{
635 tswap_siginfo(tinfo, info);
636 return 0;
637}
638
thsc3b5bc82007-12-02 06:31:25 +0000639static inline int current_exec_domain_sig(int sig)
640{
641 return /* current->exec_domain && current->exec_domain->signal_invmap
642 && sig < 32 ? current->exec_domain->signal_invmap[sig] : */ sig;
643}
644
bellard459a4012007-11-11 19:45:10 +0000645#if defined(TARGET_I386) && TARGET_ABI_BITS == 32
bellard66fb9762003-03-23 01:06:05 +0000646
647/* from the Linux kernel */
648
649struct target_fpreg {
650 uint16_t significand[4];
651 uint16_t exponent;
652};
653
654struct target_fpxreg {
655 uint16_t significand[4];
656 uint16_t exponent;
657 uint16_t padding[3];
658};
659
660struct target_xmmreg {
blueswir1992f48a2007-10-14 16:27:31 +0000661 abi_ulong element[4];
bellard66fb9762003-03-23 01:06:05 +0000662};
663
664struct target_fpstate {
665 /* Regular FPU environment */
blueswir1992f48a2007-10-14 16:27:31 +0000666 abi_ulong cw;
667 abi_ulong sw;
668 abi_ulong tag;
669 abi_ulong ipoff;
670 abi_ulong cssel;
671 abi_ulong dataoff;
672 abi_ulong datasel;
bellard66fb9762003-03-23 01:06:05 +0000673 struct target_fpreg _st[8];
674 uint16_t status;
675 uint16_t magic; /* 0xffff = regular FPU data only */
676
677 /* FXSR FPU environment */
blueswir1992f48a2007-10-14 16:27:31 +0000678 abi_ulong _fxsr_env[6]; /* FXSR FPU env is ignored */
679 abi_ulong mxcsr;
680 abi_ulong reserved;
bellard66fb9762003-03-23 01:06:05 +0000681 struct target_fpxreg _fxsr_st[8]; /* FXSR FPU reg data is ignored */
682 struct target_xmmreg _xmm[8];
blueswir1992f48a2007-10-14 16:27:31 +0000683 abi_ulong padding[56];
bellard66fb9762003-03-23 01:06:05 +0000684};
685
686#define X86_FXSR_MAGIC 0x0000
687
688struct target_sigcontext {
689 uint16_t gs, __gsh;
690 uint16_t fs, __fsh;
691 uint16_t es, __esh;
692 uint16_t ds, __dsh;
blueswir1992f48a2007-10-14 16:27:31 +0000693 abi_ulong edi;
694 abi_ulong esi;
695 abi_ulong ebp;
696 abi_ulong esp;
697 abi_ulong ebx;
698 abi_ulong edx;
699 abi_ulong ecx;
700 abi_ulong eax;
701 abi_ulong trapno;
702 abi_ulong err;
703 abi_ulong eip;
bellard66fb9762003-03-23 01:06:05 +0000704 uint16_t cs, __csh;
blueswir1992f48a2007-10-14 16:27:31 +0000705 abi_ulong eflags;
706 abi_ulong esp_at_signal;
bellard66fb9762003-03-23 01:06:05 +0000707 uint16_t ss, __ssh;
blueswir1992f48a2007-10-14 16:27:31 +0000708 abi_ulong fpstate; /* pointer */
709 abi_ulong oldmask;
710 abi_ulong cr2;
bellard66fb9762003-03-23 01:06:05 +0000711};
712
bellard66fb9762003-03-23 01:06:05 +0000713struct target_ucontext {
blueswir1992f48a2007-10-14 16:27:31 +0000714 abi_ulong tuc_flags;
715 abi_ulong tuc_link;
Anthony Liguoric227f092009-10-01 16:12:16 -0500716 target_stack_t tuc_stack;
bellardb8076a72005-04-07 22:20:31 +0000717 struct target_sigcontext tuc_mcontext;
Anthony Liguoric227f092009-10-01 16:12:16 -0500718 target_sigset_t tuc_sigmask; /* mask last for extensibility */
bellard66fb9762003-03-23 01:06:05 +0000719};
720
721struct sigframe
722{
blueswir1992f48a2007-10-14 16:27:31 +0000723 abi_ulong pretcode;
bellard66fb9762003-03-23 01:06:05 +0000724 int sig;
725 struct target_sigcontext sc;
726 struct target_fpstate fpstate;
blueswir1992f48a2007-10-14 16:27:31 +0000727 abi_ulong extramask[TARGET_NSIG_WORDS-1];
bellard66fb9762003-03-23 01:06:05 +0000728 char retcode[8];
729};
730
731struct rt_sigframe
732{
blueswir1992f48a2007-10-14 16:27:31 +0000733 abi_ulong pretcode;
bellard66fb9762003-03-23 01:06:05 +0000734 int sig;
blueswir1992f48a2007-10-14 16:27:31 +0000735 abi_ulong pinfo;
736 abi_ulong puc;
bellard66fb9762003-03-23 01:06:05 +0000737 struct target_siginfo info;
738 struct target_ucontext uc;
739 struct target_fpstate fpstate;
740 char retcode[8];
741};
742
743/*
744 * Set up a signal frame.
745 */
746
bellard66fb9762003-03-23 01:06:05 +0000747/* XXX: save x87 state */
748static int
749setup_sigcontext(struct target_sigcontext *sc, struct target_fpstate *fpstate,
bellard28be6232007-11-11 22:23:38 +0000750 CPUX86State *env, abi_ulong mask, abi_ulong fpstate_addr)
bellard66fb9762003-03-23 01:06:05 +0000751{
752 int err = 0;
bellard775b58d2007-11-11 16:22:17 +0000753 uint16_t magic;
bellard66fb9762003-03-23 01:06:05 +0000754
bellard579a97f2007-11-11 14:26:47 +0000755 /* already locked in setup_frame() */
bellarda52c7572003-06-21 13:14:12 +0000756 err |= __put_user(env->segs[R_GS].selector, (unsigned int *)&sc->gs);
757 err |= __put_user(env->segs[R_FS].selector, (unsigned int *)&sc->fs);
758 err |= __put_user(env->segs[R_ES].selector, (unsigned int *)&sc->es);
759 err |= __put_user(env->segs[R_DS].selector, (unsigned int *)&sc->ds);
bellard66fb9762003-03-23 01:06:05 +0000760 err |= __put_user(env->regs[R_EDI], &sc->edi);
761 err |= __put_user(env->regs[R_ESI], &sc->esi);
762 err |= __put_user(env->regs[R_EBP], &sc->ebp);
763 err |= __put_user(env->regs[R_ESP], &sc->esp);
764 err |= __put_user(env->regs[R_EBX], &sc->ebx);
765 err |= __put_user(env->regs[R_EDX], &sc->edx);
766 err |= __put_user(env->regs[R_ECX], &sc->ecx);
767 err |= __put_user(env->regs[R_EAX], &sc->eax);
bellard66099dd2003-05-08 15:34:02 +0000768 err |= __put_user(env->exception_index, &sc->trapno);
769 err |= __put_user(env->error_code, &sc->err);
bellard66fb9762003-03-23 01:06:05 +0000770 err |= __put_user(env->eip, &sc->eip);
bellarda52c7572003-06-21 13:14:12 +0000771 err |= __put_user(env->segs[R_CS].selector, (unsigned int *)&sc->cs);
bellard66fb9762003-03-23 01:06:05 +0000772 err |= __put_user(env->eflags, &sc->eflags);
773 err |= __put_user(env->regs[R_ESP], &sc->esp_at_signal);
bellarda52c7572003-06-21 13:14:12 +0000774 err |= __put_user(env->segs[R_SS].selector, (unsigned int *)&sc->ss);
bellarded2dcdf2003-05-29 20:06:27 +0000775
bellard28be6232007-11-11 22:23:38 +0000776 cpu_x86_fsave(env, fpstate_addr, 1);
bellarded2dcdf2003-05-29 20:06:27 +0000777 fpstate->status = fpstate->sw;
bellard775b58d2007-11-11 16:22:17 +0000778 magic = 0xffff;
779 err |= __put_user(magic, &fpstate->magic);
bellard28be6232007-11-11 22:23:38 +0000780 err |= __put_user(fpstate_addr, &sc->fpstate);
bellarded2dcdf2003-05-29 20:06:27 +0000781
bellard66fb9762003-03-23 01:06:05 +0000782 /* non-iBCS2 extensions.. */
783 err |= __put_user(mask, &sc->oldmask);
bellarda52c7572003-06-21 13:14:12 +0000784 err |= __put_user(env->cr[2], &sc->cr2);
bellard66fb9762003-03-23 01:06:05 +0000785 return err;
786}
787
788/*
789 * Determine which stack to use..
790 */
791
bellard579a97f2007-11-11 14:26:47 +0000792static inline abi_ulong
pbrook624f7972008-05-31 16:11:38 +0000793get_sigframe(struct target_sigaction *ka, CPUX86State *env, size_t frame_size)
bellard66fb9762003-03-23 01:06:05 +0000794{
795 unsigned long esp;
796
797 /* Default to using normal stack */
798 esp = env->regs[R_ESP];
bellard66fb9762003-03-23 01:06:05 +0000799 /* This is the X/Open sanctioned signal stack switching. */
pbrook624f7972008-05-31 16:11:38 +0000800 if (ka->sa_flags & TARGET_SA_ONSTACK) {
thsa04e1342007-09-27 13:57:58 +0000801 if (sas_ss_flags(esp) == 0)
802 esp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
803 }
bellard66fb9762003-03-23 01:06:05 +0000804
805 /* This is the legacy signal stack switching. */
ths5fafdf22007-09-16 21:08:06 +0000806 else
bellarda52c7572003-06-21 13:14:12 +0000807 if ((env->segs[R_SS].selector & 0xffff) != __USER_DS &&
pbrook624f7972008-05-31 16:11:38 +0000808 !(ka->sa_flags & TARGET_SA_RESTORER) &&
809 ka->sa_restorer) {
810 esp = (unsigned long) ka->sa_restorer;
bellarda52c7572003-06-21 13:14:12 +0000811 }
bellard579a97f2007-11-11 14:26:47 +0000812 return (esp - frame_size) & -8ul;
bellard66fb9762003-03-23 01:06:05 +0000813}
814
bellard579a97f2007-11-11 14:26:47 +0000815/* compare linux/arch/i386/kernel/signal.c:setup_frame() */
pbrook624f7972008-05-31 16:11:38 +0000816static void setup_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -0500817 target_sigset_t *set, CPUX86State *env)
bellard66fb9762003-03-23 01:06:05 +0000818{
bellard579a97f2007-11-11 14:26:47 +0000819 abi_ulong frame_addr;
bellard66fb9762003-03-23 01:06:05 +0000820 struct sigframe *frame;
bellard92319442004-06-19 16:58:13 +0000821 int i, err = 0;
bellard66fb9762003-03-23 01:06:05 +0000822
bellard579a97f2007-11-11 14:26:47 +0000823 frame_addr = get_sigframe(ka, env, sizeof(*frame));
bellard66fb9762003-03-23 01:06:05 +0000824
bellard579a97f2007-11-11 14:26:47 +0000825 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
bellard66fb9762003-03-23 01:06:05 +0000826 goto give_sigsegv;
bellard579a97f2007-11-11 14:26:47 +0000827
thsc3b5bc82007-12-02 06:31:25 +0000828 err |= __put_user(current_exec_domain_sig(sig),
bellard66fb9762003-03-23 01:06:05 +0000829 &frame->sig);
830 if (err)
831 goto give_sigsegv;
832
bellard28be6232007-11-11 22:23:38 +0000833 setup_sigcontext(&frame->sc, &frame->fpstate, env, set->sig[0],
834 frame_addr + offsetof(struct sigframe, fpstate));
bellard66fb9762003-03-23 01:06:05 +0000835 if (err)
836 goto give_sigsegv;
837
bellard92319442004-06-19 16:58:13 +0000838 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
839 if (__put_user(set->sig[i], &frame->extramask[i - 1]))
840 goto give_sigsegv;
841 }
bellard66fb9762003-03-23 01:06:05 +0000842
843 /* Set up to return from userspace. If provided, use a stub
844 already in userspace. */
pbrook624f7972008-05-31 16:11:38 +0000845 if (ka->sa_flags & TARGET_SA_RESTORER) {
846 err |= __put_user(ka->sa_restorer, &frame->pretcode);
bellard66fb9762003-03-23 01:06:05 +0000847 } else {
bellard775b58d2007-11-11 16:22:17 +0000848 uint16_t val16;
bellard28be6232007-11-11 22:23:38 +0000849 abi_ulong retcode_addr;
850 retcode_addr = frame_addr + offsetof(struct sigframe, retcode);
851 err |= __put_user(retcode_addr, &frame->pretcode);
bellard66fb9762003-03-23 01:06:05 +0000852 /* This is popl %eax ; movl $,%eax ; int $0x80 */
bellard775b58d2007-11-11 16:22:17 +0000853 val16 = 0xb858;
854 err |= __put_user(val16, (uint16_t *)(frame->retcode+0));
bellard66fb9762003-03-23 01:06:05 +0000855 err |= __put_user(TARGET_NR_sigreturn, (int *)(frame->retcode+2));
bellard775b58d2007-11-11 16:22:17 +0000856 val16 = 0x80cd;
857 err |= __put_user(val16, (uint16_t *)(frame->retcode+6));
bellard66fb9762003-03-23 01:06:05 +0000858 }
859
860 if (err)
861 goto give_sigsegv;
862
863 /* Set up registers for signal handler */
bellard28be6232007-11-11 22:23:38 +0000864 env->regs[R_ESP] = frame_addr;
pbrook624f7972008-05-31 16:11:38 +0000865 env->eip = ka->_sa_handler;
bellard66fb9762003-03-23 01:06:05 +0000866
867 cpu_x86_load_seg(env, R_DS, __USER_DS);
868 cpu_x86_load_seg(env, R_ES, __USER_DS);
869 cpu_x86_load_seg(env, R_SS, __USER_DS);
870 cpu_x86_load_seg(env, R_CS, __USER_CS);
871 env->eflags &= ~TF_MASK;
872
bellard579a97f2007-11-11 14:26:47 +0000873 unlock_user_struct(frame, frame_addr, 1);
874
bellard66fb9762003-03-23 01:06:05 +0000875 return;
876
877give_sigsegv:
bellard579a97f2007-11-11 14:26:47 +0000878 unlock_user_struct(frame, frame_addr, 1);
bellard66fb9762003-03-23 01:06:05 +0000879 if (sig == TARGET_SIGSEGV)
pbrook624f7972008-05-31 16:11:38 +0000880 ka->_sa_handler = TARGET_SIG_DFL;
bellard66fb9762003-03-23 01:06:05 +0000881 force_sig(TARGET_SIGSEGV /* , current */);
882}
883
bellard579a97f2007-11-11 14:26:47 +0000884/* compare linux/arch/i386/kernel/signal.c:setup_rt_frame() */
pbrook624f7972008-05-31 16:11:38 +0000885static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -0500886 target_siginfo_t *info,
887 target_sigset_t *set, CPUX86State *env)
bellard66fb9762003-03-23 01:06:05 +0000888{
bellard28be6232007-11-11 22:23:38 +0000889 abi_ulong frame_addr, addr;
bellard66fb9762003-03-23 01:06:05 +0000890 struct rt_sigframe *frame;
bellard92319442004-06-19 16:58:13 +0000891 int i, err = 0;
bellard66fb9762003-03-23 01:06:05 +0000892
bellard579a97f2007-11-11 14:26:47 +0000893 frame_addr = get_sigframe(ka, env, sizeof(*frame));
bellard66fb9762003-03-23 01:06:05 +0000894
bellard579a97f2007-11-11 14:26:47 +0000895 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
bellard66fb9762003-03-23 01:06:05 +0000896 goto give_sigsegv;
bellard66fb9762003-03-23 01:06:05 +0000897
thsc3b5bc82007-12-02 06:31:25 +0000898 err |= __put_user(current_exec_domain_sig(sig),
bellard66fb9762003-03-23 01:06:05 +0000899 &frame->sig);
bellard28be6232007-11-11 22:23:38 +0000900 addr = frame_addr + offsetof(struct rt_sigframe, info);
901 err |= __put_user(addr, &frame->pinfo);
902 addr = frame_addr + offsetof(struct rt_sigframe, uc);
903 err |= __put_user(addr, &frame->puc);
bellard66fb9762003-03-23 01:06:05 +0000904 err |= copy_siginfo_to_user(&frame->info, info);
905 if (err)
906 goto give_sigsegv;
907
908 /* Create the ucontext. */
bellardb8076a72005-04-07 22:20:31 +0000909 err |= __put_user(0, &frame->uc.tuc_flags);
910 err |= __put_user(0, &frame->uc.tuc_link);
thsa04e1342007-09-27 13:57:58 +0000911 err |= __put_user(target_sigaltstack_used.ss_sp,
bellardb8076a72005-04-07 22:20:31 +0000912 &frame->uc.tuc_stack.ss_sp);
thsa04e1342007-09-27 13:57:58 +0000913 err |= __put_user(sas_ss_flags(get_sp_from_cpustate(env)),
bellardb8076a72005-04-07 22:20:31 +0000914 &frame->uc.tuc_stack.ss_flags);
thsa04e1342007-09-27 13:57:58 +0000915 err |= __put_user(target_sigaltstack_used.ss_size,
bellardb8076a72005-04-07 22:20:31 +0000916 &frame->uc.tuc_stack.ss_size);
917 err |= setup_sigcontext(&frame->uc.tuc_mcontext, &frame->fpstate,
bellard28be6232007-11-11 22:23:38 +0000918 env, set->sig[0],
919 frame_addr + offsetof(struct rt_sigframe, fpstate));
bellard92319442004-06-19 16:58:13 +0000920 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
bellardb8076a72005-04-07 22:20:31 +0000921 if (__put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]))
bellard92319442004-06-19 16:58:13 +0000922 goto give_sigsegv;
923 }
bellard66fb9762003-03-23 01:06:05 +0000924
925 /* Set up to return from userspace. If provided, use a stub
926 already in userspace. */
pbrook624f7972008-05-31 16:11:38 +0000927 if (ka->sa_flags & TARGET_SA_RESTORER) {
928 err |= __put_user(ka->sa_restorer, &frame->pretcode);
bellard66fb9762003-03-23 01:06:05 +0000929 } else {
bellard775b58d2007-11-11 16:22:17 +0000930 uint16_t val16;
bellard28be6232007-11-11 22:23:38 +0000931 addr = frame_addr + offsetof(struct rt_sigframe, retcode);
932 err |= __put_user(addr, &frame->pretcode);
bellard66fb9762003-03-23 01:06:05 +0000933 /* This is movl $,%eax ; int $0x80 */
bellard775b58d2007-11-11 16:22:17 +0000934 err |= __put_user(0xb8, (char *)(frame->retcode+0));
bellard66fb9762003-03-23 01:06:05 +0000935 err |= __put_user(TARGET_NR_rt_sigreturn, (int *)(frame->retcode+1));
bellard775b58d2007-11-11 16:22:17 +0000936 val16 = 0x80cd;
937 err |= __put_user(val16, (uint16_t *)(frame->retcode+5));
bellard66fb9762003-03-23 01:06:05 +0000938 }
939
940 if (err)
941 goto give_sigsegv;
942
943 /* Set up registers for signal handler */
bellard28be6232007-11-11 22:23:38 +0000944 env->regs[R_ESP] = frame_addr;
pbrook624f7972008-05-31 16:11:38 +0000945 env->eip = ka->_sa_handler;
bellard66fb9762003-03-23 01:06:05 +0000946
947 cpu_x86_load_seg(env, R_DS, __USER_DS);
948 cpu_x86_load_seg(env, R_ES, __USER_DS);
949 cpu_x86_load_seg(env, R_SS, __USER_DS);
950 cpu_x86_load_seg(env, R_CS, __USER_CS);
951 env->eflags &= ~TF_MASK;
952
bellard579a97f2007-11-11 14:26:47 +0000953 unlock_user_struct(frame, frame_addr, 1);
954
bellard66fb9762003-03-23 01:06:05 +0000955 return;
956
957give_sigsegv:
bellard579a97f2007-11-11 14:26:47 +0000958 unlock_user_struct(frame, frame_addr, 1);
bellard66fb9762003-03-23 01:06:05 +0000959 if (sig == TARGET_SIGSEGV)
pbrook624f7972008-05-31 16:11:38 +0000960 ka->_sa_handler = TARGET_SIG_DFL;
bellard66fb9762003-03-23 01:06:05 +0000961 force_sig(TARGET_SIGSEGV /* , current */);
962}
963
964static int
965restore_sigcontext(CPUX86State *env, struct target_sigcontext *sc, int *peax)
966{
967 unsigned int err = 0;
bellard28be6232007-11-11 22:23:38 +0000968 abi_ulong fpstate_addr;
969 unsigned int tmpflags;
bellard66fb9762003-03-23 01:06:05 +0000970
bellard28be6232007-11-11 22:23:38 +0000971 cpu_x86_load_seg(env, R_GS, tswap16(sc->gs));
972 cpu_x86_load_seg(env, R_FS, tswap16(sc->fs));
973 cpu_x86_load_seg(env, R_ES, tswap16(sc->es));
974 cpu_x86_load_seg(env, R_DS, tswap16(sc->ds));
bellard66fb9762003-03-23 01:06:05 +0000975
bellard28be6232007-11-11 22:23:38 +0000976 env->regs[R_EDI] = tswapl(sc->edi);
977 env->regs[R_ESI] = tswapl(sc->esi);
978 env->regs[R_EBP] = tswapl(sc->ebp);
979 env->regs[R_ESP] = tswapl(sc->esp);
980 env->regs[R_EBX] = tswapl(sc->ebx);
981 env->regs[R_EDX] = tswapl(sc->edx);
982 env->regs[R_ECX] = tswapl(sc->ecx);
983 env->eip = tswapl(sc->eip);
bellard66fb9762003-03-23 01:06:05 +0000984
985 cpu_x86_load_seg(env, R_CS, lduw(&sc->cs) | 3);
986 cpu_x86_load_seg(env, R_SS, lduw(&sc->ss) | 3);
ths5fafdf22007-09-16 21:08:06 +0000987
bellard28be6232007-11-11 22:23:38 +0000988 tmpflags = tswapl(sc->eflags);
989 env->eflags = (env->eflags & ~0x40DD5) | (tmpflags & 0x40DD5);
990 // regs->orig_eax = -1; /* disable syscall checks */
991
992 fpstate_addr = tswapl(sc->fpstate);
993 if (fpstate_addr != 0) {
994 if (!access_ok(VERIFY_READ, fpstate_addr,
995 sizeof(struct target_fpstate)))
996 goto badframe;
997 cpu_x86_frstor(env, fpstate_addr, 1);
bellard66fb9762003-03-23 01:06:05 +0000998 }
999
bellard28be6232007-11-11 22:23:38 +00001000 *peax = tswapl(sc->eax);
bellard66fb9762003-03-23 01:06:05 +00001001 return err;
bellard66fb9762003-03-23 01:06:05 +00001002badframe:
1003 return 1;
bellard66fb9762003-03-23 01:06:05 +00001004}
1005
1006long do_sigreturn(CPUX86State *env)
1007{
bellard579a97f2007-11-11 14:26:47 +00001008 struct sigframe *frame;
1009 abi_ulong frame_addr = env->regs[R_ESP] - 8;
Anthony Liguoric227f092009-10-01 16:12:16 -05001010 target_sigset_t target_set;
bellard66fb9762003-03-23 01:06:05 +00001011 sigset_t set;
1012 int eax, i;
1013
bellard447db212003-05-10 15:10:36 +00001014#if defined(DEBUG_SIGNAL)
1015 fprintf(stderr, "do_sigreturn\n");
1016#endif
bellard579a97f2007-11-11 14:26:47 +00001017 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
1018 goto badframe;
bellard66fb9762003-03-23 01:06:05 +00001019 /* set blocked signals */
bellard92319442004-06-19 16:58:13 +00001020 if (__get_user(target_set.sig[0], &frame->sc.oldmask))
1021 goto badframe;
1022 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
1023 if (__get_user(target_set.sig[i], &frame->extramask[i - 1]))
1024 goto badframe;
1025 }
bellard66fb9762003-03-23 01:06:05 +00001026
bellard92319442004-06-19 16:58:13 +00001027 target_to_host_sigset_internal(&set, &target_set);
bellard66fb9762003-03-23 01:06:05 +00001028 sigprocmask(SIG_SETMASK, &set, NULL);
ths3b46e622007-09-17 08:09:54 +00001029
bellard66fb9762003-03-23 01:06:05 +00001030 /* restore registers */
1031 if (restore_sigcontext(env, &frame->sc, &eax))
1032 goto badframe;
bellard579a97f2007-11-11 14:26:47 +00001033 unlock_user_struct(frame, frame_addr, 0);
bellard66fb9762003-03-23 01:06:05 +00001034 return eax;
1035
1036badframe:
bellard579a97f2007-11-11 14:26:47 +00001037 unlock_user_struct(frame, frame_addr, 0);
bellard66fb9762003-03-23 01:06:05 +00001038 force_sig(TARGET_SIGSEGV);
1039 return 0;
1040}
1041
1042long do_rt_sigreturn(CPUX86State *env)
1043{
bellard28be6232007-11-11 22:23:38 +00001044 abi_ulong frame_addr;
1045 struct rt_sigframe *frame;
bellard66fb9762003-03-23 01:06:05 +00001046 sigset_t set;
bellard66fb9762003-03-23 01:06:05 +00001047 int eax;
1048
bellard28be6232007-11-11 22:23:38 +00001049 frame_addr = env->regs[R_ESP] - 4;
1050 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
1051 goto badframe;
bellardb8076a72005-04-07 22:20:31 +00001052 target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
bellard66fb9762003-03-23 01:06:05 +00001053 sigprocmask(SIG_SETMASK, &set, NULL);
ths5fafdf22007-09-16 21:08:06 +00001054
bellardb8076a72005-04-07 22:20:31 +00001055 if (restore_sigcontext(env, &frame->uc.tuc_mcontext, &eax))
bellard66fb9762003-03-23 01:06:05 +00001056 goto badframe;
1057
bellard28be6232007-11-11 22:23:38 +00001058 if (do_sigaltstack(frame_addr + offsetof(struct rt_sigframe, uc.tuc_stack), 0,
1059 get_sp_from_cpustate(env)) == -EFAULT)
bellard66fb9762003-03-23 01:06:05 +00001060 goto badframe;
thsa04e1342007-09-27 13:57:58 +00001061
bellard28be6232007-11-11 22:23:38 +00001062 unlock_user_struct(frame, frame_addr, 0);
bellard66fb9762003-03-23 01:06:05 +00001063 return eax;
1064
1065badframe:
bellard28be6232007-11-11 22:23:38 +00001066 unlock_user_struct(frame, frame_addr, 0);
1067 force_sig(TARGET_SIGSEGV);
bellard66fb9762003-03-23 01:06:05 +00001068 return 0;
1069}
1070
bellard43fff232003-07-09 19:31:39 +00001071#elif defined(TARGET_ARM)
1072
1073struct target_sigcontext {
blueswir1992f48a2007-10-14 16:27:31 +00001074 abi_ulong trap_no;
1075 abi_ulong error_code;
1076 abi_ulong oldmask;
1077 abi_ulong arm_r0;
1078 abi_ulong arm_r1;
1079 abi_ulong arm_r2;
1080 abi_ulong arm_r3;
1081 abi_ulong arm_r4;
1082 abi_ulong arm_r5;
1083 abi_ulong arm_r6;
1084 abi_ulong arm_r7;
1085 abi_ulong arm_r8;
1086 abi_ulong arm_r9;
1087 abi_ulong arm_r10;
1088 abi_ulong arm_fp;
1089 abi_ulong arm_ip;
1090 abi_ulong arm_sp;
1091 abi_ulong arm_lr;
1092 abi_ulong arm_pc;
1093 abi_ulong arm_cpsr;
1094 abi_ulong fault_address;
bellard43fff232003-07-09 19:31:39 +00001095};
1096
pbrooka745ec62008-05-06 15:36:17 +00001097struct target_ucontext_v1 {
blueswir1992f48a2007-10-14 16:27:31 +00001098 abi_ulong tuc_flags;
1099 abi_ulong tuc_link;
Anthony Liguoric227f092009-10-01 16:12:16 -05001100 target_stack_t tuc_stack;
bellardb8076a72005-04-07 22:20:31 +00001101 struct target_sigcontext tuc_mcontext;
Anthony Liguoric227f092009-10-01 16:12:16 -05001102 target_sigset_t tuc_sigmask; /* mask last for extensibility */
bellard43fff232003-07-09 19:31:39 +00001103};
1104
pbrooka745ec62008-05-06 15:36:17 +00001105struct target_ucontext_v2 {
1106 abi_ulong tuc_flags;
1107 abi_ulong tuc_link;
Anthony Liguoric227f092009-10-01 16:12:16 -05001108 target_stack_t tuc_stack;
pbrooka745ec62008-05-06 15:36:17 +00001109 struct target_sigcontext tuc_mcontext;
Anthony Liguoric227f092009-10-01 16:12:16 -05001110 target_sigset_t tuc_sigmask; /* mask last for extensibility */
Peter Maydell5f0b7c82010-11-24 15:20:03 +00001111 char __unused[128 - sizeof(target_sigset_t)];
pbrooka745ec62008-05-06 15:36:17 +00001112 abi_ulong tuc_regspace[128] __attribute__((__aligned__(8)));
1113};
1114
Peter Maydell0d871bd2010-11-24 15:20:05 +00001115struct target_user_vfp {
1116 uint64_t fpregs[32];
1117 abi_ulong fpscr;
1118};
1119
1120struct target_user_vfp_exc {
1121 abi_ulong fpexc;
1122 abi_ulong fpinst;
1123 abi_ulong fpinst2;
1124};
1125
1126struct target_vfp_sigframe {
1127 abi_ulong magic;
1128 abi_ulong size;
1129 struct target_user_vfp ufp;
1130 struct target_user_vfp_exc ufp_exc;
1131} __attribute__((__aligned__(8)));
1132
Peter Maydell08e11252010-11-24 15:20:07 +00001133struct target_iwmmxt_sigframe {
1134 abi_ulong magic;
1135 abi_ulong size;
1136 uint64_t regs[16];
1137 /* Note that not all the coprocessor control registers are stored here */
1138 uint32_t wcssf;
1139 uint32_t wcasf;
1140 uint32_t wcgr0;
1141 uint32_t wcgr1;
1142 uint32_t wcgr2;
1143 uint32_t wcgr3;
1144} __attribute__((__aligned__(8)));
1145
Peter Maydell0d871bd2010-11-24 15:20:05 +00001146#define TARGET_VFP_MAGIC 0x56465001
Peter Maydell08e11252010-11-24 15:20:07 +00001147#define TARGET_IWMMXT_MAGIC 0x12ef842a
Peter Maydell0d871bd2010-11-24 15:20:05 +00001148
pbrooka8c33202008-05-07 23:22:46 +00001149struct sigframe_v1
bellard43fff232003-07-09 19:31:39 +00001150{
1151 struct target_sigcontext sc;
blueswir1992f48a2007-10-14 16:27:31 +00001152 abi_ulong extramask[TARGET_NSIG_WORDS-1];
1153 abi_ulong retcode;
bellard43fff232003-07-09 19:31:39 +00001154};
1155
pbrooka8c33202008-05-07 23:22:46 +00001156struct sigframe_v2
1157{
1158 struct target_ucontext_v2 uc;
1159 abi_ulong retcode;
1160};
1161
pbrooka745ec62008-05-06 15:36:17 +00001162struct rt_sigframe_v1
bellard43fff232003-07-09 19:31:39 +00001163{
bellardf8b0aa22007-11-11 23:03:42 +00001164 abi_ulong pinfo;
1165 abi_ulong puc;
bellard43fff232003-07-09 19:31:39 +00001166 struct target_siginfo info;
pbrooka745ec62008-05-06 15:36:17 +00001167 struct target_ucontext_v1 uc;
1168 abi_ulong retcode;
1169};
1170
1171struct rt_sigframe_v2
1172{
1173 struct target_siginfo info;
1174 struct target_ucontext_v2 uc;
blueswir1992f48a2007-10-14 16:27:31 +00001175 abi_ulong retcode;
bellard43fff232003-07-09 19:31:39 +00001176};
1177
1178#define TARGET_CONFIG_CPU_32 1
1179
1180/*
1181 * For ARM syscalls, we encode the syscall number into the instruction.
1182 */
1183#define SWI_SYS_SIGRETURN (0xef000000|(TARGET_NR_sigreturn + ARM_SYSCALL_BASE))
1184#define SWI_SYS_RT_SIGRETURN (0xef000000|(TARGET_NR_rt_sigreturn + ARM_SYSCALL_BASE))
1185
1186/*
1187 * For Thumb syscalls, we pass the syscall number via r7. We therefore
1188 * need two 16-bit instructions.
1189 */
1190#define SWI_THUMB_SIGRETURN (0xdf00 << 16 | 0x2700 | (TARGET_NR_sigreturn))
1191#define SWI_THUMB_RT_SIGRETURN (0xdf00 << 16 | 0x2700 | (TARGET_NR_rt_sigreturn))
1192
blueswir1992f48a2007-10-14 16:27:31 +00001193static const abi_ulong retcodes[4] = {
bellard43fff232003-07-09 19:31:39 +00001194 SWI_SYS_SIGRETURN, SWI_THUMB_SIGRETURN,
1195 SWI_SYS_RT_SIGRETURN, SWI_THUMB_RT_SIGRETURN
1196};
1197
1198
bellard43fff232003-07-09 19:31:39 +00001199#define __get_user_error(x,p,e) __get_user(x, p)
1200
1201static inline int valid_user_regs(CPUState *regs)
1202{
1203 return 1;
1204}
1205
pbrooka8c33202008-05-07 23:22:46 +00001206static void
bellard43fff232003-07-09 19:31:39 +00001207setup_sigcontext(struct target_sigcontext *sc, /*struct _fpstate *fpstate,*/
bellardf8b0aa22007-11-11 23:03:42 +00001208 CPUState *env, abi_ulong mask)
bellard43fff232003-07-09 19:31:39 +00001209{
pbrooka8c33202008-05-07 23:22:46 +00001210 __put_user(env->regs[0], &sc->arm_r0);
1211 __put_user(env->regs[1], &sc->arm_r1);
1212 __put_user(env->regs[2], &sc->arm_r2);
1213 __put_user(env->regs[3], &sc->arm_r3);
1214 __put_user(env->regs[4], &sc->arm_r4);
1215 __put_user(env->regs[5], &sc->arm_r5);
1216 __put_user(env->regs[6], &sc->arm_r6);
1217 __put_user(env->regs[7], &sc->arm_r7);
1218 __put_user(env->regs[8], &sc->arm_r8);
1219 __put_user(env->regs[9], &sc->arm_r9);
1220 __put_user(env->regs[10], &sc->arm_r10);
1221 __put_user(env->regs[11], &sc->arm_fp);
1222 __put_user(env->regs[12], &sc->arm_ip);
1223 __put_user(env->regs[13], &sc->arm_sp);
1224 __put_user(env->regs[14], &sc->arm_lr);
1225 __put_user(env->regs[15], &sc->arm_pc);
bellard43fff232003-07-09 19:31:39 +00001226#ifdef TARGET_CONFIG_CPU_32
pbrooka8c33202008-05-07 23:22:46 +00001227 __put_user(cpsr_read(env), &sc->arm_cpsr);
bellard43fff232003-07-09 19:31:39 +00001228#endif
1229
pbrooka8c33202008-05-07 23:22:46 +00001230 __put_user(/* current->thread.trap_no */ 0, &sc->trap_no);
1231 __put_user(/* current->thread.error_code */ 0, &sc->error_code);
1232 __put_user(/* current->thread.address */ 0, &sc->fault_address);
1233 __put_user(mask, &sc->oldmask);
bellard43fff232003-07-09 19:31:39 +00001234}
1235
bellard579a97f2007-11-11 14:26:47 +00001236static inline abi_ulong
pbrook624f7972008-05-31 16:11:38 +00001237get_sigframe(struct target_sigaction *ka, CPUState *regs, int framesize)
bellard43fff232003-07-09 19:31:39 +00001238{
1239 unsigned long sp = regs->regs[13];
1240
bellard43fff232003-07-09 19:31:39 +00001241 /*
1242 * This is the X/Open sanctioned signal stack switching.
1243 */
pbrook624f7972008-05-31 16:11:38 +00001244 if ((ka->sa_flags & TARGET_SA_ONSTACK) && !sas_ss_flags(sp))
thsa04e1342007-09-27 13:57:58 +00001245 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
bellard43fff232003-07-09 19:31:39 +00001246 /*
1247 * ATPCS B01 mandates 8-byte alignment
1248 */
bellard579a97f2007-11-11 14:26:47 +00001249 return (sp - framesize) & ~7;
bellard43fff232003-07-09 19:31:39 +00001250}
1251
1252static int
pbrook624f7972008-05-31 16:11:38 +00001253setup_return(CPUState *env, struct target_sigaction *ka,
bellardf8b0aa22007-11-11 23:03:42 +00001254 abi_ulong *rc, abi_ulong frame_addr, int usig, abi_ulong rc_addr)
bellard43fff232003-07-09 19:31:39 +00001255{
pbrook624f7972008-05-31 16:11:38 +00001256 abi_ulong handler = ka->_sa_handler;
blueswir1992f48a2007-10-14 16:27:31 +00001257 abi_ulong retcode;
pbrook75b680e2008-03-21 16:07:30 +00001258 int thumb = handler & 1;
Peter Maydell964413d2011-01-14 20:39:19 +01001259 uint32_t cpsr = cpsr_read(env);
1260
1261 cpsr &= ~CPSR_IT;
1262 if (thumb) {
1263 cpsr |= CPSR_T;
1264 } else {
1265 cpsr &= ~CPSR_T;
1266 }
bellard43fff232003-07-09 19:31:39 +00001267
pbrook624f7972008-05-31 16:11:38 +00001268 if (ka->sa_flags & TARGET_SA_RESTORER) {
1269 retcode = ka->sa_restorer;
bellard43fff232003-07-09 19:31:39 +00001270 } else {
1271 unsigned int idx = thumb;
1272
pbrook624f7972008-05-31 16:11:38 +00001273 if (ka->sa_flags & TARGET_SA_SIGINFO)
bellard43fff232003-07-09 19:31:39 +00001274 idx += 2;
1275
1276 if (__put_user(retcodes[idx], rc))
1277 return 1;
1278#if 0
blueswir1992f48a2007-10-14 16:27:31 +00001279 flush_icache_range((abi_ulong)rc,
1280 (abi_ulong)(rc + 1));
bellard43fff232003-07-09 19:31:39 +00001281#endif
bellardf8b0aa22007-11-11 23:03:42 +00001282 retcode = rc_addr + thumb;
bellard43fff232003-07-09 19:31:39 +00001283 }
1284
1285 env->regs[0] = usig;
bellardf8b0aa22007-11-11 23:03:42 +00001286 env->regs[13] = frame_addr;
bellard43fff232003-07-09 19:31:39 +00001287 env->regs[14] = retcode;
1288 env->regs[15] = handler & (thumb ? ~1 : ~3);
Peter Maydell964413d2011-01-14 20:39:19 +01001289 cpsr_write(env, cpsr, 0xffffffff);
bellard43fff232003-07-09 19:31:39 +00001290
1291 return 0;
1292}
1293
Peter Maydell0d871bd2010-11-24 15:20:05 +00001294static abi_ulong *setup_sigframe_v2_vfp(abi_ulong *regspace, CPUState *env)
1295{
1296 int i;
1297 struct target_vfp_sigframe *vfpframe;
1298 vfpframe = (struct target_vfp_sigframe *)regspace;
1299 __put_user(TARGET_VFP_MAGIC, &vfpframe->magic);
1300 __put_user(sizeof(*vfpframe), &vfpframe->size);
1301 for (i = 0; i < 32; i++) {
1302 __put_user(env->vfp.regs[i], &vfpframe->ufp.fpregs[i]);
1303 }
1304 __put_user(vfp_get_fpscr(env), &vfpframe->ufp.fpscr);
1305 __put_user(env->vfp.xregs[ARM_VFP_FPEXC], &vfpframe->ufp_exc.fpexc);
1306 __put_user(env->vfp.xregs[ARM_VFP_FPINST], &vfpframe->ufp_exc.fpinst);
1307 __put_user(env->vfp.xregs[ARM_VFP_FPINST2], &vfpframe->ufp_exc.fpinst2);
1308 return (abi_ulong*)(vfpframe+1);
1309}
1310
Peter Maydell08e11252010-11-24 15:20:07 +00001311static abi_ulong *setup_sigframe_v2_iwmmxt(abi_ulong *regspace, CPUState *env)
1312{
1313 int i;
1314 struct target_iwmmxt_sigframe *iwmmxtframe;
1315 iwmmxtframe = (struct target_iwmmxt_sigframe *)regspace;
1316 __put_user(TARGET_IWMMXT_MAGIC, &iwmmxtframe->magic);
1317 __put_user(sizeof(*iwmmxtframe), &iwmmxtframe->size);
1318 for (i = 0; i < 16; i++) {
1319 __put_user(env->iwmmxt.regs[i], &iwmmxtframe->regs[i]);
1320 }
1321 __put_user(env->vfp.xregs[ARM_IWMMXT_wCSSF], &iwmmxtframe->wcssf);
1322 __put_user(env->vfp.xregs[ARM_IWMMXT_wCASF], &iwmmxtframe->wcssf);
1323 __put_user(env->vfp.xregs[ARM_IWMMXT_wCGR0], &iwmmxtframe->wcgr0);
1324 __put_user(env->vfp.xregs[ARM_IWMMXT_wCGR1], &iwmmxtframe->wcgr1);
1325 __put_user(env->vfp.xregs[ARM_IWMMXT_wCGR2], &iwmmxtframe->wcgr2);
1326 __put_user(env->vfp.xregs[ARM_IWMMXT_wCGR3], &iwmmxtframe->wcgr3);
1327 return (abi_ulong*)(iwmmxtframe+1);
1328}
1329
pbrooka8c33202008-05-07 23:22:46 +00001330static void setup_sigframe_v2(struct target_ucontext_v2 *uc,
Anthony Liguoric227f092009-10-01 16:12:16 -05001331 target_sigset_t *set, CPUState *env)
bellard43fff232003-07-09 19:31:39 +00001332{
pbrooka8c33202008-05-07 23:22:46 +00001333 struct target_sigaltstack stack;
1334 int i;
Peter Maydell0d871bd2010-11-24 15:20:05 +00001335 abi_ulong *regspace;
pbrooka8c33202008-05-07 23:22:46 +00001336
1337 /* Clear all the bits of the ucontext we don't use. */
1338 memset(uc, 0, offsetof(struct target_ucontext_v2, tuc_mcontext));
1339
1340 memset(&stack, 0, sizeof(stack));
1341 __put_user(target_sigaltstack_used.ss_sp, &stack.ss_sp);
1342 __put_user(target_sigaltstack_used.ss_size, &stack.ss_size);
1343 __put_user(sas_ss_flags(get_sp_from_cpustate(env)), &stack.ss_flags);
1344 memcpy(&uc->tuc_stack, &stack, sizeof(stack));
1345
1346 setup_sigcontext(&uc->tuc_mcontext, env, set->sig[0]);
Peter Maydell0d871bd2010-11-24 15:20:05 +00001347 /* Save coprocessor signal frame. */
1348 regspace = uc->tuc_regspace;
1349 if (arm_feature(env, ARM_FEATURE_VFP)) {
1350 regspace = setup_sigframe_v2_vfp(regspace, env);
1351 }
Peter Maydell08e11252010-11-24 15:20:07 +00001352 if (arm_feature(env, ARM_FEATURE_IWMMXT)) {
1353 regspace = setup_sigframe_v2_iwmmxt(regspace, env);
1354 }
1355
Peter Maydell0d871bd2010-11-24 15:20:05 +00001356 /* Write terminating magic word */
1357 __put_user(0, regspace);
1358
pbrooka8c33202008-05-07 23:22:46 +00001359 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
1360 __put_user(set->sig[i], &uc->tuc_sigmask.sig[i]);
1361 }
1362}
1363
1364/* compare linux/arch/arm/kernel/signal.c:setup_frame() */
pbrook624f7972008-05-31 16:11:38 +00001365static void setup_frame_v1(int usig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05001366 target_sigset_t *set, CPUState *regs)
pbrooka8c33202008-05-07 23:22:46 +00001367{
1368 struct sigframe_v1 *frame;
bellard579a97f2007-11-11 14:26:47 +00001369 abi_ulong frame_addr = get_sigframe(ka, regs, sizeof(*frame));
pbrooka8c33202008-05-07 23:22:46 +00001370 int i;
bellard43fff232003-07-09 19:31:39 +00001371
bellard579a97f2007-11-11 14:26:47 +00001372 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
1373 return;
1374
pbrooka8c33202008-05-07 23:22:46 +00001375 setup_sigcontext(&frame->sc, regs, set->sig[0]);
bellard43fff232003-07-09 19:31:39 +00001376
bellard92319442004-06-19 16:58:13 +00001377 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
1378 if (__put_user(set->sig[i], &frame->extramask[i - 1]))
bellard579a97f2007-11-11 14:26:47 +00001379 goto end;
bellard43fff232003-07-09 19:31:39 +00001380 }
1381
pbrooka8c33202008-05-07 23:22:46 +00001382 setup_return(regs, ka, &frame->retcode, frame_addr, usig,
1383 frame_addr + offsetof(struct sigframe_v1, retcode));
bellard579a97f2007-11-11 14:26:47 +00001384
1385end:
1386 unlock_user_struct(frame, frame_addr, 1);
pbrooka8c33202008-05-07 23:22:46 +00001387}
1388
pbrook624f7972008-05-31 16:11:38 +00001389static void setup_frame_v2(int usig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05001390 target_sigset_t *set, CPUState *regs)
pbrooka8c33202008-05-07 23:22:46 +00001391{
1392 struct sigframe_v2 *frame;
1393 abi_ulong frame_addr = get_sigframe(ka, regs, sizeof(*frame));
1394
1395 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
1396 return;
1397
1398 setup_sigframe_v2(&frame->uc, set, regs);
1399
1400 setup_return(regs, ka, &frame->retcode, frame_addr, usig,
1401 frame_addr + offsetof(struct sigframe_v2, retcode));
1402
1403 unlock_user_struct(frame, frame_addr, 1);
1404}
1405
pbrook624f7972008-05-31 16:11:38 +00001406static void setup_frame(int usig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05001407 target_sigset_t *set, CPUState *regs)
pbrooka8c33202008-05-07 23:22:46 +00001408{
1409 if (get_osversion() >= 0x020612) {
1410 setup_frame_v2(usig, ka, set, regs);
1411 } else {
1412 setup_frame_v1(usig, ka, set, regs);
1413 }
bellard43fff232003-07-09 19:31:39 +00001414}
1415
bellard579a97f2007-11-11 14:26:47 +00001416/* compare linux/arch/arm/kernel/signal.c:setup_rt_frame() */
pbrook624f7972008-05-31 16:11:38 +00001417static void setup_rt_frame_v1(int usig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05001418 target_siginfo_t *info,
1419 target_sigset_t *set, CPUState *env)
bellard43fff232003-07-09 19:31:39 +00001420{
pbrooka745ec62008-05-06 15:36:17 +00001421 struct rt_sigframe_v1 *frame;
bellard579a97f2007-11-11 14:26:47 +00001422 abi_ulong frame_addr = get_sigframe(ka, env, sizeof(*frame));
thsa04e1342007-09-27 13:57:58 +00001423 struct target_sigaltstack stack;
pbrooka8c33202008-05-07 23:22:46 +00001424 int i;
bellardf8b0aa22007-11-11 23:03:42 +00001425 abi_ulong info_addr, uc_addr;
bellard43fff232003-07-09 19:31:39 +00001426
bellard579a97f2007-11-11 14:26:47 +00001427 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
bellardedf779f2004-02-22 13:40:13 +00001428 return /* 1 */;
1429
pbrooka745ec62008-05-06 15:36:17 +00001430 info_addr = frame_addr + offsetof(struct rt_sigframe_v1, info);
pbrooka8c33202008-05-07 23:22:46 +00001431 __put_user(info_addr, &frame->pinfo);
pbrooka745ec62008-05-06 15:36:17 +00001432 uc_addr = frame_addr + offsetof(struct rt_sigframe_v1, uc);
pbrooka8c33202008-05-07 23:22:46 +00001433 __put_user(uc_addr, &frame->puc);
1434 copy_siginfo_to_user(&frame->info, info);
bellard43fff232003-07-09 19:31:39 +00001435
1436 /* Clear all the bits of the ucontext we don't use. */
pbrooka745ec62008-05-06 15:36:17 +00001437 memset(&frame->uc, 0, offsetof(struct target_ucontext_v1, tuc_mcontext));
bellard43fff232003-07-09 19:31:39 +00001438
thsa04e1342007-09-27 13:57:58 +00001439 memset(&stack, 0, sizeof(stack));
1440 __put_user(target_sigaltstack_used.ss_sp, &stack.ss_sp);
1441 __put_user(target_sigaltstack_used.ss_size, &stack.ss_size);
1442 __put_user(sas_ss_flags(get_sp_from_cpustate(env)), &stack.ss_flags);
bellard775b58d2007-11-11 16:22:17 +00001443 memcpy(&frame->uc.tuc_stack, &stack, sizeof(stack));
thsa04e1342007-09-27 13:57:58 +00001444
pbrooka8c33202008-05-07 23:22:46 +00001445 setup_sigcontext(&frame->uc.tuc_mcontext, env, set->sig[0]);
bellard92319442004-06-19 16:58:13 +00001446 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
bellardb8076a72005-04-07 22:20:31 +00001447 if (__put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]))
bellard579a97f2007-11-11 14:26:47 +00001448 goto end;
bellard92319442004-06-19 16:58:13 +00001449 }
bellard43fff232003-07-09 19:31:39 +00001450
pbrooka8c33202008-05-07 23:22:46 +00001451 setup_return(env, ka, &frame->retcode, frame_addr, usig,
1452 frame_addr + offsetof(struct rt_sigframe_v1, retcode));
pbrooka745ec62008-05-06 15:36:17 +00001453
pbrooka8c33202008-05-07 23:22:46 +00001454 env->regs[1] = info_addr;
1455 env->regs[2] = uc_addr;
pbrooka745ec62008-05-06 15:36:17 +00001456
1457end:
1458 unlock_user_struct(frame, frame_addr, 1);
pbrooka745ec62008-05-06 15:36:17 +00001459}
1460
pbrook624f7972008-05-31 16:11:38 +00001461static void setup_rt_frame_v2(int usig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05001462 target_siginfo_t *info,
1463 target_sigset_t *set, CPUState *env)
pbrooka745ec62008-05-06 15:36:17 +00001464{
1465 struct rt_sigframe_v2 *frame;
1466 abi_ulong frame_addr = get_sigframe(ka, env, sizeof(*frame));
pbrooka745ec62008-05-06 15:36:17 +00001467 abi_ulong info_addr, uc_addr;
1468
1469 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
1470 return /* 1 */;
1471
1472 info_addr = frame_addr + offsetof(struct rt_sigframe_v2, info);
1473 uc_addr = frame_addr + offsetof(struct rt_sigframe_v2, uc);
pbrooka8c33202008-05-07 23:22:46 +00001474 copy_siginfo_to_user(&frame->info, info);
pbrooka745ec62008-05-06 15:36:17 +00001475
pbrooka8c33202008-05-07 23:22:46 +00001476 setup_sigframe_v2(&frame->uc, set, env);
pbrooka745ec62008-05-06 15:36:17 +00001477
pbrooka8c33202008-05-07 23:22:46 +00001478 setup_return(env, ka, &frame->retcode, frame_addr, usig,
1479 frame_addr + offsetof(struct rt_sigframe_v2, retcode));
pbrooka745ec62008-05-06 15:36:17 +00001480
pbrooka8c33202008-05-07 23:22:46 +00001481 env->regs[1] = info_addr;
1482 env->regs[2] = uc_addr;
pbrooka745ec62008-05-06 15:36:17 +00001483
bellard579a97f2007-11-11 14:26:47 +00001484 unlock_user_struct(frame, frame_addr, 1);
bellard43fff232003-07-09 19:31:39 +00001485}
1486
pbrook624f7972008-05-31 16:11:38 +00001487static void setup_rt_frame(int usig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05001488 target_siginfo_t *info,
1489 target_sigset_t *set, CPUState *env)
pbrooka745ec62008-05-06 15:36:17 +00001490{
1491 if (get_osversion() >= 0x020612) {
1492 setup_rt_frame_v2(usig, ka, info, set, env);
1493 } else {
1494 setup_rt_frame_v1(usig, ka, info, set, env);
1495 }
1496}
1497
bellard43fff232003-07-09 19:31:39 +00001498static int
1499restore_sigcontext(CPUState *env, struct target_sigcontext *sc)
1500{
1501 int err = 0;
bellardb5ff1b32005-11-26 10:38:39 +00001502 uint32_t cpsr;
bellard43fff232003-07-09 19:31:39 +00001503
1504 __get_user_error(env->regs[0], &sc->arm_r0, err);
1505 __get_user_error(env->regs[1], &sc->arm_r1, err);
1506 __get_user_error(env->regs[2], &sc->arm_r2, err);
1507 __get_user_error(env->regs[3], &sc->arm_r3, err);
1508 __get_user_error(env->regs[4], &sc->arm_r4, err);
1509 __get_user_error(env->regs[5], &sc->arm_r5, err);
1510 __get_user_error(env->regs[6], &sc->arm_r6, err);
1511 __get_user_error(env->regs[7], &sc->arm_r7, err);
1512 __get_user_error(env->regs[8], &sc->arm_r8, err);
1513 __get_user_error(env->regs[9], &sc->arm_r9, err);
1514 __get_user_error(env->regs[10], &sc->arm_r10, err);
1515 __get_user_error(env->regs[11], &sc->arm_fp, err);
1516 __get_user_error(env->regs[12], &sc->arm_ip, err);
1517 __get_user_error(env->regs[13], &sc->arm_sp, err);
1518 __get_user_error(env->regs[14], &sc->arm_lr, err);
1519 __get_user_error(env->regs[15], &sc->arm_pc, err);
1520#ifdef TARGET_CONFIG_CPU_32
bellardb5ff1b32005-11-26 10:38:39 +00001521 __get_user_error(cpsr, &sc->arm_cpsr, err);
pbrook75b680e2008-03-21 16:07:30 +00001522 cpsr_write(env, cpsr, CPSR_USER | CPSR_EXEC);
bellard43fff232003-07-09 19:31:39 +00001523#endif
1524
1525 err |= !valid_user_regs(env);
1526
1527 return err;
1528}
1529
aurel32dc7eea62009-01-30 20:15:32 +00001530static long do_sigreturn_v1(CPUState *env)
bellard43fff232003-07-09 19:31:39 +00001531{
bellardf8b0aa22007-11-11 23:03:42 +00001532 abi_ulong frame_addr;
pbrooka8c33202008-05-07 23:22:46 +00001533 struct sigframe_v1 *frame;
Anthony Liguoric227f092009-10-01 16:12:16 -05001534 target_sigset_t set;
bellard43fff232003-07-09 19:31:39 +00001535 sigset_t host_set;
bellard92319442004-06-19 16:58:13 +00001536 int i;
bellard43fff232003-07-09 19:31:39 +00001537
1538 /*
1539 * Since we stacked the signal on a 64-bit boundary,
1540 * then 'sp' should be word aligned here. If it's
1541 * not, then the user is trying to mess with us.
1542 */
1543 if (env->regs[13] & 7)
1544 goto badframe;
1545
bellardf8b0aa22007-11-11 23:03:42 +00001546 frame_addr = env->regs[13];
1547 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
1548 goto badframe;
bellard43fff232003-07-09 19:31:39 +00001549
bellard92319442004-06-19 16:58:13 +00001550 if (__get_user(set.sig[0], &frame->sc.oldmask))
1551 goto badframe;
1552 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
1553 if (__get_user(set.sig[i], &frame->extramask[i - 1]))
1554 goto badframe;
1555 }
bellard43fff232003-07-09 19:31:39 +00001556
bellard92319442004-06-19 16:58:13 +00001557 target_to_host_sigset_internal(&host_set, &set);
bellard43fff232003-07-09 19:31:39 +00001558 sigprocmask(SIG_SETMASK, &host_set, NULL);
1559
1560 if (restore_sigcontext(env, &frame->sc))
1561 goto badframe;
1562
1563#if 0
1564 /* Send SIGTRAP if we're single-stepping */
1565 if (ptrace_cancel_bpt(current))
1566 send_sig(SIGTRAP, current, 1);
1567#endif
bellardf8b0aa22007-11-11 23:03:42 +00001568 unlock_user_struct(frame, frame_addr, 0);
1569 return env->regs[0];
bellard43fff232003-07-09 19:31:39 +00001570
1571badframe:
bellardf8b0aa22007-11-11 23:03:42 +00001572 unlock_user_struct(frame, frame_addr, 0);
Riku Voipio66393fb2009-12-04 15:16:32 +02001573 force_sig(TARGET_SIGSEGV /* , current */);
bellard43fff232003-07-09 19:31:39 +00001574 return 0;
1575}
1576
Peter Maydell5f9099d2010-11-24 15:20:06 +00001577static abi_ulong *restore_sigframe_v2_vfp(CPUState *env, abi_ulong *regspace)
1578{
1579 int i;
1580 abi_ulong magic, sz;
1581 uint32_t fpscr, fpexc;
1582 struct target_vfp_sigframe *vfpframe;
1583 vfpframe = (struct target_vfp_sigframe *)regspace;
1584
1585 __get_user(magic, &vfpframe->magic);
1586 __get_user(sz, &vfpframe->size);
1587 if (magic != TARGET_VFP_MAGIC || sz != sizeof(*vfpframe)) {
1588 return 0;
1589 }
1590 for (i = 0; i < 32; i++) {
1591 __get_user(env->vfp.regs[i], &vfpframe->ufp.fpregs[i]);
1592 }
1593 __get_user(fpscr, &vfpframe->ufp.fpscr);
1594 vfp_set_fpscr(env, fpscr);
1595 __get_user(fpexc, &vfpframe->ufp_exc.fpexc);
1596 /* Sanitise FPEXC: ensure VFP is enabled, FPINST2 is invalid
1597 * and the exception flag is cleared
1598 */
1599 fpexc |= (1 << 30);
1600 fpexc &= ~((1 << 31) | (1 << 28));
1601 env->vfp.xregs[ARM_VFP_FPEXC] = fpexc;
1602 __get_user(env->vfp.xregs[ARM_VFP_FPINST], &vfpframe->ufp_exc.fpinst);
1603 __get_user(env->vfp.xregs[ARM_VFP_FPINST2], &vfpframe->ufp_exc.fpinst2);
1604 return (abi_ulong*)(vfpframe + 1);
1605}
1606
Peter Maydella59d69d2010-11-24 15:20:08 +00001607static abi_ulong *restore_sigframe_v2_iwmmxt(CPUState *env, abi_ulong *regspace)
1608{
1609 int i;
1610 abi_ulong magic, sz;
1611 struct target_iwmmxt_sigframe *iwmmxtframe;
1612 iwmmxtframe = (struct target_iwmmxt_sigframe *)regspace;
1613
1614 __get_user(magic, &iwmmxtframe->magic);
1615 __get_user(sz, &iwmmxtframe->size);
1616 if (magic != TARGET_IWMMXT_MAGIC || sz != sizeof(*iwmmxtframe)) {
1617 return 0;
1618 }
1619 for (i = 0; i < 16; i++) {
1620 __get_user(env->iwmmxt.regs[i], &iwmmxtframe->regs[i]);
1621 }
1622 __get_user(env->vfp.xregs[ARM_IWMMXT_wCSSF], &iwmmxtframe->wcssf);
1623 __get_user(env->vfp.xregs[ARM_IWMMXT_wCASF], &iwmmxtframe->wcssf);
1624 __get_user(env->vfp.xregs[ARM_IWMMXT_wCGR0], &iwmmxtframe->wcgr0);
1625 __get_user(env->vfp.xregs[ARM_IWMMXT_wCGR1], &iwmmxtframe->wcgr1);
1626 __get_user(env->vfp.xregs[ARM_IWMMXT_wCGR2], &iwmmxtframe->wcgr2);
1627 __get_user(env->vfp.xregs[ARM_IWMMXT_wCGR3], &iwmmxtframe->wcgr3);
1628 return (abi_ulong*)(iwmmxtframe + 1);
1629}
1630
pbrooka8c33202008-05-07 23:22:46 +00001631static int do_sigframe_return_v2(CPUState *env, target_ulong frame_addr,
1632 struct target_ucontext_v2 *uc)
1633{
1634 sigset_t host_set;
Peter Maydell5f9099d2010-11-24 15:20:06 +00001635 abi_ulong *regspace;
pbrooka8c33202008-05-07 23:22:46 +00001636
1637 target_to_host_sigset(&host_set, &uc->tuc_sigmask);
1638 sigprocmask(SIG_SETMASK, &host_set, NULL);
1639
1640 if (restore_sigcontext(env, &uc->tuc_mcontext))
1641 return 1;
1642
Peter Maydell5f9099d2010-11-24 15:20:06 +00001643 /* Restore coprocessor signal frame */
1644 regspace = uc->tuc_regspace;
1645 if (arm_feature(env, ARM_FEATURE_VFP)) {
1646 regspace = restore_sigframe_v2_vfp(env, regspace);
1647 if (!regspace) {
1648 return 1;
1649 }
1650 }
Peter Maydella59d69d2010-11-24 15:20:08 +00001651 if (arm_feature(env, ARM_FEATURE_IWMMXT)) {
1652 regspace = restore_sigframe_v2_iwmmxt(env, regspace);
1653 if (!regspace) {
1654 return 1;
1655 }
1656 }
Peter Maydell5f9099d2010-11-24 15:20:06 +00001657
pbrooka8c33202008-05-07 23:22:46 +00001658 if (do_sigaltstack(frame_addr + offsetof(struct target_ucontext_v2, tuc_stack), 0, get_sp_from_cpustate(env)) == -EFAULT)
1659 return 1;
1660
1661#if 0
1662 /* Send SIGTRAP if we're single-stepping */
1663 if (ptrace_cancel_bpt(current))
1664 send_sig(SIGTRAP, current, 1);
1665#endif
1666
1667 return 0;
1668}
1669
aurel32dc7eea62009-01-30 20:15:32 +00001670static long do_sigreturn_v2(CPUState *env)
pbrooka8c33202008-05-07 23:22:46 +00001671{
1672 abi_ulong frame_addr;
1673 struct sigframe_v2 *frame;
1674
1675 /*
1676 * Since we stacked the signal on a 64-bit boundary,
1677 * then 'sp' should be word aligned here. If it's
1678 * not, then the user is trying to mess with us.
1679 */
1680 if (env->regs[13] & 7)
1681 goto badframe;
1682
1683 frame_addr = env->regs[13];
1684 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
1685 goto badframe;
1686
1687 if (do_sigframe_return_v2(env, frame_addr, &frame->uc))
1688 goto badframe;
1689
1690 unlock_user_struct(frame, frame_addr, 0);
1691 return env->regs[0];
1692
1693badframe:
1694 unlock_user_struct(frame, frame_addr, 0);
Riku Voipio66393fb2009-12-04 15:16:32 +02001695 force_sig(TARGET_SIGSEGV /* , current */);
pbrooka8c33202008-05-07 23:22:46 +00001696 return 0;
1697}
1698
1699long do_sigreturn(CPUState *env)
1700{
1701 if (get_osversion() >= 0x020612) {
1702 return do_sigreturn_v2(env);
1703 } else {
1704 return do_sigreturn_v1(env);
1705 }
1706}
1707
aurel32dc7eea62009-01-30 20:15:32 +00001708static long do_rt_sigreturn_v1(CPUState *env)
bellard43fff232003-07-09 19:31:39 +00001709{
bellardf8b0aa22007-11-11 23:03:42 +00001710 abi_ulong frame_addr;
pbrooka745ec62008-05-06 15:36:17 +00001711 struct rt_sigframe_v1 *frame;
bellard43fff232003-07-09 19:31:39 +00001712 sigset_t host_set;
1713
1714 /*
1715 * Since we stacked the signal on a 64-bit boundary,
1716 * then 'sp' should be word aligned here. If it's
1717 * not, then the user is trying to mess with us.
1718 */
1719 if (env->regs[13] & 7)
1720 goto badframe;
1721
bellardf8b0aa22007-11-11 23:03:42 +00001722 frame_addr = env->regs[13];
1723 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
1724 goto badframe;
bellard43fff232003-07-09 19:31:39 +00001725
bellardb8076a72005-04-07 22:20:31 +00001726 target_to_host_sigset(&host_set, &frame->uc.tuc_sigmask);
bellard43fff232003-07-09 19:31:39 +00001727 sigprocmask(SIG_SETMASK, &host_set, NULL);
1728
bellardb8076a72005-04-07 22:20:31 +00001729 if (restore_sigcontext(env, &frame->uc.tuc_mcontext))
bellard43fff232003-07-09 19:31:39 +00001730 goto badframe;
1731
pbrooka745ec62008-05-06 15:36:17 +00001732 if (do_sigaltstack(frame_addr + offsetof(struct rt_sigframe_v1, uc.tuc_stack), 0, get_sp_from_cpustate(env)) == -EFAULT)
thsa04e1342007-09-27 13:57:58 +00001733 goto badframe;
1734
bellard43fff232003-07-09 19:31:39 +00001735#if 0
1736 /* Send SIGTRAP if we're single-stepping */
1737 if (ptrace_cancel_bpt(current))
1738 send_sig(SIGTRAP, current, 1);
1739#endif
bellardf8b0aa22007-11-11 23:03:42 +00001740 unlock_user_struct(frame, frame_addr, 0);
bellard43fff232003-07-09 19:31:39 +00001741 return env->regs[0];
1742
1743badframe:
bellardf8b0aa22007-11-11 23:03:42 +00001744 unlock_user_struct(frame, frame_addr, 0);
Riku Voipio66393fb2009-12-04 15:16:32 +02001745 force_sig(TARGET_SIGSEGV /* , current */);
bellard43fff232003-07-09 19:31:39 +00001746 return 0;
1747}
1748
aurel32dc7eea62009-01-30 20:15:32 +00001749static long do_rt_sigreturn_v2(CPUState *env)
pbrooka745ec62008-05-06 15:36:17 +00001750{
1751 abi_ulong frame_addr;
1752 struct rt_sigframe_v2 *frame;
pbrooka745ec62008-05-06 15:36:17 +00001753
1754 /*
1755 * Since we stacked the signal on a 64-bit boundary,
1756 * then 'sp' should be word aligned here. If it's
1757 * not, then the user is trying to mess with us.
1758 */
1759 if (env->regs[13] & 7)
1760 goto badframe;
1761
1762 frame_addr = env->regs[13];
1763 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
1764 goto badframe;
1765
pbrooka8c33202008-05-07 23:22:46 +00001766 if (do_sigframe_return_v2(env, frame_addr, &frame->uc))
1767 goto badframe;
pbrooka745ec62008-05-06 15:36:17 +00001768
pbrooka745ec62008-05-06 15:36:17 +00001769 unlock_user_struct(frame, frame_addr, 0);
1770 return env->regs[0];
1771
1772badframe:
1773 unlock_user_struct(frame, frame_addr, 0);
Riku Voipio66393fb2009-12-04 15:16:32 +02001774 force_sig(TARGET_SIGSEGV /* , current */);
pbrooka745ec62008-05-06 15:36:17 +00001775 return 0;
1776}
1777
1778long do_rt_sigreturn(CPUState *env)
1779{
1780 if (get_osversion() >= 0x020612) {
1781 return do_rt_sigreturn_v2(env);
1782 } else {
1783 return do_rt_sigreturn_v1(env);
1784 }
1785}
1786
bellard6d5e2162004-09-30 22:04:13 +00001787#elif defined(TARGET_SPARC)
bellard80a9d032005-01-03 23:31:27 +00001788
bellard6d5e2162004-09-30 22:04:13 +00001789#define __SUNOS_MAXWIN 31
1790
1791/* This is what SunOS does, so shall I. */
1792struct target_sigcontext {
blueswir1992f48a2007-10-14 16:27:31 +00001793 abi_ulong sigc_onstack; /* state to restore */
bellard6d5e2162004-09-30 22:04:13 +00001794
blueswir1992f48a2007-10-14 16:27:31 +00001795 abi_ulong sigc_mask; /* sigmask to restore */
1796 abi_ulong sigc_sp; /* stack pointer */
1797 abi_ulong sigc_pc; /* program counter */
1798 abi_ulong sigc_npc; /* next program counter */
1799 abi_ulong sigc_psr; /* for condition codes etc */
1800 abi_ulong sigc_g1; /* User uses these two registers */
1801 abi_ulong sigc_o0; /* within the trampoline code. */
bellard6d5e2162004-09-30 22:04:13 +00001802
1803 /* Now comes information regarding the users window set
1804 * at the time of the signal.
1805 */
blueswir1992f48a2007-10-14 16:27:31 +00001806 abi_ulong sigc_oswins; /* outstanding windows */
bellard6d5e2162004-09-30 22:04:13 +00001807
1808 /* stack ptrs for each regwin buf */
1809 char *sigc_spbuf[__SUNOS_MAXWIN];
1810
1811 /* Windows to restore after signal */
1812 struct {
blueswir1992f48a2007-10-14 16:27:31 +00001813 abi_ulong locals[8];
1814 abi_ulong ins[8];
bellard6d5e2162004-09-30 22:04:13 +00001815 } sigc_wbuf[__SUNOS_MAXWIN];
1816};
1817/* A Sparc stack frame */
1818struct sparc_stackf {
blueswir1992f48a2007-10-14 16:27:31 +00001819 abi_ulong locals[8];
1820 abi_ulong ins[6];
bellard6d5e2162004-09-30 22:04:13 +00001821 struct sparc_stackf *fp;
blueswir1992f48a2007-10-14 16:27:31 +00001822 abi_ulong callers_pc;
bellard6d5e2162004-09-30 22:04:13 +00001823 char *structptr;
blueswir1992f48a2007-10-14 16:27:31 +00001824 abi_ulong xargs[6];
1825 abi_ulong xxargs[1];
bellard6d5e2162004-09-30 22:04:13 +00001826};
1827
1828typedef struct {
1829 struct {
blueswir1992f48a2007-10-14 16:27:31 +00001830 abi_ulong psr;
1831 abi_ulong pc;
1832 abi_ulong npc;
1833 abi_ulong y;
1834 abi_ulong u_regs[16]; /* globals and ins */
bellard6d5e2162004-09-30 22:04:13 +00001835 } si_regs;
1836 int si_mask;
1837} __siginfo_t;
1838
1839typedef struct {
1840 unsigned long si_float_regs [32];
1841 unsigned long si_fsr;
1842 unsigned long si_fpqdepth;
1843 struct {
1844 unsigned long *insn_addr;
1845 unsigned long insn;
1846 } si_fpqueue [16];
Anthony Liguoric227f092009-10-01 16:12:16 -05001847} qemu_siginfo_fpu_t;
bellard6d5e2162004-09-30 22:04:13 +00001848
1849
1850struct target_signal_frame {
1851 struct sparc_stackf ss;
1852 __siginfo_t info;
bellardf8b0aa22007-11-11 23:03:42 +00001853 abi_ulong fpu_save;
blueswir1992f48a2007-10-14 16:27:31 +00001854 abi_ulong insns[2] __attribute__ ((aligned (8)));
1855 abi_ulong extramask[TARGET_NSIG_WORDS - 1];
1856 abi_ulong extra_size; /* Should be 0 */
Anthony Liguoric227f092009-10-01 16:12:16 -05001857 qemu_siginfo_fpu_t fpu_state;
bellard6d5e2162004-09-30 22:04:13 +00001858};
1859struct target_rt_signal_frame {
1860 struct sparc_stackf ss;
1861 siginfo_t info;
blueswir1992f48a2007-10-14 16:27:31 +00001862 abi_ulong regs[20];
bellard6d5e2162004-09-30 22:04:13 +00001863 sigset_t mask;
bellardf8b0aa22007-11-11 23:03:42 +00001864 abi_ulong fpu_save;
bellard6d5e2162004-09-30 22:04:13 +00001865 unsigned int insns[2];
1866 stack_t stack;
1867 unsigned int extra_size; /* Should be 0 */
Anthony Liguoric227f092009-10-01 16:12:16 -05001868 qemu_siginfo_fpu_t fpu_state;
bellard6d5e2162004-09-30 22:04:13 +00001869};
1870
bellarde80cfcf2004-12-19 23:18:01 +00001871#define UREG_O0 16
1872#define UREG_O6 22
1873#define UREG_I0 0
1874#define UREG_I1 1
1875#define UREG_I2 2
blueswir15bfb56b2007-10-05 17:01:51 +00001876#define UREG_I3 3
1877#define UREG_I4 4
1878#define UREG_I5 5
bellarde80cfcf2004-12-19 23:18:01 +00001879#define UREG_I6 6
1880#define UREG_I7 7
1881#define UREG_L0 8
bellard6d5e2162004-09-30 22:04:13 +00001882#define UREG_FP UREG_I6
1883#define UREG_SP UREG_O6
1884
pbrook624f7972008-05-31 16:11:38 +00001885static inline abi_ulong get_sigframe(struct target_sigaction *sa,
bellard459a4012007-11-11 19:45:10 +00001886 CPUState *env, unsigned long framesize)
bellard6d5e2162004-09-30 22:04:13 +00001887{
bellard459a4012007-11-11 19:45:10 +00001888 abi_ulong sp;
bellard6d5e2162004-09-30 22:04:13 +00001889
1890 sp = env->regwptr[UREG_FP];
bellard6d5e2162004-09-30 22:04:13 +00001891
1892 /* This is the X/Open sanctioned signal stack switching. */
pbrook624f7972008-05-31 16:11:38 +00001893 if (sa->sa_flags & TARGET_SA_ONSTACK) {
thsa04e1342007-09-27 13:57:58 +00001894 if (!on_sig_stack(sp)
1895 && !((target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size) & 7))
1896 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
bellard6d5e2162004-09-30 22:04:13 +00001897 }
bellard459a4012007-11-11 19:45:10 +00001898 return sp - framesize;
bellard6d5e2162004-09-30 22:04:13 +00001899}
1900
1901static int
blueswir1992f48a2007-10-14 16:27:31 +00001902setup___siginfo(__siginfo_t *si, CPUState *env, abi_ulong mask)
bellard6d5e2162004-09-30 22:04:13 +00001903{
1904 int err = 0, i;
1905
bellard6d5e2162004-09-30 22:04:13 +00001906 err |= __put_user(env->psr, &si->si_regs.psr);
bellard6d5e2162004-09-30 22:04:13 +00001907 err |= __put_user(env->pc, &si->si_regs.pc);
1908 err |= __put_user(env->npc, &si->si_regs.npc);
1909 err |= __put_user(env->y, &si->si_regs.y);
bellarda315a142005-01-30 22:59:18 +00001910 for (i=0; i < 8; i++) {
bellard6d5e2162004-09-30 22:04:13 +00001911 err |= __put_user(env->gregs[i], &si->si_regs.u_regs[i]);
1912 }
bellarda315a142005-01-30 22:59:18 +00001913 for (i=0; i < 8; i++) {
bellarde80cfcf2004-12-19 23:18:01 +00001914 err |= __put_user(env->regwptr[UREG_I0 + i], &si->si_regs.u_regs[i+8]);
bellard6d5e2162004-09-30 22:04:13 +00001915 }
bellard6d5e2162004-09-30 22:04:13 +00001916 err |= __put_user(mask, &si->si_mask);
1917 return err;
1918}
bellarde80cfcf2004-12-19 23:18:01 +00001919
bellard80a9d032005-01-03 23:31:27 +00001920#if 0
bellard6d5e2162004-09-30 22:04:13 +00001921static int
1922setup_sigcontext(struct target_sigcontext *sc, /*struct _fpstate *fpstate,*/
1923 CPUState *env, unsigned long mask)
1924{
1925 int err = 0;
1926
1927 err |= __put_user(mask, &sc->sigc_mask);
1928 err |= __put_user(env->regwptr[UREG_SP], &sc->sigc_sp);
1929 err |= __put_user(env->pc, &sc->sigc_pc);
1930 err |= __put_user(env->npc, &sc->sigc_npc);
1931 err |= __put_user(env->psr, &sc->sigc_psr);
1932 err |= __put_user(env->gregs[1], &sc->sigc_g1);
1933 err |= __put_user(env->regwptr[UREG_O0], &sc->sigc_o0);
1934
1935 return err;
1936}
bellard80a9d032005-01-03 23:31:27 +00001937#endif
bellard6d5e2162004-09-30 22:04:13 +00001938#define NF_ALIGNEDSZ (((sizeof(struct target_signal_frame) + 7) & (~7)))
1939
pbrook624f7972008-05-31 16:11:38 +00001940static void setup_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05001941 target_sigset_t *set, CPUState *env)
bellard6d5e2162004-09-30 22:04:13 +00001942{
bellard459a4012007-11-11 19:45:10 +00001943 abi_ulong sf_addr;
bellard6d5e2162004-09-30 22:04:13 +00001944 struct target_signal_frame *sf;
1945 int sigframe_size, err, i;
1946
1947 /* 1. Make sure everything is clean */
1948 //synchronize_user_stack();
1949
1950 sigframe_size = NF_ALIGNEDSZ;
bellard459a4012007-11-11 19:45:10 +00001951 sf_addr = get_sigframe(ka, env, sigframe_size);
bellard6d5e2162004-09-30 22:04:13 +00001952
bellard459a4012007-11-11 19:45:10 +00001953 sf = lock_user(VERIFY_WRITE, sf_addr,
1954 sizeof(struct target_signal_frame), 0);
1955 if (!sf)
1956 goto sigsegv;
1957
bellarde80cfcf2004-12-19 23:18:01 +00001958 //fprintf(stderr, "sf: %x pc %x fp %x sp %x\n", sf, env->pc, env->regwptr[UREG_FP], env->regwptr[UREG_SP]);
bellard6d5e2162004-09-30 22:04:13 +00001959#if 0
1960 if (invalid_frame_pointer(sf, sigframe_size))
1961 goto sigill_and_return;
1962#endif
1963 /* 2. Save the current process state */
1964 err = setup___siginfo(&sf->info, env, set->sig[0]);
1965 err |= __put_user(0, &sf->extra_size);
1966
1967 //err |= save_fpu_state(regs, &sf->fpu_state);
1968 //err |= __put_user(&sf->fpu_state, &sf->fpu_save);
1969
1970 err |= __put_user(set->sig[0], &sf->info.si_mask);
1971 for (i = 0; i < TARGET_NSIG_WORDS - 1; i++) {
1972 err |= __put_user(set->sig[i + 1], &sf->extramask[i]);
1973 }
1974
bellarda315a142005-01-30 22:59:18 +00001975 for (i = 0; i < 8; i++) {
bellarde80cfcf2004-12-19 23:18:01 +00001976 err |= __put_user(env->regwptr[i + UREG_L0], &sf->ss.locals[i]);
bellard6d5e2162004-09-30 22:04:13 +00001977 }
bellarda315a142005-01-30 22:59:18 +00001978 for (i = 0; i < 8; i++) {
bellarde80cfcf2004-12-19 23:18:01 +00001979 err |= __put_user(env->regwptr[i + UREG_I0], &sf->ss.ins[i]);
bellard6d5e2162004-09-30 22:04:13 +00001980 }
bellard6d5e2162004-09-30 22:04:13 +00001981 if (err)
1982 goto sigsegv;
1983
1984 /* 3. signal handler back-trampoline and parameters */
bellard459a4012007-11-11 19:45:10 +00001985 env->regwptr[UREG_FP] = sf_addr;
bellard6d5e2162004-09-30 22:04:13 +00001986 env->regwptr[UREG_I0] = sig;
bellard459a4012007-11-11 19:45:10 +00001987 env->regwptr[UREG_I1] = sf_addr +
1988 offsetof(struct target_signal_frame, info);
1989 env->regwptr[UREG_I2] = sf_addr +
1990 offsetof(struct target_signal_frame, info);
bellard6d5e2162004-09-30 22:04:13 +00001991
1992 /* 4. signal handler */
pbrook624f7972008-05-31 16:11:38 +00001993 env->pc = ka->_sa_handler;
bellard6d5e2162004-09-30 22:04:13 +00001994 env->npc = (env->pc + 4);
1995 /* 5. return to kernel instructions */
pbrook624f7972008-05-31 16:11:38 +00001996 if (ka->sa_restorer)
1997 env->regwptr[UREG_I7] = ka->sa_restorer;
bellard6d5e2162004-09-30 22:04:13 +00001998 else {
bellard775b58d2007-11-11 16:22:17 +00001999 uint32_t val32;
bellard459a4012007-11-11 19:45:10 +00002000
2001 env->regwptr[UREG_I7] = sf_addr +
2002 offsetof(struct target_signal_frame, insns) - 2 * 4;
bellard6d5e2162004-09-30 22:04:13 +00002003
2004 /* mov __NR_sigreturn, %g1 */
bellard775b58d2007-11-11 16:22:17 +00002005 val32 = 0x821020d8;
2006 err |= __put_user(val32, &sf->insns[0]);
bellard6d5e2162004-09-30 22:04:13 +00002007
2008 /* t 0x10 */
bellard775b58d2007-11-11 16:22:17 +00002009 val32 = 0x91d02010;
2010 err |= __put_user(val32, &sf->insns[1]);
bellard6d5e2162004-09-30 22:04:13 +00002011 if (err)
2012 goto sigsegv;
2013
2014 /* Flush instruction space. */
2015 //flush_sig_insns(current->mm, (unsigned long) &(sf->insns[0]));
bellard80a9d032005-01-03 23:31:27 +00002016 // tb_flush(env);
bellard6d5e2162004-09-30 22:04:13 +00002017 }
bellard459a4012007-11-11 19:45:10 +00002018 unlock_user(sf, sf_addr, sizeof(struct target_signal_frame));
bellard6d5e2162004-09-30 22:04:13 +00002019 return;
bellard459a4012007-11-11 19:45:10 +00002020#if 0
2021sigill_and_return:
bellard6d5e2162004-09-30 22:04:13 +00002022 force_sig(TARGET_SIGILL);
bellard459a4012007-11-11 19:45:10 +00002023#endif
bellard6d5e2162004-09-30 22:04:13 +00002024sigsegv:
bellarde80cfcf2004-12-19 23:18:01 +00002025 //fprintf(stderr, "force_sig\n");
bellard459a4012007-11-11 19:45:10 +00002026 unlock_user(sf, sf_addr, sizeof(struct target_signal_frame));
bellard6d5e2162004-09-30 22:04:13 +00002027 force_sig(TARGET_SIGSEGV);
2028}
2029static inline int
Anthony Liguoric227f092009-10-01 16:12:16 -05002030restore_fpu_state(CPUState *env, qemu_siginfo_fpu_t *fpu)
bellard6d5e2162004-09-30 22:04:13 +00002031{
2032 int err;
2033#if 0
2034#ifdef CONFIG_SMP
2035 if (current->flags & PF_USEDFPU)
2036 regs->psr &= ~PSR_EF;
2037#else
2038 if (current == last_task_used_math) {
2039 last_task_used_math = 0;
2040 regs->psr &= ~PSR_EF;
2041 }
2042#endif
2043 current->used_math = 1;
2044 current->flags &= ~PF_USEDFPU;
2045#endif
2046#if 0
2047 if (verify_area (VERIFY_READ, fpu, sizeof(*fpu)))
2048 return -EFAULT;
2049#endif
2050
bellardfafffae2006-10-28 12:09:16 +00002051#if 0
2052 /* XXX: incorrect */
bellard6d5e2162004-09-30 22:04:13 +00002053 err = __copy_from_user(&env->fpr[0], &fpu->si_float_regs[0],
2054 (sizeof(unsigned long) * 32));
bellardfafffae2006-10-28 12:09:16 +00002055#endif
bellard6d5e2162004-09-30 22:04:13 +00002056 err |= __get_user(env->fsr, &fpu->si_fsr);
2057#if 0
2058 err |= __get_user(current->thread.fpqdepth, &fpu->si_fpqdepth);
2059 if (current->thread.fpqdepth != 0)
2060 err |= __copy_from_user(&current->thread.fpqueue[0],
2061 &fpu->si_fpqueue[0],
2062 ((sizeof(unsigned long) +
2063 (sizeof(unsigned long *)))*16));
2064#endif
2065 return err;
2066}
2067
2068
pbrook624f7972008-05-31 16:11:38 +00002069static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05002070 target_siginfo_t *info,
2071 target_sigset_t *set, CPUState *env)
bellard6d5e2162004-09-30 22:04:13 +00002072{
2073 fprintf(stderr, "setup_rt_frame: not implemented\n");
2074}
2075
2076long do_sigreturn(CPUState *env)
2077{
bellardf8b0aa22007-11-11 23:03:42 +00002078 abi_ulong sf_addr;
bellard6d5e2162004-09-30 22:04:13 +00002079 struct target_signal_frame *sf;
bellarde80cfcf2004-12-19 23:18:01 +00002080 uint32_t up_psr, pc, npc;
Anthony Liguoric227f092009-10-01 16:12:16 -05002081 target_sigset_t set;
bellarde80cfcf2004-12-19 23:18:01 +00002082 sigset_t host_set;
bellardf8b0aa22007-11-11 23:03:42 +00002083 abi_ulong fpu_save_addr;
bellarde80cfcf2004-12-19 23:18:01 +00002084 int err, i;
bellard6d5e2162004-09-30 22:04:13 +00002085
bellardf8b0aa22007-11-11 23:03:42 +00002086 sf_addr = env->regwptr[UREG_FP];
2087 if (!lock_user_struct(VERIFY_READ, sf, sf_addr, 1))
2088 goto segv_and_exit;
bellard80a9d032005-01-03 23:31:27 +00002089#if 0
bellarde80cfcf2004-12-19 23:18:01 +00002090 fprintf(stderr, "sigreturn\n");
2091 fprintf(stderr, "sf: %x pc %x fp %x sp %x\n", sf, env->pc, env->regwptr[UREG_FP], env->regwptr[UREG_SP]);
bellard80a9d032005-01-03 23:31:27 +00002092#endif
bellarde80cfcf2004-12-19 23:18:01 +00002093 //cpu_dump_state(env, stderr, fprintf, 0);
bellard6d5e2162004-09-30 22:04:13 +00002094
2095 /* 1. Make sure we are not getting garbage from the user */
bellard6d5e2162004-09-30 22:04:13 +00002096
bellardf8b0aa22007-11-11 23:03:42 +00002097 if (sf_addr & 3)
bellard6d5e2162004-09-30 22:04:13 +00002098 goto segv_and_exit;
2099
2100 err = __get_user(pc, &sf->info.si_regs.pc);
2101 err |= __get_user(npc, &sf->info.si_regs.npc);
2102
bellard6d5e2162004-09-30 22:04:13 +00002103 if ((pc | npc) & 3)
2104 goto segv_and_exit;
2105
2106 /* 2. Restore the state */
bellarde80cfcf2004-12-19 23:18:01 +00002107 err |= __get_user(up_psr, &sf->info.si_regs.psr);
2108
bellard6d5e2162004-09-30 22:04:13 +00002109 /* User can only change condition codes and FPU enabling in %psr. */
bellarda315a142005-01-30 22:59:18 +00002110 env->psr = (up_psr & (PSR_ICC /* | PSR_EF */))
2111 | (env->psr & ~(PSR_ICC /* | PSR_EF */));
2112
2113 env->pc = pc;
2114 env->npc = npc;
bellarde80cfcf2004-12-19 23:18:01 +00002115 err |= __get_user(env->y, &sf->info.si_regs.y);
bellarda315a142005-01-30 22:59:18 +00002116 for (i=0; i < 8; i++) {
bellarde80cfcf2004-12-19 23:18:01 +00002117 err |= __get_user(env->gregs[i], &sf->info.si_regs.u_regs[i]);
2118 }
bellarda315a142005-01-30 22:59:18 +00002119 for (i=0; i < 8; i++) {
bellarde80cfcf2004-12-19 23:18:01 +00002120 err |= __get_user(env->regwptr[i + UREG_I0], &sf->info.si_regs.u_regs[i+8]);
2121 }
bellard6d5e2162004-09-30 22:04:13 +00002122
bellardf8b0aa22007-11-11 23:03:42 +00002123 err |= __get_user(fpu_save_addr, &sf->fpu_save);
bellard6d5e2162004-09-30 22:04:13 +00002124
bellarde80cfcf2004-12-19 23:18:01 +00002125 //if (fpu_save)
2126 // err |= restore_fpu_state(env, fpu_save);
bellard6d5e2162004-09-30 22:04:13 +00002127
2128 /* This is pretty much atomic, no amount locking would prevent
2129 * the races which exist anyways.
2130 */
2131 err |= __get_user(set.sig[0], &sf->info.si_mask);
bellarde80cfcf2004-12-19 23:18:01 +00002132 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
2133 err |= (__get_user(set.sig[i], &sf->extramask[i - 1]));
2134 }
2135
2136 target_to_host_sigset_internal(&host_set, &set);
2137 sigprocmask(SIG_SETMASK, &host_set, NULL);
bellard6d5e2162004-09-30 22:04:13 +00002138
2139 if (err)
2140 goto segv_and_exit;
bellardf8b0aa22007-11-11 23:03:42 +00002141 unlock_user_struct(sf, sf_addr, 0);
bellard6d5e2162004-09-30 22:04:13 +00002142 return env->regwptr[0];
2143
2144segv_and_exit:
bellardf8b0aa22007-11-11 23:03:42 +00002145 unlock_user_struct(sf, sf_addr, 0);
bellard6d5e2162004-09-30 22:04:13 +00002146 force_sig(TARGET_SIGSEGV);
2147}
2148
2149long do_rt_sigreturn(CPUState *env)
2150{
2151 fprintf(stderr, "do_rt_sigreturn: not implemented\n");
bellardf8b0aa22007-11-11 23:03:42 +00002152 return -TARGET_ENOSYS;
bellard6d5e2162004-09-30 22:04:13 +00002153}
2154
bellard459a4012007-11-11 19:45:10 +00002155#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
blueswir15bfb56b2007-10-05 17:01:51 +00002156#define MC_TSTATE 0
2157#define MC_PC 1
2158#define MC_NPC 2
2159#define MC_Y 3
2160#define MC_G1 4
2161#define MC_G2 5
2162#define MC_G3 6
2163#define MC_G4 7
2164#define MC_G5 8
2165#define MC_G6 9
2166#define MC_G7 10
2167#define MC_O0 11
2168#define MC_O1 12
2169#define MC_O2 13
2170#define MC_O3 14
2171#define MC_O4 15
2172#define MC_O5 16
2173#define MC_O6 17
2174#define MC_O7 18
2175#define MC_NGREG 19
2176
Anthony Liguoric227f092009-10-01 16:12:16 -05002177typedef abi_ulong target_mc_greg_t;
2178typedef target_mc_greg_t target_mc_gregset_t[MC_NGREG];
blueswir15bfb56b2007-10-05 17:01:51 +00002179
2180struct target_mc_fq {
blueswir1992f48a2007-10-14 16:27:31 +00002181 abi_ulong *mcfq_addr;
blueswir15bfb56b2007-10-05 17:01:51 +00002182 uint32_t mcfq_insn;
2183};
2184
2185struct target_mc_fpu {
2186 union {
2187 uint32_t sregs[32];
2188 uint64_t dregs[32];
2189 //uint128_t qregs[16];
2190 } mcfpu_fregs;
blueswir1992f48a2007-10-14 16:27:31 +00002191 abi_ulong mcfpu_fsr;
2192 abi_ulong mcfpu_fprs;
2193 abi_ulong mcfpu_gsr;
blueswir15bfb56b2007-10-05 17:01:51 +00002194 struct target_mc_fq *mcfpu_fq;
2195 unsigned char mcfpu_qcnt;
2196 unsigned char mcfpu_qentsz;
2197 unsigned char mcfpu_enab;
2198};
Anthony Liguoric227f092009-10-01 16:12:16 -05002199typedef struct target_mc_fpu target_mc_fpu_t;
blueswir15bfb56b2007-10-05 17:01:51 +00002200
2201typedef struct {
Anthony Liguoric227f092009-10-01 16:12:16 -05002202 target_mc_gregset_t mc_gregs;
2203 target_mc_greg_t mc_fp;
2204 target_mc_greg_t mc_i7;
2205 target_mc_fpu_t mc_fpregs;
2206} target_mcontext_t;
blueswir15bfb56b2007-10-05 17:01:51 +00002207
2208struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02002209 struct target_ucontext *tuc_link;
2210 abi_ulong tuc_flags;
2211 target_sigset_t tuc_sigmask;
2212 target_mcontext_t tuc_mcontext;
blueswir15bfb56b2007-10-05 17:01:51 +00002213};
2214
2215/* A V9 register window */
2216struct target_reg_window {
blueswir1992f48a2007-10-14 16:27:31 +00002217 abi_ulong locals[8];
2218 abi_ulong ins[8];
blueswir15bfb56b2007-10-05 17:01:51 +00002219};
2220
2221#define TARGET_STACK_BIAS 2047
2222
2223/* {set, get}context() needed for 64-bit SparcLinux userland. */
2224void sparc64_set_context(CPUSPARCState *env)
2225{
bellard459a4012007-11-11 19:45:10 +00002226 abi_ulong ucp_addr;
2227 struct target_ucontext *ucp;
Anthony Liguoric227f092009-10-01 16:12:16 -05002228 target_mc_gregset_t *grp;
blueswir1992f48a2007-10-14 16:27:31 +00002229 abi_ulong pc, npc, tstate;
bellard459a4012007-11-11 19:45:10 +00002230 abi_ulong fp, i7, w_addr;
blueswir15bfb56b2007-10-05 17:01:51 +00002231 unsigned char fenab;
2232 int err;
2233 unsigned int i;
blueswir15bfb56b2007-10-05 17:01:51 +00002234
bellard459a4012007-11-11 19:45:10 +00002235 ucp_addr = env->regwptr[UREG_I0];
2236 if (!lock_user_struct(VERIFY_READ, ucp, ucp_addr, 1))
2237 goto do_sigsegv;
Aurelien Jarno60e99242010-03-29 02:12:51 +02002238 grp = &ucp->tuc_mcontext.mc_gregs;
bellard579a97f2007-11-11 14:26:47 +00002239 err = __get_user(pc, &((*grp)[MC_PC]));
2240 err |= __get_user(npc, &((*grp)[MC_NPC]));
blueswir15bfb56b2007-10-05 17:01:51 +00002241 if (err || ((pc | npc) & 3))
2242 goto do_sigsegv;
2243 if (env->regwptr[UREG_I1]) {
Anthony Liguoric227f092009-10-01 16:12:16 -05002244 target_sigset_t target_set;
blueswir15bfb56b2007-10-05 17:01:51 +00002245 sigset_t set;
2246
2247 if (TARGET_NSIG_WORDS == 1) {
Aurelien Jarno60e99242010-03-29 02:12:51 +02002248 if (__get_user(target_set.sig[0], &ucp->tuc_sigmask.sig[0]))
blueswir15bfb56b2007-10-05 17:01:51 +00002249 goto do_sigsegv;
2250 } else {
bellard459a4012007-11-11 19:45:10 +00002251 abi_ulong *src, *dst;
Aurelien Jarno60e99242010-03-29 02:12:51 +02002252 src = ucp->tuc_sigmask.sig;
bellard459a4012007-11-11 19:45:10 +00002253 dst = target_set.sig;
Anthony Liguoric227f092009-10-01 16:12:16 -05002254 for (i = 0; i < sizeof(target_sigset_t) / sizeof(abi_ulong);
blueswir15bfb56b2007-10-05 17:01:51 +00002255 i++, dst++, src++)
bellard459a4012007-11-11 19:45:10 +00002256 err |= __get_user(*dst, src);
blueswir15bfb56b2007-10-05 17:01:51 +00002257 if (err)
2258 goto do_sigsegv;
2259 }
2260 target_to_host_sigset_internal(&set, &target_set);
2261 sigprocmask(SIG_SETMASK, &set, NULL);
2262 }
2263 env->pc = pc;
2264 env->npc = npc;
bellard579a97f2007-11-11 14:26:47 +00002265 err |= __get_user(env->y, &((*grp)[MC_Y]));
2266 err |= __get_user(tstate, &((*grp)[MC_TSTATE]));
blueswir15bfb56b2007-10-05 17:01:51 +00002267 env->asi = (tstate >> 24) & 0xff;
Blue Swirl5a834bb2010-05-09 20:19:04 +00002268 cpu_put_ccr(env, tstate >> 32);
2269 cpu_put_cwp64(env, tstate & 0x1f);
bellard579a97f2007-11-11 14:26:47 +00002270 err |= __get_user(env->gregs[1], (&(*grp)[MC_G1]));
2271 err |= __get_user(env->gregs[2], (&(*grp)[MC_G2]));
2272 err |= __get_user(env->gregs[3], (&(*grp)[MC_G3]));
2273 err |= __get_user(env->gregs[4], (&(*grp)[MC_G4]));
2274 err |= __get_user(env->gregs[5], (&(*grp)[MC_G5]));
2275 err |= __get_user(env->gregs[6], (&(*grp)[MC_G6]));
2276 err |= __get_user(env->gregs[7], (&(*grp)[MC_G7]));
2277 err |= __get_user(env->regwptr[UREG_I0], (&(*grp)[MC_O0]));
2278 err |= __get_user(env->regwptr[UREG_I1], (&(*grp)[MC_O1]));
2279 err |= __get_user(env->regwptr[UREG_I2], (&(*grp)[MC_O2]));
2280 err |= __get_user(env->regwptr[UREG_I3], (&(*grp)[MC_O3]));
2281 err |= __get_user(env->regwptr[UREG_I4], (&(*grp)[MC_O4]));
2282 err |= __get_user(env->regwptr[UREG_I5], (&(*grp)[MC_O5]));
2283 err |= __get_user(env->regwptr[UREG_I6], (&(*grp)[MC_O6]));
2284 err |= __get_user(env->regwptr[UREG_I7], (&(*grp)[MC_O7]));
blueswir15bfb56b2007-10-05 17:01:51 +00002285
Aurelien Jarno60e99242010-03-29 02:12:51 +02002286 err |= __get_user(fp, &(ucp->tuc_mcontext.mc_fp));
2287 err |= __get_user(i7, &(ucp->tuc_mcontext.mc_i7));
blueswir15bfb56b2007-10-05 17:01:51 +00002288
bellard459a4012007-11-11 19:45:10 +00002289 w_addr = TARGET_STACK_BIAS+env->regwptr[UREG_I6];
2290 if (put_user(fp, w_addr + offsetof(struct target_reg_window, ins[6]),
2291 abi_ulong) != 0)
2292 goto do_sigsegv;
2293 if (put_user(i7, w_addr + offsetof(struct target_reg_window, ins[7]),
2294 abi_ulong) != 0)
2295 goto do_sigsegv;
Aurelien Jarno60e99242010-03-29 02:12:51 +02002296 err |= __get_user(fenab, &(ucp->tuc_mcontext.mc_fpregs.mcfpu_enab));
2297 err |= __get_user(env->fprs, &(ucp->tuc_mcontext.mc_fpregs.mcfpu_fprs));
bellard459a4012007-11-11 19:45:10 +00002298 {
2299 uint32_t *src, *dst;
Aurelien Jarno60e99242010-03-29 02:12:51 +02002300 src = ucp->tuc_mcontext.mc_fpregs.mcfpu_fregs.sregs;
bellard459a4012007-11-11 19:45:10 +00002301 dst = env->fpr;
2302 /* XXX: check that the CPU storage is the same as user context */
2303 for (i = 0; i < 64; i++, dst++, src++)
2304 err |= __get_user(*dst, src);
2305 }
bellard579a97f2007-11-11 14:26:47 +00002306 err |= __get_user(env->fsr,
Aurelien Jarno60e99242010-03-29 02:12:51 +02002307 &(ucp->tuc_mcontext.mc_fpregs.mcfpu_fsr));
bellard579a97f2007-11-11 14:26:47 +00002308 err |= __get_user(env->gsr,
Aurelien Jarno60e99242010-03-29 02:12:51 +02002309 &(ucp->tuc_mcontext.mc_fpregs.mcfpu_gsr));
blueswir15bfb56b2007-10-05 17:01:51 +00002310 if (err)
2311 goto do_sigsegv;
bellard459a4012007-11-11 19:45:10 +00002312 unlock_user_struct(ucp, ucp_addr, 0);
blueswir15bfb56b2007-10-05 17:01:51 +00002313 return;
2314 do_sigsegv:
bellard459a4012007-11-11 19:45:10 +00002315 unlock_user_struct(ucp, ucp_addr, 0);
Riku Voipio66393fb2009-12-04 15:16:32 +02002316 force_sig(TARGET_SIGSEGV);
blueswir15bfb56b2007-10-05 17:01:51 +00002317}
2318
2319void sparc64_get_context(CPUSPARCState *env)
2320{
bellard459a4012007-11-11 19:45:10 +00002321 abi_ulong ucp_addr;
2322 struct target_ucontext *ucp;
Anthony Liguoric227f092009-10-01 16:12:16 -05002323 target_mc_gregset_t *grp;
2324 target_mcontext_t *mcp;
bellard459a4012007-11-11 19:45:10 +00002325 abi_ulong fp, i7, w_addr;
blueswir15bfb56b2007-10-05 17:01:51 +00002326 int err;
2327 unsigned int i;
Anthony Liguoric227f092009-10-01 16:12:16 -05002328 target_sigset_t target_set;
blueswir15bfb56b2007-10-05 17:01:51 +00002329 sigset_t set;
2330
bellard459a4012007-11-11 19:45:10 +00002331 ucp_addr = env->regwptr[UREG_I0];
2332 if (!lock_user_struct(VERIFY_WRITE, ucp, ucp_addr, 0))
2333 goto do_sigsegv;
2334
Aurelien Jarno60e99242010-03-29 02:12:51 +02002335 mcp = &ucp->tuc_mcontext;
blueswir15bfb56b2007-10-05 17:01:51 +00002336 grp = &mcp->mc_gregs;
2337
2338 /* Skip over the trap instruction, first. */
2339 env->pc = env->npc;
2340 env->npc += 4;
2341
2342 err = 0;
2343
2344 sigprocmask(0, NULL, &set);
2345 host_to_target_sigset_internal(&target_set, &set);
bellard459a4012007-11-11 19:45:10 +00002346 if (TARGET_NSIG_WORDS == 1) {
bellard579a97f2007-11-11 14:26:47 +00002347 err |= __put_user(target_set.sig[0],
Aurelien Jarno60e99242010-03-29 02:12:51 +02002348 (abi_ulong *)&ucp->tuc_sigmask);
bellard459a4012007-11-11 19:45:10 +00002349 } else {
2350 abi_ulong *src, *dst;
2351 src = target_set.sig;
Aurelien Jarno60e99242010-03-29 02:12:51 +02002352 dst = ucp->tuc_sigmask.sig;
Anthony Liguoric227f092009-10-01 16:12:16 -05002353 for (i = 0; i < sizeof(target_sigset_t) / sizeof(abi_ulong);
blueswir15bfb56b2007-10-05 17:01:51 +00002354 i++, dst++, src++)
bellard459a4012007-11-11 19:45:10 +00002355 err |= __put_user(*src, dst);
blueswir15bfb56b2007-10-05 17:01:51 +00002356 if (err)
2357 goto do_sigsegv;
2358 }
2359
bellard459a4012007-11-11 19:45:10 +00002360 /* XXX: tstate must be saved properly */
2361 // err |= __put_user(env->tstate, &((*grp)[MC_TSTATE]));
bellard579a97f2007-11-11 14:26:47 +00002362 err |= __put_user(env->pc, &((*grp)[MC_PC]));
2363 err |= __put_user(env->npc, &((*grp)[MC_NPC]));
2364 err |= __put_user(env->y, &((*grp)[MC_Y]));
2365 err |= __put_user(env->gregs[1], &((*grp)[MC_G1]));
2366 err |= __put_user(env->gregs[2], &((*grp)[MC_G2]));
2367 err |= __put_user(env->gregs[3], &((*grp)[MC_G3]));
2368 err |= __put_user(env->gregs[4], &((*grp)[MC_G4]));
2369 err |= __put_user(env->gregs[5], &((*grp)[MC_G5]));
2370 err |= __put_user(env->gregs[6], &((*grp)[MC_G6]));
2371 err |= __put_user(env->gregs[7], &((*grp)[MC_G7]));
2372 err |= __put_user(env->regwptr[UREG_I0], &((*grp)[MC_O0]));
2373 err |= __put_user(env->regwptr[UREG_I1], &((*grp)[MC_O1]));
2374 err |= __put_user(env->regwptr[UREG_I2], &((*grp)[MC_O2]));
2375 err |= __put_user(env->regwptr[UREG_I3], &((*grp)[MC_O3]));
2376 err |= __put_user(env->regwptr[UREG_I4], &((*grp)[MC_O4]));
2377 err |= __put_user(env->regwptr[UREG_I5], &((*grp)[MC_O5]));
2378 err |= __put_user(env->regwptr[UREG_I6], &((*grp)[MC_O6]));
2379 err |= __put_user(env->regwptr[UREG_I7], &((*grp)[MC_O7]));
blueswir15bfb56b2007-10-05 17:01:51 +00002380
bellard459a4012007-11-11 19:45:10 +00002381 w_addr = TARGET_STACK_BIAS+env->regwptr[UREG_I6];
2382 fp = i7 = 0;
2383 if (get_user(fp, w_addr + offsetof(struct target_reg_window, ins[6]),
2384 abi_ulong) != 0)
2385 goto do_sigsegv;
2386 if (get_user(i7, w_addr + offsetof(struct target_reg_window, ins[7]),
2387 abi_ulong) != 0)
2388 goto do_sigsegv;
bellard579a97f2007-11-11 14:26:47 +00002389 err |= __put_user(fp, &(mcp->mc_fp));
2390 err |= __put_user(i7, &(mcp->mc_i7));
blueswir15bfb56b2007-10-05 17:01:51 +00002391
bellard459a4012007-11-11 19:45:10 +00002392 {
2393 uint32_t *src, *dst;
2394 src = env->fpr;
Aurelien Jarno60e99242010-03-29 02:12:51 +02002395 dst = ucp->tuc_mcontext.mc_fpregs.mcfpu_fregs.sregs;
bellard459a4012007-11-11 19:45:10 +00002396 /* XXX: check that the CPU storage is the same as user context */
2397 for (i = 0; i < 64; i++, dst++, src++)
2398 err |= __put_user(*src, dst);
2399 }
bellard579a97f2007-11-11 14:26:47 +00002400 err |= __put_user(env->fsr, &(mcp->mc_fpregs.mcfpu_fsr));
2401 err |= __put_user(env->gsr, &(mcp->mc_fpregs.mcfpu_gsr));
2402 err |= __put_user(env->fprs, &(mcp->mc_fpregs.mcfpu_fprs));
blueswir15bfb56b2007-10-05 17:01:51 +00002403
2404 if (err)
2405 goto do_sigsegv;
bellard459a4012007-11-11 19:45:10 +00002406 unlock_user_struct(ucp, ucp_addr, 1);
blueswir15bfb56b2007-10-05 17:01:51 +00002407 return;
2408 do_sigsegv:
bellard459a4012007-11-11 19:45:10 +00002409 unlock_user_struct(ucp, ucp_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02002410 force_sig(TARGET_SIGSEGV);
blueswir15bfb56b2007-10-05 17:01:51 +00002411}
2412#endif
thsd26bc212007-11-08 18:05:37 +00002413#elif defined(TARGET_ABI_MIPSN64)
ths540635b2007-09-30 01:58:33 +00002414
2415# warning signal handling not implemented
2416
pbrook624f7972008-05-31 16:11:38 +00002417static void setup_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05002418 target_sigset_t *set, CPUState *env)
ths540635b2007-09-30 01:58:33 +00002419{
2420 fprintf(stderr, "setup_frame: not implemented\n");
2421}
2422
pbrook624f7972008-05-31 16:11:38 +00002423static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05002424 target_siginfo_t *info,
2425 target_sigset_t *set, CPUState *env)
ths540635b2007-09-30 01:58:33 +00002426{
2427 fprintf(stderr, "setup_rt_frame: not implemented\n");
2428}
2429
2430long do_sigreturn(CPUState *env)
2431{
2432 fprintf(stderr, "do_sigreturn: not implemented\n");
bellardf8b0aa22007-11-11 23:03:42 +00002433 return -TARGET_ENOSYS;
ths540635b2007-09-30 01:58:33 +00002434}
2435
2436long do_rt_sigreturn(CPUState *env)
2437{
2438 fprintf(stderr, "do_rt_sigreturn: not implemented\n");
bellardf8b0aa22007-11-11 23:03:42 +00002439 return -TARGET_ENOSYS;
ths540635b2007-09-30 01:58:33 +00002440}
2441
thsd26bc212007-11-08 18:05:37 +00002442#elif defined(TARGET_ABI_MIPSN32)
ths540635b2007-09-30 01:58:33 +00002443
2444# warning signal handling not implemented
2445
pbrook624f7972008-05-31 16:11:38 +00002446static void setup_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05002447 target_sigset_t *set, CPUState *env)
ths540635b2007-09-30 01:58:33 +00002448{
2449 fprintf(stderr, "setup_frame: not implemented\n");
2450}
2451
pbrook624f7972008-05-31 16:11:38 +00002452static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05002453 target_siginfo_t *info,
2454 target_sigset_t *set, CPUState *env)
ths540635b2007-09-30 01:58:33 +00002455{
2456 fprintf(stderr, "setup_rt_frame: not implemented\n");
2457}
2458
2459long do_sigreturn(CPUState *env)
2460{
2461 fprintf(stderr, "do_sigreturn: not implemented\n");
bellardf8b0aa22007-11-11 23:03:42 +00002462 return -TARGET_ENOSYS;
ths540635b2007-09-30 01:58:33 +00002463}
2464
2465long do_rt_sigreturn(CPUState *env)
2466{
2467 fprintf(stderr, "do_rt_sigreturn: not implemented\n");
bellardf8b0aa22007-11-11 23:03:42 +00002468 return -TARGET_ENOSYS;
ths540635b2007-09-30 01:58:33 +00002469}
2470
thsd26bc212007-11-08 18:05:37 +00002471#elif defined(TARGET_ABI_MIPSO32)
bellard106ec872006-06-27 21:08:10 +00002472
2473struct target_sigcontext {
2474 uint32_t sc_regmask; /* Unused */
2475 uint32_t sc_status;
2476 uint64_t sc_pc;
2477 uint64_t sc_regs[32];
2478 uint64_t sc_fpregs[32];
2479 uint32_t sc_ownedfp; /* Unused */
2480 uint32_t sc_fpc_csr;
2481 uint32_t sc_fpc_eir; /* Unused */
2482 uint32_t sc_used_math;
2483 uint32_t sc_dsp; /* dsp status, was sc_ssflags */
Paul Brook94c54952009-07-09 18:40:15 +01002484 uint32_t pad0;
bellard106ec872006-06-27 21:08:10 +00002485 uint64_t sc_mdhi;
2486 uint64_t sc_mdlo;
2487 target_ulong sc_hi1; /* Was sc_cause */
2488 target_ulong sc_lo1; /* Was sc_badvaddr */
2489 target_ulong sc_hi2; /* Was sc_sigset[4] */
2490 target_ulong sc_lo2;
2491 target_ulong sc_hi3;
2492 target_ulong sc_lo3;
2493};
2494
2495struct sigframe {
2496 uint32_t sf_ass[4]; /* argument save space for o32 */
2497 uint32_t sf_code[2]; /* signal trampoline */
2498 struct target_sigcontext sf_sc;
Anthony Liguoric227f092009-10-01 16:12:16 -05002499 target_sigset_t sf_mask;
bellard106ec872006-06-27 21:08:10 +00002500};
2501
pbrook0b1bcb02009-04-21 01:41:10 +00002502struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02002503 target_ulong tuc_flags;
2504 target_ulong tuc_link;
2505 target_stack_t tuc_stack;
Paul Brook94c54952009-07-09 18:40:15 +01002506 target_ulong pad0;
Aurelien Jarno60e99242010-03-29 02:12:51 +02002507 struct target_sigcontext tuc_mcontext;
2508 target_sigset_t tuc_sigmask;
pbrook0b1bcb02009-04-21 01:41:10 +00002509};
2510
2511struct target_rt_sigframe {
2512 uint32_t rs_ass[4]; /* argument save space for o32 */
2513 uint32_t rs_code[2]; /* signal trampoline */
2514 struct target_siginfo rs_info;
2515 struct target_ucontext rs_uc;
2516};
2517
bellard106ec872006-06-27 21:08:10 +00002518/* Install trampoline to jump back from signal handler */
2519static inline int install_sigtramp(unsigned int *tramp, unsigned int syscall)
2520{
2521 int err;
2522
2523 /*
2524 * Set up the return code ...
2525 *
2526 * li v0, __NR__foo_sigreturn
2527 * syscall
2528 */
2529
2530 err = __put_user(0x24020000 + syscall, tramp + 0);
2531 err |= __put_user(0x0000000c , tramp + 1);
2532 /* flush_cache_sigtramp((unsigned long) tramp); */
2533 return err;
2534}
2535
2536static inline int
2537setup_sigcontext(CPUState *regs, struct target_sigcontext *sc)
2538{
2539 int err = 0;
2540
thsb5dc7732008-06-27 10:02:35 +00002541 err |= __put_user(regs->active_tc.PC, &sc->sc_pc);
bellard106ec872006-06-27 21:08:10 +00002542
thsb5dc7732008-06-27 10:02:35 +00002543#define save_gp_reg(i) do { \
2544 err |= __put_user(regs->active_tc.gpr[i], &sc->sc_regs[i]); \
bellard106ec872006-06-27 21:08:10 +00002545 } while(0)
2546 __put_user(0, &sc->sc_regs[0]); save_gp_reg(1); save_gp_reg(2);
2547 save_gp_reg(3); save_gp_reg(4); save_gp_reg(5); save_gp_reg(6);
2548 save_gp_reg(7); save_gp_reg(8); save_gp_reg(9); save_gp_reg(10);
2549 save_gp_reg(11); save_gp_reg(12); save_gp_reg(13); save_gp_reg(14);
2550 save_gp_reg(15); save_gp_reg(16); save_gp_reg(17); save_gp_reg(18);
2551 save_gp_reg(19); save_gp_reg(20); save_gp_reg(21); save_gp_reg(22);
2552 save_gp_reg(23); save_gp_reg(24); save_gp_reg(25); save_gp_reg(26);
2553 save_gp_reg(27); save_gp_reg(28); save_gp_reg(29); save_gp_reg(30);
2554 save_gp_reg(31);
ths388bb212007-05-13 13:58:00 +00002555#undef save_gp_reg
bellard106ec872006-06-27 21:08:10 +00002556
thsb5dc7732008-06-27 10:02:35 +00002557 err |= __put_user(regs->active_tc.HI[0], &sc->sc_mdhi);
2558 err |= __put_user(regs->active_tc.LO[0], &sc->sc_mdlo);
bellard106ec872006-06-27 21:08:10 +00002559
2560 /* Not used yet, but might be useful if we ever have DSP suppport */
2561#if 0
2562 if (cpu_has_dsp) {
2563 err |= __put_user(mfhi1(), &sc->sc_hi1);
2564 err |= __put_user(mflo1(), &sc->sc_lo1);
2565 err |= __put_user(mfhi2(), &sc->sc_hi2);
2566 err |= __put_user(mflo2(), &sc->sc_lo2);
2567 err |= __put_user(mfhi3(), &sc->sc_hi3);
2568 err |= __put_user(mflo3(), &sc->sc_lo3);
2569 err |= __put_user(rddsp(DSP_MASK), &sc->sc_dsp);
2570 }
2571 /* same with 64 bit */
ths388bb212007-05-13 13:58:00 +00002572#ifdef CONFIG_64BIT
bellard106ec872006-06-27 21:08:10 +00002573 err |= __put_user(regs->hi, &sc->sc_hi[0]);
2574 err |= __put_user(regs->lo, &sc->sc_lo[0]);
2575 if (cpu_has_dsp) {
2576 err |= __put_user(mfhi1(), &sc->sc_hi[1]);
2577 err |= __put_user(mflo1(), &sc->sc_lo[1]);
2578 err |= __put_user(mfhi2(), &sc->sc_hi[2]);
2579 err |= __put_user(mflo2(), &sc->sc_lo[2]);
2580 err |= __put_user(mfhi3(), &sc->sc_hi[3]);
2581 err |= __put_user(mflo3(), &sc->sc_lo[3]);
2582 err |= __put_user(rddsp(DSP_MASK), &sc->sc_dsp);
2583 }
ths388bb212007-05-13 13:58:00 +00002584#endif
2585#endif
bellard106ec872006-06-27 21:08:10 +00002586
ths388bb212007-05-13 13:58:00 +00002587#if 0
bellard106ec872006-06-27 21:08:10 +00002588 err |= __put_user(!!used_math(), &sc->sc_used_math);
2589
2590 if (!used_math())
2591 goto out;
2592
2593 /*
2594 * Save FPU state to signal context. Signal handler will "inherit"
2595 * current FPU state.
2596 */
2597 preempt_disable();
2598
2599 if (!is_fpu_owner()) {
2600 own_fpu();
2601 restore_fp(current);
2602 }
2603 err |= save_fp_context(sc);
2604
2605 preempt_enable();
2606 out:
2607#endif
2608 return err;
2609}
2610
2611static inline int
2612restore_sigcontext(CPUState *regs, struct target_sigcontext *sc)
2613{
2614 int err = 0;
2615
2616 err |= __get_user(regs->CP0_EPC, &sc->sc_pc);
2617
thsb5dc7732008-06-27 10:02:35 +00002618 err |= __get_user(regs->active_tc.HI[0], &sc->sc_mdhi);
2619 err |= __get_user(regs->active_tc.LO[0], &sc->sc_mdlo);
bellard106ec872006-06-27 21:08:10 +00002620
thsead93602007-09-06 00:18:15 +00002621#define restore_gp_reg(i) do { \
thsb5dc7732008-06-27 10:02:35 +00002622 err |= __get_user(regs->active_tc.gpr[i], &sc->sc_regs[i]); \
bellard106ec872006-06-27 21:08:10 +00002623 } while(0)
2624 restore_gp_reg( 1); restore_gp_reg( 2); restore_gp_reg( 3);
2625 restore_gp_reg( 4); restore_gp_reg( 5); restore_gp_reg( 6);
2626 restore_gp_reg( 7); restore_gp_reg( 8); restore_gp_reg( 9);
2627 restore_gp_reg(10); restore_gp_reg(11); restore_gp_reg(12);
2628 restore_gp_reg(13); restore_gp_reg(14); restore_gp_reg(15);
2629 restore_gp_reg(16); restore_gp_reg(17); restore_gp_reg(18);
2630 restore_gp_reg(19); restore_gp_reg(20); restore_gp_reg(21);
2631 restore_gp_reg(22); restore_gp_reg(23); restore_gp_reg(24);
2632 restore_gp_reg(25); restore_gp_reg(26); restore_gp_reg(27);
2633 restore_gp_reg(28); restore_gp_reg(29); restore_gp_reg(30);
2634 restore_gp_reg(31);
ths388bb212007-05-13 13:58:00 +00002635#undef restore_gp_reg
bellard106ec872006-06-27 21:08:10 +00002636
2637#if 0
2638 if (cpu_has_dsp) {
2639 err |= __get_user(treg, &sc->sc_hi1); mthi1(treg);
2640 err |= __get_user(treg, &sc->sc_lo1); mtlo1(treg);
2641 err |= __get_user(treg, &sc->sc_hi2); mthi2(treg);
2642 err |= __get_user(treg, &sc->sc_lo2); mtlo2(treg);
2643 err |= __get_user(treg, &sc->sc_hi3); mthi3(treg);
2644 err |= __get_user(treg, &sc->sc_lo3); mtlo3(treg);
2645 err |= __get_user(treg, &sc->sc_dsp); wrdsp(treg, DSP_MASK);
2646 }
ths388bb212007-05-13 13:58:00 +00002647#ifdef CONFIG_64BIT
bellard106ec872006-06-27 21:08:10 +00002648 err |= __get_user(regs->hi, &sc->sc_hi[0]);
2649 err |= __get_user(regs->lo, &sc->sc_lo[0]);
2650 if (cpu_has_dsp) {
2651 err |= __get_user(treg, &sc->sc_hi[1]); mthi1(treg);
2652 err |= __get_user(treg, &sc->sc_lo[1]); mthi1(treg);
2653 err |= __get_user(treg, &sc->sc_hi[2]); mthi2(treg);
2654 err |= __get_user(treg, &sc->sc_lo[2]); mthi2(treg);
2655 err |= __get_user(treg, &sc->sc_hi[3]); mthi3(treg);
2656 err |= __get_user(treg, &sc->sc_lo[3]); mthi3(treg);
2657 err |= __get_user(treg, &sc->sc_dsp); wrdsp(treg, DSP_MASK);
2658 }
ths388bb212007-05-13 13:58:00 +00002659#endif
bellard106ec872006-06-27 21:08:10 +00002660
2661 err |= __get_user(used_math, &sc->sc_used_math);
2662 conditional_used_math(used_math);
2663
2664 preempt_disable();
2665
2666 if (used_math()) {
2667 /* restore fpu context if we have used it before */
2668 own_fpu();
2669 err |= restore_fp_context(sc);
2670 } else {
2671 /* signal handler may have used FPU. Give it up. */
2672 lose_fpu();
2673 }
2674
2675 preempt_enable();
2676#endif
2677 return err;
2678}
2679/*
2680 * Determine which stack to use..
2681 */
bellard579a97f2007-11-11 14:26:47 +00002682static inline abi_ulong
pbrook624f7972008-05-31 16:11:38 +00002683get_sigframe(struct target_sigaction *ka, CPUState *regs, size_t frame_size)
bellard106ec872006-06-27 21:08:10 +00002684{
2685 unsigned long sp;
2686
2687 /* Default to using normal stack */
thsb5dc7732008-06-27 10:02:35 +00002688 sp = regs->active_tc.gpr[29];
bellard106ec872006-06-27 21:08:10 +00002689
2690 /*
2691 * FPU emulator may have it's own trampoline active just
2692 * above the user stack, 16-bytes before the next lowest
2693 * 16 byte boundary. Try to avoid trashing it.
2694 */
2695 sp -= 32;
2696
bellard106ec872006-06-27 21:08:10 +00002697 /* This is the X/Open sanctioned signal stack switching. */
pbrook624f7972008-05-31 16:11:38 +00002698 if ((ka->sa_flags & TARGET_SA_ONSTACK) && (sas_ss_flags (sp) == 0)) {
thsa04e1342007-09-27 13:57:58 +00002699 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
2700 }
bellard106ec872006-06-27 21:08:10 +00002701
bellard579a97f2007-11-11 14:26:47 +00002702 return (sp - frame_size) & ~7;
bellard106ec872006-06-27 21:08:10 +00002703}
2704
bellard579a97f2007-11-11 14:26:47 +00002705/* compare linux/arch/mips/kernel/signal.c:setup_frame() */
pbrook624f7972008-05-31 16:11:38 +00002706static void setup_frame(int sig, struct target_sigaction * ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05002707 target_sigset_t *set, CPUState *regs)
bellard106ec872006-06-27 21:08:10 +00002708{
2709 struct sigframe *frame;
bellard579a97f2007-11-11 14:26:47 +00002710 abi_ulong frame_addr;
bellard106ec872006-06-27 21:08:10 +00002711 int i;
2712
bellard579a97f2007-11-11 14:26:47 +00002713 frame_addr = get_sigframe(ka, regs, sizeof(*frame));
2714 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
bellard106ec872006-06-27 21:08:10 +00002715 goto give_sigsegv;
2716
2717 install_sigtramp(frame->sf_code, TARGET_NR_sigreturn);
2718
2719 if(setup_sigcontext(regs, &frame->sf_sc))
2720 goto give_sigsegv;
2721
2722 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
2723 if(__put_user(set->sig[i], &frame->sf_mask.sig[i]))
2724 goto give_sigsegv;
2725 }
2726
2727 /*
2728 * Arguments to signal handler:
2729 *
2730 * a0 = signal number
2731 * a1 = 0 (should be cause)
2732 * a2 = pointer to struct sigcontext
2733 *
2734 * $25 and PC point to the signal handler, $29 points to the
2735 * struct sigframe.
2736 */
thsb5dc7732008-06-27 10:02:35 +00002737 regs->active_tc.gpr[ 4] = sig;
2738 regs->active_tc.gpr[ 5] = 0;
2739 regs->active_tc.gpr[ 6] = frame_addr + offsetof(struct sigframe, sf_sc);
2740 regs->active_tc.gpr[29] = frame_addr;
2741 regs->active_tc.gpr[31] = frame_addr + offsetof(struct sigframe, sf_code);
bellard106ec872006-06-27 21:08:10 +00002742 /* The original kernel code sets CP0_EPC to the handler
2743 * since it returns to userland using eret
2744 * we cannot do this here, and we must set PC directly */
thsb5dc7732008-06-27 10:02:35 +00002745 regs->active_tc.PC = regs->active_tc.gpr[25] = ka->_sa_handler;
bellard579a97f2007-11-11 14:26:47 +00002746 unlock_user_struct(frame, frame_addr, 1);
bellard106ec872006-06-27 21:08:10 +00002747 return;
2748
2749give_sigsegv:
bellard579a97f2007-11-11 14:26:47 +00002750 unlock_user_struct(frame, frame_addr, 1);
bellard106ec872006-06-27 21:08:10 +00002751 force_sig(TARGET_SIGSEGV/*, current*/);
ths5fafdf22007-09-16 21:08:06 +00002752 return;
bellard106ec872006-06-27 21:08:10 +00002753}
2754
2755long do_sigreturn(CPUState *regs)
2756{
ths388bb212007-05-13 13:58:00 +00002757 struct sigframe *frame;
bellard579a97f2007-11-11 14:26:47 +00002758 abi_ulong frame_addr;
ths388bb212007-05-13 13:58:00 +00002759 sigset_t blocked;
Anthony Liguoric227f092009-10-01 16:12:16 -05002760 target_sigset_t target_set;
ths388bb212007-05-13 13:58:00 +00002761 int i;
bellard106ec872006-06-27 21:08:10 +00002762
2763#if defined(DEBUG_SIGNAL)
ths388bb212007-05-13 13:58:00 +00002764 fprintf(stderr, "do_sigreturn\n");
bellard106ec872006-06-27 21:08:10 +00002765#endif
thsb5dc7732008-06-27 10:02:35 +00002766 frame_addr = regs->active_tc.gpr[29];
bellard579a97f2007-11-11 14:26:47 +00002767 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
bellard106ec872006-06-27 21:08:10 +00002768 goto badframe;
2769
ths388bb212007-05-13 13:58:00 +00002770 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
bellard106ec872006-06-27 21:08:10 +00002771 if(__get_user(target_set.sig[i], &frame->sf_mask.sig[i]))
2772 goto badframe;
ths388bb212007-05-13 13:58:00 +00002773 }
bellard106ec872006-06-27 21:08:10 +00002774
ths388bb212007-05-13 13:58:00 +00002775 target_to_host_sigset_internal(&blocked, &target_set);
2776 sigprocmask(SIG_SETMASK, &blocked, NULL);
bellard106ec872006-06-27 21:08:10 +00002777
ths388bb212007-05-13 13:58:00 +00002778 if (restore_sigcontext(regs, &frame->sf_sc))
bellard106ec872006-06-27 21:08:10 +00002779 goto badframe;
2780
2781#if 0
ths388bb212007-05-13 13:58:00 +00002782 /*
2783 * Don't let your children do this ...
2784 */
2785 __asm__ __volatile__(
bellard106ec872006-06-27 21:08:10 +00002786 "move\t$29, %0\n\t"
2787 "j\tsyscall_exit"
2788 :/* no outputs */
2789 :"r" (&regs));
ths388bb212007-05-13 13:58:00 +00002790 /* Unreached */
bellard106ec872006-06-27 21:08:10 +00002791#endif
ths3b46e622007-09-17 08:09:54 +00002792
thsb5dc7732008-06-27 10:02:35 +00002793 regs->active_tc.PC = regs->CP0_EPC;
ths388bb212007-05-13 13:58:00 +00002794 /* I am not sure this is right, but it seems to work
bellard106ec872006-06-27 21:08:10 +00002795 * maybe a problem with nested signals ? */
2796 regs->CP0_EPC = 0;
pbrook0b1bcb02009-04-21 01:41:10 +00002797 return -TARGET_QEMU_ESIGRETURN;
bellard106ec872006-06-27 21:08:10 +00002798
2799badframe:
ths388bb212007-05-13 13:58:00 +00002800 force_sig(TARGET_SIGSEGV/*, current*/);
2801 return 0;
bellard106ec872006-06-27 21:08:10 +00002802}
2803
pbrook624f7972008-05-31 16:11:38 +00002804static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05002805 target_siginfo_t *info,
2806 target_sigset_t *set, CPUState *env)
bellard106ec872006-06-27 21:08:10 +00002807{
pbrook0b1bcb02009-04-21 01:41:10 +00002808 struct target_rt_sigframe *frame;
2809 abi_ulong frame_addr;
2810 int i;
2811
2812 frame_addr = get_sigframe(ka, env, sizeof(*frame));
2813 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
2814 goto give_sigsegv;
2815
2816 install_sigtramp(frame->rs_code, TARGET_NR_rt_sigreturn);
2817
2818 copy_siginfo_to_user(&frame->rs_info, info);
2819
Aurelien Jarno60e99242010-03-29 02:12:51 +02002820 __put_user(0, &frame->rs_uc.tuc_flags);
2821 __put_user(0, &frame->rs_uc.tuc_link);
2822 __put_user(target_sigaltstack_used.ss_sp, &frame->rs_uc.tuc_stack.ss_sp);
2823 __put_user(target_sigaltstack_used.ss_size, &frame->rs_uc.tuc_stack.ss_size);
pbrook0b1bcb02009-04-21 01:41:10 +00002824 __put_user(sas_ss_flags(get_sp_from_cpustate(env)),
Aurelien Jarno60e99242010-03-29 02:12:51 +02002825 &frame->rs_uc.tuc_stack.ss_flags);
pbrook0b1bcb02009-04-21 01:41:10 +00002826
Aurelien Jarno60e99242010-03-29 02:12:51 +02002827 setup_sigcontext(env, &frame->rs_uc.tuc_mcontext);
pbrook0b1bcb02009-04-21 01:41:10 +00002828
2829 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
Aurelien Jarno60e99242010-03-29 02:12:51 +02002830 __put_user(set->sig[i], &frame->rs_uc.tuc_sigmask.sig[i]);
pbrook0b1bcb02009-04-21 01:41:10 +00002831 }
2832
2833 /*
2834 * Arguments to signal handler:
2835 *
2836 * a0 = signal number
2837 * a1 = pointer to struct siginfo
2838 * a2 = pointer to struct ucontext
2839 *
2840 * $25 and PC point to the signal handler, $29 points to the
2841 * struct sigframe.
2842 */
2843 env->active_tc.gpr[ 4] = sig;
2844 env->active_tc.gpr[ 5] = frame_addr
2845 + offsetof(struct target_rt_sigframe, rs_info);
2846 env->active_tc.gpr[ 6] = frame_addr
2847 + offsetof(struct target_rt_sigframe, rs_uc);
2848 env->active_tc.gpr[29] = frame_addr;
2849 env->active_tc.gpr[31] = frame_addr
2850 + offsetof(struct target_rt_sigframe, rs_code);
2851 /* The original kernel code sets CP0_EPC to the handler
2852 * since it returns to userland using eret
2853 * we cannot do this here, and we must set PC directly */
2854 env->active_tc.PC = env->active_tc.gpr[25] = ka->_sa_handler;
2855 unlock_user_struct(frame, frame_addr, 1);
2856 return;
2857
2858give_sigsegv:
2859 unlock_user_struct(frame, frame_addr, 1);
2860 force_sig(TARGET_SIGSEGV/*, current*/);
2861 return;
bellard106ec872006-06-27 21:08:10 +00002862}
2863
2864long do_rt_sigreturn(CPUState *env)
2865{
pbrook0b1bcb02009-04-21 01:41:10 +00002866 struct target_rt_sigframe *frame;
2867 abi_ulong frame_addr;
2868 sigset_t blocked;
2869
2870#if defined(DEBUG_SIGNAL)
2871 fprintf(stderr, "do_rt_sigreturn\n");
2872#endif
2873 frame_addr = env->active_tc.gpr[29];
2874 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
2875 goto badframe;
2876
Aurelien Jarno60e99242010-03-29 02:12:51 +02002877 target_to_host_sigset(&blocked, &frame->rs_uc.tuc_sigmask);
pbrook0b1bcb02009-04-21 01:41:10 +00002878 sigprocmask(SIG_SETMASK, &blocked, NULL);
2879
Aurelien Jarno60e99242010-03-29 02:12:51 +02002880 if (restore_sigcontext(env, &frame->rs_uc.tuc_mcontext))
pbrook0b1bcb02009-04-21 01:41:10 +00002881 goto badframe;
2882
2883 if (do_sigaltstack(frame_addr +
Aurelien Jarno60e99242010-03-29 02:12:51 +02002884 offsetof(struct target_rt_sigframe, rs_uc.tuc_stack),
pbrook0b1bcb02009-04-21 01:41:10 +00002885 0, get_sp_from_cpustate(env)) == -EFAULT)
2886 goto badframe;
2887
2888 env->active_tc.PC = env->CP0_EPC;
2889 /* I am not sure this is right, but it seems to work
2890 * maybe a problem with nested signals ? */
2891 env->CP0_EPC = 0;
2892 return -TARGET_QEMU_ESIGRETURN;
2893
2894badframe:
2895 force_sig(TARGET_SIGSEGV/*, current*/);
2896 return 0;
bellard106ec872006-06-27 21:08:10 +00002897}
bellard6d5e2162004-09-30 22:04:13 +00002898
thsc3b5bc82007-12-02 06:31:25 +00002899#elif defined(TARGET_SH4)
2900
2901/*
2902 * code and data structures from linux kernel:
2903 * include/asm-sh/sigcontext.h
2904 * arch/sh/kernel/signal.c
2905 */
2906
2907struct target_sigcontext {
2908 target_ulong oldmask;
2909
2910 /* CPU registers */
2911 target_ulong sc_gregs[16];
2912 target_ulong sc_pc;
2913 target_ulong sc_pr;
2914 target_ulong sc_sr;
2915 target_ulong sc_gbr;
2916 target_ulong sc_mach;
2917 target_ulong sc_macl;
2918
2919 /* FPU registers */
2920 target_ulong sc_fpregs[16];
2921 target_ulong sc_xfpregs[16];
2922 unsigned int sc_fpscr;
2923 unsigned int sc_fpul;
2924 unsigned int sc_ownedfp;
2925};
2926
2927struct target_sigframe
2928{
2929 struct target_sigcontext sc;
2930 target_ulong extramask[TARGET_NSIG_WORDS-1];
2931 uint16_t retcode[3];
2932};
2933
2934
2935struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02002936 target_ulong tuc_flags;
2937 struct target_ucontext *tuc_link;
2938 target_stack_t tuc_stack;
2939 struct target_sigcontext tuc_mcontext;
2940 target_sigset_t tuc_sigmask; /* mask last for extensibility */
thsc3b5bc82007-12-02 06:31:25 +00002941};
2942
2943struct target_rt_sigframe
2944{
2945 struct target_siginfo info;
2946 struct target_ucontext uc;
2947 uint16_t retcode[3];
2948};
2949
2950
2951#define MOVW(n) (0x9300|((n)-2)) /* Move mem word at PC+n to R3 */
2952#define TRAP_NOARG 0xc310 /* Syscall w/no args (NR in R3) SH3/4 */
2953
pbrook624f7972008-05-31 16:11:38 +00002954static abi_ulong get_sigframe(struct target_sigaction *ka,
thsc3b5bc82007-12-02 06:31:25 +00002955 unsigned long sp, size_t frame_size)
2956{
pbrook624f7972008-05-31 16:11:38 +00002957 if ((ka->sa_flags & TARGET_SA_ONSTACK) && (sas_ss_flags(sp) == 0)) {
thsc3b5bc82007-12-02 06:31:25 +00002958 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
2959 }
2960
2961 return (sp - frame_size) & -8ul;
2962}
2963
2964static int setup_sigcontext(struct target_sigcontext *sc,
2965 CPUState *regs, unsigned long mask)
2966{
2967 int err = 0;
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09002968 int i;
thsc3b5bc82007-12-02 06:31:25 +00002969
2970#define COPY(x) err |= __put_user(regs->x, &sc->sc_##x)
2971 COPY(gregs[0]); COPY(gregs[1]);
2972 COPY(gregs[2]); COPY(gregs[3]);
2973 COPY(gregs[4]); COPY(gregs[5]);
2974 COPY(gregs[6]); COPY(gregs[7]);
2975 COPY(gregs[8]); COPY(gregs[9]);
2976 COPY(gregs[10]); COPY(gregs[11]);
2977 COPY(gregs[12]); COPY(gregs[13]);
2978 COPY(gregs[14]); COPY(gregs[15]);
2979 COPY(gbr); COPY(mach);
2980 COPY(macl); COPY(pr);
2981 COPY(sr); COPY(pc);
2982#undef COPY
2983
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09002984 for (i=0; i<16; i++) {
2985 err |= __put_user(regs->fregs[i], &sc->sc_fpregs[i]);
2986 }
2987 err |= __put_user(regs->fpscr, &sc->sc_fpscr);
2988 err |= __put_user(regs->fpul, &sc->sc_fpul);
thsc3b5bc82007-12-02 06:31:25 +00002989
2990 /* non-iBCS2 extensions.. */
2991 err |= __put_user(mask, &sc->oldmask);
2992
2993 return err;
2994}
2995
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09002996static int restore_sigcontext(CPUState *regs, struct target_sigcontext *sc,
2997 target_ulong *r0_p)
thsc3b5bc82007-12-02 06:31:25 +00002998{
2999 unsigned int err = 0;
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003000 int i;
thsc3b5bc82007-12-02 06:31:25 +00003001
3002#define COPY(x) err |= __get_user(regs->x, &sc->sc_##x)
3003 COPY(gregs[1]);
3004 COPY(gregs[2]); COPY(gregs[3]);
3005 COPY(gregs[4]); COPY(gregs[5]);
3006 COPY(gregs[6]); COPY(gregs[7]);
3007 COPY(gregs[8]); COPY(gregs[9]);
3008 COPY(gregs[10]); COPY(gregs[11]);
3009 COPY(gregs[12]); COPY(gregs[13]);
3010 COPY(gregs[14]); COPY(gregs[15]);
3011 COPY(gbr); COPY(mach);
3012 COPY(macl); COPY(pr);
3013 COPY(sr); COPY(pc);
3014#undef COPY
3015
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003016 for (i=0; i<16; i++) {
3017 err |= __get_user(regs->fregs[i], &sc->sc_fpregs[i]);
3018 }
3019 err |= __get_user(regs->fpscr, &sc->sc_fpscr);
3020 err |= __get_user(regs->fpul, &sc->sc_fpul);
thsc3b5bc82007-12-02 06:31:25 +00003021
3022 regs->tra = -1; /* disable syscall checks */
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003023 err |= __get_user(*r0_p, &sc->sc_gregs[0]);
thsc3b5bc82007-12-02 06:31:25 +00003024 return err;
3025}
3026
pbrook624f7972008-05-31 16:11:38 +00003027static void setup_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05003028 target_sigset_t *set, CPUState *regs)
thsc3b5bc82007-12-02 06:31:25 +00003029{
3030 struct target_sigframe *frame;
3031 abi_ulong frame_addr;
3032 int i;
3033 int err = 0;
3034 int signal;
3035
3036 frame_addr = get_sigframe(ka, regs->gregs[15], sizeof(*frame));
3037 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
3038 goto give_sigsegv;
3039
3040 signal = current_exec_domain_sig(sig);
3041
3042 err |= setup_sigcontext(&frame->sc, regs, set->sig[0]);
3043
3044 for (i = 0; i < TARGET_NSIG_WORDS - 1; i++) {
3045 err |= __put_user(set->sig[i + 1], &frame->extramask[i]);
3046 }
3047
3048 /* Set up to return from userspace. If provided, use a stub
3049 already in userspace. */
pbrook624f7972008-05-31 16:11:38 +00003050 if (ka->sa_flags & TARGET_SA_RESTORER) {
3051 regs->pr = (unsigned long) ka->sa_restorer;
thsc3b5bc82007-12-02 06:31:25 +00003052 } else {
3053 /* Generate return code (system call to sigreturn) */
3054 err |= __put_user(MOVW(2), &frame->retcode[0]);
3055 err |= __put_user(TRAP_NOARG, &frame->retcode[1]);
3056 err |= __put_user((TARGET_NR_sigreturn), &frame->retcode[2]);
3057 regs->pr = (unsigned long) frame->retcode;
3058 }
3059
3060 if (err)
3061 goto give_sigsegv;
3062
3063 /* Set up registers for signal handler */
3064 regs->gregs[15] = (unsigned long) frame;
3065 regs->gregs[4] = signal; /* Arg for signal handler */
3066 regs->gregs[5] = 0;
3067 regs->gregs[6] = (unsigned long) &frame->sc;
pbrook624f7972008-05-31 16:11:38 +00003068 regs->pc = (unsigned long) ka->_sa_handler;
thsc3b5bc82007-12-02 06:31:25 +00003069
3070 unlock_user_struct(frame, frame_addr, 1);
3071 return;
3072
3073give_sigsegv:
3074 unlock_user_struct(frame, frame_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02003075 force_sig(TARGET_SIGSEGV);
thsc3b5bc82007-12-02 06:31:25 +00003076}
3077
pbrook624f7972008-05-31 16:11:38 +00003078static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05003079 target_siginfo_t *info,
3080 target_sigset_t *set, CPUState *regs)
thsc3b5bc82007-12-02 06:31:25 +00003081{
3082 struct target_rt_sigframe *frame;
3083 abi_ulong frame_addr;
3084 int i;
3085 int err = 0;
3086 int signal;
3087
3088 frame_addr = get_sigframe(ka, regs->gregs[15], sizeof(*frame));
3089 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
3090 goto give_sigsegv;
3091
3092 signal = current_exec_domain_sig(sig);
3093
3094 err |= copy_siginfo_to_user(&frame->info, info);
3095
3096 /* Create the ucontext. */
Aurelien Jarno60e99242010-03-29 02:12:51 +02003097 err |= __put_user(0, &frame->uc.tuc_flags);
3098 err |= __put_user(0, (unsigned long *)&frame->uc.tuc_link);
balrog526ccb72008-07-16 12:13:52 +00003099 err |= __put_user((unsigned long)target_sigaltstack_used.ss_sp,
Aurelien Jarno60e99242010-03-29 02:12:51 +02003100 &frame->uc.tuc_stack.ss_sp);
thsc3b5bc82007-12-02 06:31:25 +00003101 err |= __put_user(sas_ss_flags(regs->gregs[15]),
Aurelien Jarno60e99242010-03-29 02:12:51 +02003102 &frame->uc.tuc_stack.ss_flags);
thsc3b5bc82007-12-02 06:31:25 +00003103 err |= __put_user(target_sigaltstack_used.ss_size,
Aurelien Jarno60e99242010-03-29 02:12:51 +02003104 &frame->uc.tuc_stack.ss_size);
3105 err |= setup_sigcontext(&frame->uc.tuc_mcontext,
thsc3b5bc82007-12-02 06:31:25 +00003106 regs, set->sig[0]);
3107 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
Aurelien Jarno60e99242010-03-29 02:12:51 +02003108 err |= __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
thsc3b5bc82007-12-02 06:31:25 +00003109 }
3110
3111 /* Set up to return from userspace. If provided, use a stub
3112 already in userspace. */
pbrook624f7972008-05-31 16:11:38 +00003113 if (ka->sa_flags & TARGET_SA_RESTORER) {
3114 regs->pr = (unsigned long) ka->sa_restorer;
thsc3b5bc82007-12-02 06:31:25 +00003115 } else {
3116 /* Generate return code (system call to sigreturn) */
3117 err |= __put_user(MOVW(2), &frame->retcode[0]);
3118 err |= __put_user(TRAP_NOARG, &frame->retcode[1]);
3119 err |= __put_user((TARGET_NR_rt_sigreturn), &frame->retcode[2]);
3120 regs->pr = (unsigned long) frame->retcode;
3121 }
3122
3123 if (err)
3124 goto give_sigsegv;
3125
3126 /* Set up registers for signal handler */
3127 regs->gregs[15] = (unsigned long) frame;
3128 regs->gregs[4] = signal; /* Arg for signal handler */
3129 regs->gregs[5] = (unsigned long) &frame->info;
3130 regs->gregs[6] = (unsigned long) &frame->uc;
pbrook624f7972008-05-31 16:11:38 +00003131 regs->pc = (unsigned long) ka->_sa_handler;
thsc3b5bc82007-12-02 06:31:25 +00003132
3133 unlock_user_struct(frame, frame_addr, 1);
3134 return;
3135
3136give_sigsegv:
3137 unlock_user_struct(frame, frame_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02003138 force_sig(TARGET_SIGSEGV);
thsc3b5bc82007-12-02 06:31:25 +00003139}
3140
3141long do_sigreturn(CPUState *regs)
3142{
3143 struct target_sigframe *frame;
3144 abi_ulong frame_addr;
3145 sigset_t blocked;
Anthony Liguoric227f092009-10-01 16:12:16 -05003146 target_sigset_t target_set;
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003147 target_ulong r0;
thsc3b5bc82007-12-02 06:31:25 +00003148 int i;
3149 int err = 0;
3150
3151#if defined(DEBUG_SIGNAL)
3152 fprintf(stderr, "do_sigreturn\n");
3153#endif
3154 frame_addr = regs->gregs[15];
3155 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
3156 goto badframe;
3157
3158 err |= __get_user(target_set.sig[0], &frame->sc.oldmask);
3159 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
3160 err |= (__get_user(target_set.sig[i], &frame->extramask[i - 1]));
3161 }
3162
3163 if (err)
3164 goto badframe;
3165
3166 target_to_host_sigset_internal(&blocked, &target_set);
3167 sigprocmask(SIG_SETMASK, &blocked, NULL);
3168
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003169 if (restore_sigcontext(regs, &frame->sc, &r0))
thsc3b5bc82007-12-02 06:31:25 +00003170 goto badframe;
3171
3172 unlock_user_struct(frame, frame_addr, 0);
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003173 return r0;
thsc3b5bc82007-12-02 06:31:25 +00003174
3175badframe:
3176 unlock_user_struct(frame, frame_addr, 0);
3177 force_sig(TARGET_SIGSEGV);
3178 return 0;
3179}
3180
3181long do_rt_sigreturn(CPUState *regs)
3182{
3183 struct target_rt_sigframe *frame;
3184 abi_ulong frame_addr;
3185 sigset_t blocked;
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003186 target_ulong r0;
thsc3b5bc82007-12-02 06:31:25 +00003187
3188#if defined(DEBUG_SIGNAL)
3189 fprintf(stderr, "do_rt_sigreturn\n");
3190#endif
3191 frame_addr = regs->gregs[15];
3192 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
3193 goto badframe;
3194
Aurelien Jarno60e99242010-03-29 02:12:51 +02003195 target_to_host_sigset(&blocked, &frame->uc.tuc_sigmask);
thsc3b5bc82007-12-02 06:31:25 +00003196 sigprocmask(SIG_SETMASK, &blocked, NULL);
3197
Aurelien Jarno60e99242010-03-29 02:12:51 +02003198 if (restore_sigcontext(regs, &frame->uc.tuc_mcontext, &r0))
thsc3b5bc82007-12-02 06:31:25 +00003199 goto badframe;
3200
3201 if (do_sigaltstack(frame_addr +
Aurelien Jarno60e99242010-03-29 02:12:51 +02003202 offsetof(struct target_rt_sigframe, uc.tuc_stack),
thsc3b5bc82007-12-02 06:31:25 +00003203 0, get_sp_from_cpustate(regs)) == -EFAULT)
3204 goto badframe;
3205
3206 unlock_user_struct(frame, frame_addr, 0);
takasi-y@ops.dti.ne.jpd8714432010-02-18 00:46:45 +09003207 return r0;
thsc3b5bc82007-12-02 06:31:25 +00003208
3209badframe:
3210 unlock_user_struct(frame, frame_addr, 0);
3211 force_sig(TARGET_SIGSEGV);
3212 return 0;
3213}
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003214#elif defined(TARGET_MICROBLAZE)
3215
3216struct target_sigcontext {
3217 struct target_pt_regs regs; /* needs to be first */
3218 uint32_t oldmask;
3219};
3220
Edgar E. Iglesiasb2178702010-07-23 09:30:37 +02003221struct target_stack_t {
3222 abi_ulong ss_sp;
3223 int ss_flags;
3224 unsigned int ss_size;
3225};
3226
3227struct target_ucontext {
Richard Hendersonf711df62010-11-22 14:57:52 -08003228 abi_ulong tuc_flags;
3229 abi_ulong tuc_link;
3230 struct target_stack_t tuc_stack;
3231 struct target_sigcontext tuc_mcontext;
3232 uint32_t tuc_extramask[TARGET_NSIG_WORDS - 1];
Edgar E. Iglesiasb2178702010-07-23 09:30:37 +02003233};
3234
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003235/* Signal frames. */
3236struct target_signal_frame {
Edgar E. Iglesiasb2178702010-07-23 09:30:37 +02003237 struct target_ucontext uc;
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003238 uint32_t extramask[TARGET_NSIG_WORDS - 1];
3239 uint32_t tramp[2];
3240};
3241
3242struct rt_signal_frame {
3243 struct siginfo info;
3244 struct ucontext uc;
3245 uint32_t tramp[2];
3246};
3247
3248static void setup_sigcontext(struct target_sigcontext *sc, CPUState *env)
3249{
3250 __put_user(env->regs[0], &sc->regs.r0);
3251 __put_user(env->regs[1], &sc->regs.r1);
3252 __put_user(env->regs[2], &sc->regs.r2);
3253 __put_user(env->regs[3], &sc->regs.r3);
3254 __put_user(env->regs[4], &sc->regs.r4);
3255 __put_user(env->regs[5], &sc->regs.r5);
3256 __put_user(env->regs[6], &sc->regs.r6);
3257 __put_user(env->regs[7], &sc->regs.r7);
3258 __put_user(env->regs[8], &sc->regs.r8);
3259 __put_user(env->regs[9], &sc->regs.r9);
3260 __put_user(env->regs[10], &sc->regs.r10);
3261 __put_user(env->regs[11], &sc->regs.r11);
3262 __put_user(env->regs[12], &sc->regs.r12);
3263 __put_user(env->regs[13], &sc->regs.r13);
3264 __put_user(env->regs[14], &sc->regs.r14);
3265 __put_user(env->regs[15], &sc->regs.r15);
3266 __put_user(env->regs[16], &sc->regs.r16);
3267 __put_user(env->regs[17], &sc->regs.r17);
3268 __put_user(env->regs[18], &sc->regs.r18);
3269 __put_user(env->regs[19], &sc->regs.r19);
3270 __put_user(env->regs[20], &sc->regs.r20);
3271 __put_user(env->regs[21], &sc->regs.r21);
3272 __put_user(env->regs[22], &sc->regs.r22);
3273 __put_user(env->regs[23], &sc->regs.r23);
3274 __put_user(env->regs[24], &sc->regs.r24);
3275 __put_user(env->regs[25], &sc->regs.r25);
3276 __put_user(env->regs[26], &sc->regs.r26);
3277 __put_user(env->regs[27], &sc->regs.r27);
3278 __put_user(env->regs[28], &sc->regs.r28);
3279 __put_user(env->regs[29], &sc->regs.r29);
3280 __put_user(env->regs[30], &sc->regs.r30);
3281 __put_user(env->regs[31], &sc->regs.r31);
3282 __put_user(env->sregs[SR_PC], &sc->regs.pc);
3283}
3284
3285static void restore_sigcontext(struct target_sigcontext *sc, CPUState *env)
3286{
3287 __get_user(env->regs[0], &sc->regs.r0);
3288 __get_user(env->regs[1], &sc->regs.r1);
3289 __get_user(env->regs[2], &sc->regs.r2);
3290 __get_user(env->regs[3], &sc->regs.r3);
3291 __get_user(env->regs[4], &sc->regs.r4);
3292 __get_user(env->regs[5], &sc->regs.r5);
3293 __get_user(env->regs[6], &sc->regs.r6);
3294 __get_user(env->regs[7], &sc->regs.r7);
3295 __get_user(env->regs[8], &sc->regs.r8);
3296 __get_user(env->regs[9], &sc->regs.r9);
3297 __get_user(env->regs[10], &sc->regs.r10);
3298 __get_user(env->regs[11], &sc->regs.r11);
3299 __get_user(env->regs[12], &sc->regs.r12);
3300 __get_user(env->regs[13], &sc->regs.r13);
3301 __get_user(env->regs[14], &sc->regs.r14);
3302 __get_user(env->regs[15], &sc->regs.r15);
3303 __get_user(env->regs[16], &sc->regs.r16);
3304 __get_user(env->regs[17], &sc->regs.r17);
3305 __get_user(env->regs[18], &sc->regs.r18);
3306 __get_user(env->regs[19], &sc->regs.r19);
3307 __get_user(env->regs[20], &sc->regs.r20);
3308 __get_user(env->regs[21], &sc->regs.r21);
3309 __get_user(env->regs[22], &sc->regs.r22);
3310 __get_user(env->regs[23], &sc->regs.r23);
3311 __get_user(env->regs[24], &sc->regs.r24);
3312 __get_user(env->regs[25], &sc->regs.r25);
3313 __get_user(env->regs[26], &sc->regs.r26);
3314 __get_user(env->regs[27], &sc->regs.r27);
3315 __get_user(env->regs[28], &sc->regs.r28);
3316 __get_user(env->regs[29], &sc->regs.r29);
3317 __get_user(env->regs[30], &sc->regs.r30);
3318 __get_user(env->regs[31], &sc->regs.r31);
3319 __get_user(env->sregs[SR_PC], &sc->regs.pc);
3320}
3321
3322static abi_ulong get_sigframe(struct target_sigaction *ka,
3323 CPUState *env, int frame_size)
3324{
3325 abi_ulong sp = env->regs[1];
3326
3327 if ((ka->sa_flags & SA_ONSTACK) != 0 && !on_sig_stack(sp))
3328 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
3329
3330 return ((sp - frame_size) & -8UL);
3331}
3332
3333static void setup_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05003334 target_sigset_t *set, CPUState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003335{
3336 struct target_signal_frame *frame;
3337 abi_ulong frame_addr;
3338 int err = 0;
3339 int i;
3340
3341 frame_addr = get_sigframe(ka, env, sizeof *frame);
3342 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
3343 goto badframe;
3344
3345 /* Save the mask. */
Richard Hendersonf711df62010-11-22 14:57:52 -08003346 err |= __put_user(set->sig[0], &frame->uc.tuc_mcontext.oldmask);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003347 if (err)
3348 goto badframe;
3349
3350 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
3351 if (__put_user(set->sig[i], &frame->extramask[i - 1]))
3352 goto badframe;
3353 }
3354
Richard Hendersonf711df62010-11-22 14:57:52 -08003355 setup_sigcontext(&frame->uc.tuc_mcontext, env);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003356
3357 /* Set up to return from userspace. If provided, use a stub
3358 already in userspace. */
3359 /* minus 8 is offset to cater for "rtsd r15,8" offset */
3360 if (ka->sa_flags & TARGET_SA_RESTORER) {
3361 env->regs[15] = ((unsigned long)ka->sa_restorer)-8;
3362 } else {
3363 uint32_t t;
3364 /* Note, these encodings are _big endian_! */
3365 /* addi r12, r0, __NR_sigreturn */
3366 t = 0x31800000UL | TARGET_NR_sigreturn;
3367 err |= __put_user(t, frame->tramp + 0);
3368 /* brki r14, 0x8 */
3369 t = 0xb9cc0008UL;
3370 err |= __put_user(t, frame->tramp + 1);
3371
3372 /* Return from sighandler will jump to the tramp.
3373 Negative 8 offset because return is rtsd r15, 8 */
3374 env->regs[15] = ((unsigned long)frame->tramp) - 8;
3375 }
3376
3377 if (err)
3378 goto badframe;
3379
3380 /* Set up registers for signal handler */
3381 env->regs[1] = (unsigned long) frame;
3382 /* Signal handler args: */
3383 env->regs[5] = sig; /* Arg 0: signum */
Edgar E. Iglesias187b4e02010-07-15 15:32:51 +02003384 env->regs[6] = 0;
Edgar E. Iglesiasb2178702010-07-23 09:30:37 +02003385 env->regs[7] = (unsigned long) &frame->uc; /* arg 1: sigcontext */
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003386
3387 /* Offset of 4 to handle microblaze rtid r14, 0 */
3388 env->sregs[SR_PC] = (unsigned long)ka->_sa_handler;
3389
3390 unlock_user_struct(frame, frame_addr, 1);
3391 return;
3392 badframe:
3393 unlock_user_struct(frame, frame_addr, 1);
3394 force_sig(TARGET_SIGSEGV);
3395}
3396
3397static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05003398 target_siginfo_t *info,
3399 target_sigset_t *set, CPUState *env)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003400{
3401 fprintf(stderr, "Microblaze setup_rt_frame: not implemented\n");
3402}
3403
3404long do_sigreturn(CPUState *env)
3405{
3406 struct target_signal_frame *frame;
3407 abi_ulong frame_addr;
Anthony Liguoric227f092009-10-01 16:12:16 -05003408 target_sigset_t target_set;
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003409 sigset_t set;
3410 int i;
3411
3412 frame_addr = env->regs[R_SP];
3413 /* Make sure the guest isn't playing games. */
3414 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 1))
3415 goto badframe;
3416
3417 /* Restore blocked signals */
Richard Hendersonf711df62010-11-22 14:57:52 -08003418 if (__get_user(target_set.sig[0], &frame->uc.tuc_mcontext.oldmask))
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003419 goto badframe;
3420 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
3421 if (__get_user(target_set.sig[i], &frame->extramask[i - 1]))
3422 goto badframe;
3423 }
3424 target_to_host_sigset_internal(&set, &target_set);
3425 sigprocmask(SIG_SETMASK, &set, NULL);
3426
Richard Hendersonf711df62010-11-22 14:57:52 -08003427 restore_sigcontext(&frame->uc.tuc_mcontext, env);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +02003428 /* We got here through a sigreturn syscall, our path back is via an
3429 rtb insn so setup r14 for that. */
3430 env->regs[14] = env->sregs[SR_PC];
3431
3432 unlock_user_struct(frame, frame_addr, 0);
3433 return env->regs[10];
3434 badframe:
3435 unlock_user_struct(frame, frame_addr, 0);
3436 force_sig(TARGET_SIGSEGV);
3437}
3438
3439long do_rt_sigreturn(CPUState *env)
3440{
3441 fprintf(stderr, "Microblaze do_rt_sigreturn: not implemented\n");
3442 return -TARGET_ENOSYS;
3443}
3444
edgar_iglb6d3abd2008-02-28 11:29:27 +00003445#elif defined(TARGET_CRIS)
3446
3447struct target_sigcontext {
3448 struct target_pt_regs regs; /* needs to be first */
3449 uint32_t oldmask;
3450 uint32_t usp; /* usp before stacking this gunk on it */
3451};
3452
3453/* Signal frames. */
3454struct target_signal_frame {
3455 struct target_sigcontext sc;
3456 uint32_t extramask[TARGET_NSIG_WORDS - 1];
3457 uint8_t retcode[8]; /* Trampoline code. */
3458};
3459
3460struct rt_signal_frame {
3461 struct siginfo *pinfo;
3462 void *puc;
3463 struct siginfo info;
3464 struct ucontext uc;
3465 uint8_t retcode[8]; /* Trampoline code. */
3466};
3467
3468static void setup_sigcontext(struct target_sigcontext *sc, CPUState *env)
3469{
edgar_igl9664d922008-03-03 22:23:53 +00003470 __put_user(env->regs[0], &sc->regs.r0);
3471 __put_user(env->regs[1], &sc->regs.r1);
3472 __put_user(env->regs[2], &sc->regs.r2);
3473 __put_user(env->regs[3], &sc->regs.r3);
3474 __put_user(env->regs[4], &sc->regs.r4);
3475 __put_user(env->regs[5], &sc->regs.r5);
3476 __put_user(env->regs[6], &sc->regs.r6);
3477 __put_user(env->regs[7], &sc->regs.r7);
3478 __put_user(env->regs[8], &sc->regs.r8);
3479 __put_user(env->regs[9], &sc->regs.r9);
3480 __put_user(env->regs[10], &sc->regs.r10);
3481 __put_user(env->regs[11], &sc->regs.r11);
3482 __put_user(env->regs[12], &sc->regs.r12);
3483 __put_user(env->regs[13], &sc->regs.r13);
3484 __put_user(env->regs[14], &sc->usp);
3485 __put_user(env->regs[15], &sc->regs.acr);
3486 __put_user(env->pregs[PR_MOF], &sc->regs.mof);
3487 __put_user(env->pregs[PR_SRP], &sc->regs.srp);
3488 __put_user(env->pc, &sc->regs.erp);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003489}
edgar_igl9664d922008-03-03 22:23:53 +00003490
edgar_iglb6d3abd2008-02-28 11:29:27 +00003491static void restore_sigcontext(struct target_sigcontext *sc, CPUState *env)
3492{
edgar_igl9664d922008-03-03 22:23:53 +00003493 __get_user(env->regs[0], &sc->regs.r0);
3494 __get_user(env->regs[1], &sc->regs.r1);
3495 __get_user(env->regs[2], &sc->regs.r2);
3496 __get_user(env->regs[3], &sc->regs.r3);
3497 __get_user(env->regs[4], &sc->regs.r4);
3498 __get_user(env->regs[5], &sc->regs.r5);
3499 __get_user(env->regs[6], &sc->regs.r6);
3500 __get_user(env->regs[7], &sc->regs.r7);
3501 __get_user(env->regs[8], &sc->regs.r8);
3502 __get_user(env->regs[9], &sc->regs.r9);
3503 __get_user(env->regs[10], &sc->regs.r10);
3504 __get_user(env->regs[11], &sc->regs.r11);
3505 __get_user(env->regs[12], &sc->regs.r12);
3506 __get_user(env->regs[13], &sc->regs.r13);
3507 __get_user(env->regs[14], &sc->usp);
3508 __get_user(env->regs[15], &sc->regs.acr);
3509 __get_user(env->pregs[PR_MOF], &sc->regs.mof);
3510 __get_user(env->pregs[PR_SRP], &sc->regs.srp);
3511 __get_user(env->pc, &sc->regs.erp);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003512}
3513
edgar_igl9664d922008-03-03 22:23:53 +00003514static abi_ulong get_sigframe(CPUState *env, int framesize)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003515{
edgar_igl9664d922008-03-03 22:23:53 +00003516 abi_ulong sp;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003517 /* Align the stack downwards to 4. */
edgar_igl9664d922008-03-03 22:23:53 +00003518 sp = (env->regs[R_SP] & ~3);
3519 return sp - framesize;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003520}
3521
pbrook624f7972008-05-31 16:11:38 +00003522static void setup_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05003523 target_sigset_t *set, CPUState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003524{
3525 struct target_signal_frame *frame;
edgar_igl9664d922008-03-03 22:23:53 +00003526 abi_ulong frame_addr;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003527 int err = 0;
3528 int i;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003529
edgar_igl9664d922008-03-03 22:23:53 +00003530 frame_addr = get_sigframe(env, sizeof *frame);
3531 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
edgar_iglb6d3abd2008-02-28 11:29:27 +00003532 goto badframe;
3533
3534 /*
3535 * The CRIS signal return trampoline. A real linux/CRIS kernel doesn't
3536 * use this trampoline anymore but it sets it up for GDB.
3537 * In QEMU, using the trampoline simplifies things a bit so we use it.
3538 *
3539 * This is movu.w __NR_sigreturn, r9; break 13;
3540 */
3541 err |= __put_user(0x9c5f, frame->retcode+0);
3542 err |= __put_user(TARGET_NR_sigreturn,
3543 frame->retcode+2);
3544 err |= __put_user(0xe93d, frame->retcode+4);
3545
3546 /* Save the mask. */
3547 err |= __put_user(set->sig[0], &frame->sc.oldmask);
3548 if (err)
3549 goto badframe;
3550
3551 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
3552 if (__put_user(set->sig[i], &frame->extramask[i - 1]))
3553 goto badframe;
3554 }
3555
3556 setup_sigcontext(&frame->sc, env);
3557
3558 /* Move the stack and setup the arguments for the handler. */
balrog526ccb72008-07-16 12:13:52 +00003559 env->regs[R_SP] = (uint32_t) (unsigned long) frame;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003560 env->regs[10] = sig;
pbrook624f7972008-05-31 16:11:38 +00003561 env->pc = (unsigned long) ka->_sa_handler;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003562 /* Link SRP so the guest returns through the trampoline. */
balrog526ccb72008-07-16 12:13:52 +00003563 env->pregs[PR_SRP] = (uint32_t) (unsigned long) &frame->retcode[0];
edgar_iglb6d3abd2008-02-28 11:29:27 +00003564
edgar_igl9664d922008-03-03 22:23:53 +00003565 unlock_user_struct(frame, frame_addr, 1);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003566 return;
3567 badframe:
edgar_igl9664d922008-03-03 22:23:53 +00003568 unlock_user_struct(frame, frame_addr, 1);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003569 force_sig(TARGET_SIGSEGV);
3570}
3571
pbrook624f7972008-05-31 16:11:38 +00003572static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05003573 target_siginfo_t *info,
3574 target_sigset_t *set, CPUState *env)
edgar_iglb6d3abd2008-02-28 11:29:27 +00003575{
3576 fprintf(stderr, "CRIS setup_rt_frame: not implemented\n");
3577}
3578
3579long do_sigreturn(CPUState *env)
3580{
3581 struct target_signal_frame *frame;
edgar_igl9664d922008-03-03 22:23:53 +00003582 abi_ulong frame_addr;
Anthony Liguoric227f092009-10-01 16:12:16 -05003583 target_sigset_t target_set;
edgar_iglb6d3abd2008-02-28 11:29:27 +00003584 sigset_t set;
3585 int i;
3586
edgar_igl9664d922008-03-03 22:23:53 +00003587 frame_addr = env->regs[R_SP];
edgar_iglb6d3abd2008-02-28 11:29:27 +00003588 /* Make sure the guest isn't playing games. */
edgar_igl9664d922008-03-03 22:23:53 +00003589 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 1))
edgar_iglb6d3abd2008-02-28 11:29:27 +00003590 goto badframe;
3591
3592 /* Restore blocked signals */
3593 if (__get_user(target_set.sig[0], &frame->sc.oldmask))
3594 goto badframe;
3595 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
3596 if (__get_user(target_set.sig[i], &frame->extramask[i - 1]))
3597 goto badframe;
3598 }
3599 target_to_host_sigset_internal(&set, &target_set);
3600 sigprocmask(SIG_SETMASK, &set, NULL);
3601
3602 restore_sigcontext(&frame->sc, env);
edgar_igl9664d922008-03-03 22:23:53 +00003603 unlock_user_struct(frame, frame_addr, 0);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003604 return env->regs[10];
3605 badframe:
edgar_igl9664d922008-03-03 22:23:53 +00003606 unlock_user_struct(frame, frame_addr, 0);
edgar_iglb6d3abd2008-02-28 11:29:27 +00003607 force_sig(TARGET_SIGSEGV);
3608}
3609
3610long do_rt_sigreturn(CPUState *env)
3611{
3612 fprintf(stderr, "CRIS do_rt_sigreturn: not implemented\n");
3613 return -TARGET_ENOSYS;
3614}
thsc3b5bc82007-12-02 06:31:25 +00003615
Nathan Froydbcd49332009-05-12 19:13:18 -07003616#elif defined(TARGET_PPC) && !defined(TARGET_PPC64)
3617
3618/* FIXME: Many of the structures are defined for both PPC and PPC64, but
3619 the signal handling is different enough that we haven't implemented
3620 support for PPC64 yet. Hence the restriction above.
3621
3622 There are various #if'd blocks for code for TARGET_PPC64. These
3623 blocks should go away so that we can successfully run 32-bit and
3624 64-bit binaries on a QEMU configured for PPC64. */
3625
3626/* Size of dummy stack frame allocated when calling signal handler.
3627 See arch/powerpc/include/asm/ptrace.h. */
3628#if defined(TARGET_PPC64)
3629#define SIGNAL_FRAMESIZE 128
3630#else
3631#define SIGNAL_FRAMESIZE 64
3632#endif
3633
3634/* See arch/powerpc/include/asm/sigcontext.h. */
3635struct target_sigcontext {
3636 target_ulong _unused[4];
3637 int32_t signal;
3638#if defined(TARGET_PPC64)
3639 int32_t pad0;
3640#endif
3641 target_ulong handler;
3642 target_ulong oldmask;
3643 target_ulong regs; /* struct pt_regs __user * */
3644 /* TODO: PPC64 includes extra bits here. */
3645};
3646
3647/* Indices for target_mcontext.mc_gregs, below.
3648 See arch/powerpc/include/asm/ptrace.h for details. */
3649enum {
3650 TARGET_PT_R0 = 0,
3651 TARGET_PT_R1 = 1,
3652 TARGET_PT_R2 = 2,
3653 TARGET_PT_R3 = 3,
3654 TARGET_PT_R4 = 4,
3655 TARGET_PT_R5 = 5,
3656 TARGET_PT_R6 = 6,
3657 TARGET_PT_R7 = 7,
3658 TARGET_PT_R8 = 8,
3659 TARGET_PT_R9 = 9,
3660 TARGET_PT_R10 = 10,
3661 TARGET_PT_R11 = 11,
3662 TARGET_PT_R12 = 12,
3663 TARGET_PT_R13 = 13,
3664 TARGET_PT_R14 = 14,
3665 TARGET_PT_R15 = 15,
3666 TARGET_PT_R16 = 16,
3667 TARGET_PT_R17 = 17,
3668 TARGET_PT_R18 = 18,
3669 TARGET_PT_R19 = 19,
3670 TARGET_PT_R20 = 20,
3671 TARGET_PT_R21 = 21,
3672 TARGET_PT_R22 = 22,
3673 TARGET_PT_R23 = 23,
3674 TARGET_PT_R24 = 24,
3675 TARGET_PT_R25 = 25,
3676 TARGET_PT_R26 = 26,
3677 TARGET_PT_R27 = 27,
3678 TARGET_PT_R28 = 28,
3679 TARGET_PT_R29 = 29,
3680 TARGET_PT_R30 = 30,
3681 TARGET_PT_R31 = 31,
3682 TARGET_PT_NIP = 32,
3683 TARGET_PT_MSR = 33,
3684 TARGET_PT_ORIG_R3 = 34,
3685 TARGET_PT_CTR = 35,
3686 TARGET_PT_LNK = 36,
3687 TARGET_PT_XER = 37,
3688 TARGET_PT_CCR = 38,
3689 /* Yes, there are two registers with #39. One is 64-bit only. */
3690 TARGET_PT_MQ = 39,
3691 TARGET_PT_SOFTE = 39,
3692 TARGET_PT_TRAP = 40,
3693 TARGET_PT_DAR = 41,
3694 TARGET_PT_DSISR = 42,
3695 TARGET_PT_RESULT = 43,
3696 TARGET_PT_REGS_COUNT = 44
3697};
3698
3699/* See arch/powerpc/include/asm/ucontext.h. Only used for 32-bit PPC;
3700 on 64-bit PPC, sigcontext and mcontext are one and the same. */
3701struct target_mcontext {
3702 target_ulong mc_gregs[48];
3703 /* Includes fpscr. */
3704 uint64_t mc_fregs[33];
3705 target_ulong mc_pad[2];
3706 /* We need to handle Altivec and SPE at the same time, which no
3707 kernel needs to do. Fortunately, the kernel defines this bit to
3708 be Altivec-register-large all the time, rather than trying to
3709 twiddle it based on the specific platform. */
3710 union {
3711 /* SPE vector registers. One extra for SPEFSCR. */
3712 uint32_t spe[33];
3713 /* Altivec vector registers. The packing of VSCR and VRSAVE
3714 varies depending on whether we're PPC64 or not: PPC64 splits
3715 them apart; PPC32 stuffs them together. */
3716#if defined(TARGET_PPC64)
malc3efa9a62009-07-18 13:10:12 +04003717#define QEMU_NVRREG 34
Nathan Froydbcd49332009-05-12 19:13:18 -07003718#else
malc3efa9a62009-07-18 13:10:12 +04003719#define QEMU_NVRREG 33
Nathan Froydbcd49332009-05-12 19:13:18 -07003720#endif
Anthony Liguoric227f092009-10-01 16:12:16 -05003721 ppc_avr_t altivec[QEMU_NVRREG];
malc3efa9a62009-07-18 13:10:12 +04003722#undef QEMU_NVRREG
Nathan Froydbcd49332009-05-12 19:13:18 -07003723 } mc_vregs __attribute__((__aligned__(16)));
3724};
3725
3726struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02003727 target_ulong tuc_flags;
3728 target_ulong tuc_link; /* struct ucontext __user * */
3729 struct target_sigaltstack tuc_stack;
Nathan Froydbcd49332009-05-12 19:13:18 -07003730#if !defined(TARGET_PPC64)
Aurelien Jarno60e99242010-03-29 02:12:51 +02003731 int32_t tuc_pad[7];
3732 target_ulong tuc_regs; /* struct mcontext __user *
Nathan Froydbcd49332009-05-12 19:13:18 -07003733 points to uc_mcontext field */
3734#endif
Aurelien Jarno60e99242010-03-29 02:12:51 +02003735 target_sigset_t tuc_sigmask;
Nathan Froydbcd49332009-05-12 19:13:18 -07003736#if defined(TARGET_PPC64)
Anthony Liguoric227f092009-10-01 16:12:16 -05003737 target_sigset_t unused[15]; /* Allow for uc_sigmask growth */
Aurelien Jarno60e99242010-03-29 02:12:51 +02003738 struct target_sigcontext tuc_mcontext;
Nathan Froydbcd49332009-05-12 19:13:18 -07003739#else
Aurelien Jarno60e99242010-03-29 02:12:51 +02003740 int32_t tuc_maskext[30];
3741 int32_t tuc_pad2[3];
3742 struct target_mcontext tuc_mcontext;
Nathan Froydbcd49332009-05-12 19:13:18 -07003743#endif
3744};
3745
3746/* See arch/powerpc/kernel/signal_32.c. */
3747struct target_sigframe {
3748 struct target_sigcontext sctx;
3749 struct target_mcontext mctx;
3750 int32_t abigap[56];
3751};
3752
3753struct target_rt_sigframe {
3754 struct target_siginfo info;
3755 struct target_ucontext uc;
3756 int32_t abigap[56];
3757};
3758
3759/* We use the mc_pad field for the signal return trampoline. */
3760#define tramp mc_pad
3761
3762/* See arch/powerpc/kernel/signal.c. */
3763static target_ulong get_sigframe(struct target_sigaction *ka,
3764 CPUState *env,
3765 int frame_size)
3766{
3767 target_ulong oldsp, newsp;
3768
3769 oldsp = env->gpr[1];
3770
3771 if ((ka->sa_flags & TARGET_SA_ONSTACK) &&
3772 (sas_ss_flags(oldsp))) {
3773 oldsp = (target_sigaltstack_used.ss_sp
3774 + target_sigaltstack_used.ss_size);
3775 }
3776
3777 newsp = (oldsp - frame_size) & ~0xFUL;
3778
3779 return newsp;
3780}
3781
3782static int save_user_regs(CPUState *env, struct target_mcontext *frame,
3783 int sigret)
3784{
3785 target_ulong msr = env->msr;
3786 int i;
3787 target_ulong ccr = 0;
3788
3789 /* In general, the kernel attempts to be intelligent about what it
3790 needs to save for Altivec/FP/SPE registers. We don't care that
3791 much, so we just go ahead and save everything. */
3792
3793 /* Save general registers. */
3794 for (i = 0; i < ARRAY_SIZE(env->gpr); i++) {
3795 if (__put_user(env->gpr[i], &frame->mc_gregs[i])) {
3796 return 1;
3797 }
3798 }
3799 if (__put_user(env->nip, &frame->mc_gregs[TARGET_PT_NIP])
3800 || __put_user(env->ctr, &frame->mc_gregs[TARGET_PT_CTR])
3801 || __put_user(env->lr, &frame->mc_gregs[TARGET_PT_LNK])
3802 || __put_user(env->xer, &frame->mc_gregs[TARGET_PT_XER]))
3803 return 1;
3804
3805 for (i = 0; i < ARRAY_SIZE(env->crf); i++) {
3806 ccr |= env->crf[i] << (32 - ((i + 1) * 4));
3807 }
3808 if (__put_user(ccr, &frame->mc_gregs[TARGET_PT_CCR]))
3809 return 1;
3810
3811 /* Save Altivec registers if necessary. */
3812 if (env->insns_flags & PPC_ALTIVEC) {
3813 for (i = 0; i < ARRAY_SIZE(env->avr); i++) {
Anthony Liguoric227f092009-10-01 16:12:16 -05003814 ppc_avr_t *avr = &env->avr[i];
3815 ppc_avr_t *vreg = &frame->mc_vregs.altivec[i];
Nathan Froydbcd49332009-05-12 19:13:18 -07003816
3817 if (__put_user(avr->u64[0], &vreg->u64[0]) ||
3818 __put_user(avr->u64[1], &vreg->u64[1])) {
3819 return 1;
3820 }
3821 }
3822 /* Set MSR_VR in the saved MSR value to indicate that
3823 frame->mc_vregs contains valid data. */
3824 msr |= MSR_VR;
3825 if (__put_user((uint32_t)env->spr[SPR_VRSAVE],
3826 &frame->mc_vregs.altivec[32].u32[3]))
3827 return 1;
3828 }
3829
3830 /* Save floating point registers. */
3831 if (env->insns_flags & PPC_FLOAT) {
3832 for (i = 0; i < ARRAY_SIZE(env->fpr); i++) {
3833 if (__put_user(env->fpr[i], &frame->mc_fregs[i])) {
3834 return 1;
3835 }
3836 }
3837 if (__put_user((uint64_t) env->fpscr, &frame->mc_fregs[32]))
3838 return 1;
3839 }
3840
3841 /* Save SPE registers. The kernel only saves the high half. */
3842 if (env->insns_flags & PPC_SPE) {
3843#if defined(TARGET_PPC64)
3844 for (i = 0; i < ARRAY_SIZE(env->gpr); i++) {
3845 if (__put_user(env->gpr[i] >> 32, &frame->mc_vregs.spe[i])) {
3846 return 1;
3847 }
3848 }
3849#else
3850 for (i = 0; i < ARRAY_SIZE(env->gprh); i++) {
3851 if (__put_user(env->gprh[i], &frame->mc_vregs.spe[i])) {
3852 return 1;
3853 }
3854 }
3855#endif
3856 /* Set MSR_SPE in the saved MSR value to indicate that
3857 frame->mc_vregs contains valid data. */
3858 msr |= MSR_SPE;
3859 if (__put_user(env->spe_fscr, &frame->mc_vregs.spe[32]))
3860 return 1;
3861 }
3862
3863 /* Store MSR. */
3864 if (__put_user(msr, &frame->mc_gregs[TARGET_PT_MSR]))
3865 return 1;
3866
3867 /* Set up the sigreturn trampoline: li r0,sigret; sc. */
3868 if (sigret) {
3869 if (__put_user(0x38000000UL | sigret, &frame->tramp[0]) ||
3870 __put_user(0x44000002UL, &frame->tramp[1])) {
3871 return 1;
3872 }
3873 }
3874
3875 return 0;
3876}
3877
3878static int restore_user_regs(CPUState *env,
3879 struct target_mcontext *frame, int sig)
3880{
3881 target_ulong save_r2 = 0;
3882 target_ulong msr;
3883 target_ulong ccr;
3884
3885 int i;
3886
3887 if (!sig) {
3888 save_r2 = env->gpr[2];
3889 }
3890
3891 /* Restore general registers. */
3892 for (i = 0; i < ARRAY_SIZE(env->gpr); i++) {
3893 if (__get_user(env->gpr[i], &frame->mc_gregs[i])) {
3894 return 1;
3895 }
3896 }
3897 if (__get_user(env->nip, &frame->mc_gregs[TARGET_PT_NIP])
3898 || __get_user(env->ctr, &frame->mc_gregs[TARGET_PT_CTR])
3899 || __get_user(env->lr, &frame->mc_gregs[TARGET_PT_LNK])
3900 || __get_user(env->xer, &frame->mc_gregs[TARGET_PT_XER]))
3901 return 1;
3902 if (__get_user(ccr, &frame->mc_gregs[TARGET_PT_CCR]))
3903 return 1;
3904
3905 for (i = 0; i < ARRAY_SIZE(env->crf); i++) {
3906 env->crf[i] = (ccr >> (32 - ((i + 1) * 4))) & 0xf;
3907 }
3908
3909 if (!sig) {
3910 env->gpr[2] = save_r2;
3911 }
3912 /* Restore MSR. */
3913 if (__get_user(msr, &frame->mc_gregs[TARGET_PT_MSR]))
3914 return 1;
3915
3916 /* If doing signal return, restore the previous little-endian mode. */
3917 if (sig)
3918 env->msr = (env->msr & ~MSR_LE) | (msr & MSR_LE);
3919
3920 /* Restore Altivec registers if necessary. */
3921 if (env->insns_flags & PPC_ALTIVEC) {
3922 for (i = 0; i < ARRAY_SIZE(env->avr); i++) {
Anthony Liguoric227f092009-10-01 16:12:16 -05003923 ppc_avr_t *avr = &env->avr[i];
3924 ppc_avr_t *vreg = &frame->mc_vregs.altivec[i];
Nathan Froydbcd49332009-05-12 19:13:18 -07003925
3926 if (__get_user(avr->u64[0], &vreg->u64[0]) ||
3927 __get_user(avr->u64[1], &vreg->u64[1])) {
3928 return 1;
3929 }
3930 }
3931 /* Set MSR_VEC in the saved MSR value to indicate that
3932 frame->mc_vregs contains valid data. */
3933 if (__get_user(env->spr[SPR_VRSAVE],
3934 (target_ulong *)(&frame->mc_vregs.altivec[32].u32[3])))
3935 return 1;
3936 }
3937
3938 /* Restore floating point registers. */
3939 if (env->insns_flags & PPC_FLOAT) {
3940 uint64_t fpscr;
3941 for (i = 0; i < ARRAY_SIZE(env->fpr); i++) {
3942 if (__get_user(env->fpr[i], &frame->mc_fregs[i])) {
3943 return 1;
3944 }
3945 }
3946 if (__get_user(fpscr, &frame->mc_fregs[32]))
3947 return 1;
3948 env->fpscr = (uint32_t) fpscr;
3949 }
3950
3951 /* Save SPE registers. The kernel only saves the high half. */
3952 if (env->insns_flags & PPC_SPE) {
3953#if defined(TARGET_PPC64)
3954 for (i = 0; i < ARRAY_SIZE(env->gpr); i++) {
3955 uint32_t hi;
3956
3957 if (__get_user(hi, &frame->mc_vregs.spe[i])) {
3958 return 1;
3959 }
3960 env->gpr[i] = ((uint64_t)hi << 32) | ((uint32_t) env->gpr[i]);
3961 }
3962#else
3963 for (i = 0; i < ARRAY_SIZE(env->gprh); i++) {
3964 if (__get_user(env->gprh[i], &frame->mc_vregs.spe[i])) {
3965 return 1;
3966 }
3967 }
3968#endif
3969 if (__get_user(env->spe_fscr, &frame->mc_vregs.spe[32]))
3970 return 1;
3971 }
3972
3973 return 0;
3974}
3975
3976static void setup_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05003977 target_sigset_t *set, CPUState *env)
Nathan Froydbcd49332009-05-12 19:13:18 -07003978{
3979 struct target_sigframe *frame;
3980 struct target_sigcontext *sc;
3981 target_ulong frame_addr, newsp;
3982 int err = 0;
3983 int signal;
3984
3985 frame_addr = get_sigframe(ka, env, sizeof(*frame));
3986 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 1))
3987 goto sigsegv;
3988 sc = &frame->sctx;
3989
3990 signal = current_exec_domain_sig(sig);
3991
3992 err |= __put_user(h2g(ka->_sa_handler), &sc->handler);
3993 err |= __put_user(set->sig[0], &sc->oldmask);
3994#if defined(TARGET_PPC64)
3995 err |= __put_user(set->sig[0] >> 32, &sc->_unused[3]);
3996#else
3997 err |= __put_user(set->sig[1], &sc->_unused[3]);
3998#endif
3999 err |= __put_user(h2g(&frame->mctx), &sc->regs);
4000 err |= __put_user(sig, &sc->signal);
4001
4002 /* Save user regs. */
4003 err |= save_user_regs(env, &frame->mctx, TARGET_NR_sigreturn);
4004
4005 /* The kernel checks for the presence of a VDSO here. We don't
4006 emulate a vdso, so use a sigreturn system call. */
4007 env->lr = (target_ulong) h2g(frame->mctx.tramp);
4008
4009 /* Turn off all fp exceptions. */
4010 env->fpscr = 0;
4011
4012 /* Create a stack frame for the caller of the handler. */
4013 newsp = frame_addr - SIGNAL_FRAMESIZE;
4014 err |= __put_user(env->gpr[1], (target_ulong *)(uintptr_t) newsp);
4015
4016 if (err)
4017 goto sigsegv;
4018
4019 /* Set up registers for signal handler. */
4020 env->gpr[1] = newsp;
4021 env->gpr[3] = signal;
4022 env->gpr[4] = (target_ulong) h2g(sc);
4023 env->nip = (target_ulong) ka->_sa_handler;
4024 /* Signal handlers are entered in big-endian mode. */
4025 env->msr &= ~MSR_LE;
4026
4027 unlock_user_struct(frame, frame_addr, 1);
4028 return;
4029
4030sigsegv:
4031 unlock_user_struct(frame, frame_addr, 1);
4032 if (logfile)
4033 fprintf (logfile, "segfaulting from setup_frame\n");
Riku Voipio66393fb2009-12-04 15:16:32 +02004034 force_sig(TARGET_SIGSEGV);
Nathan Froydbcd49332009-05-12 19:13:18 -07004035}
4036
4037static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05004038 target_siginfo_t *info,
4039 target_sigset_t *set, CPUState *env)
Nathan Froydbcd49332009-05-12 19:13:18 -07004040{
4041 struct target_rt_sigframe *rt_sf;
4042 struct target_mcontext *frame;
4043 target_ulong rt_sf_addr, newsp = 0;
4044 int i, err = 0;
4045 int signal;
4046
4047 rt_sf_addr = get_sigframe(ka, env, sizeof(*rt_sf));
4048 if (!lock_user_struct(VERIFY_WRITE, rt_sf, rt_sf_addr, 1))
4049 goto sigsegv;
4050
4051 signal = current_exec_domain_sig(sig);
4052
4053 err |= copy_siginfo_to_user(&rt_sf->info, info);
4054
Aurelien Jarno60e99242010-03-29 02:12:51 +02004055 err |= __put_user(0, &rt_sf->uc.tuc_flags);
4056 err |= __put_user(0, &rt_sf->uc.tuc_link);
Nathan Froydbcd49332009-05-12 19:13:18 -07004057 err |= __put_user((target_ulong)target_sigaltstack_used.ss_sp,
Aurelien Jarno60e99242010-03-29 02:12:51 +02004058 &rt_sf->uc.tuc_stack.ss_sp);
Nathan Froydbcd49332009-05-12 19:13:18 -07004059 err |= __put_user(sas_ss_flags(env->gpr[1]),
Aurelien Jarno60e99242010-03-29 02:12:51 +02004060 &rt_sf->uc.tuc_stack.ss_flags);
Nathan Froydbcd49332009-05-12 19:13:18 -07004061 err |= __put_user(target_sigaltstack_used.ss_size,
Aurelien Jarno60e99242010-03-29 02:12:51 +02004062 &rt_sf->uc.tuc_stack.ss_size);
4063 err |= __put_user(h2g (&rt_sf->uc.tuc_mcontext),
4064 &rt_sf->uc.tuc_regs);
Nathan Froydbcd49332009-05-12 19:13:18 -07004065 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
Aurelien Jarno60e99242010-03-29 02:12:51 +02004066 err |= __put_user(set->sig[i], &rt_sf->uc.tuc_sigmask.sig[i]);
Nathan Froydbcd49332009-05-12 19:13:18 -07004067 }
4068
Aurelien Jarno60e99242010-03-29 02:12:51 +02004069 frame = &rt_sf->uc.tuc_mcontext;
Nathan Froydbcd49332009-05-12 19:13:18 -07004070 err |= save_user_regs(env, frame, TARGET_NR_rt_sigreturn);
4071
4072 /* The kernel checks for the presence of a VDSO here. We don't
4073 emulate a vdso, so use a sigreturn system call. */
4074 env->lr = (target_ulong) h2g(frame->tramp);
4075
4076 /* Turn off all fp exceptions. */
4077 env->fpscr = 0;
4078
4079 /* Create a stack frame for the caller of the handler. */
4080 newsp = rt_sf_addr - (SIGNAL_FRAMESIZE + 16);
4081 err |= __put_user(env->gpr[1], (target_ulong *)(uintptr_t) newsp);
4082
4083 if (err)
4084 goto sigsegv;
4085
4086 /* Set up registers for signal handler. */
4087 env->gpr[1] = newsp;
4088 env->gpr[3] = (target_ulong) signal;
4089 env->gpr[4] = (target_ulong) h2g(&rt_sf->info);
4090 env->gpr[5] = (target_ulong) h2g(&rt_sf->uc);
4091 env->gpr[6] = (target_ulong) h2g(rt_sf);
4092 env->nip = (target_ulong) ka->_sa_handler;
4093 /* Signal handlers are entered in big-endian mode. */
4094 env->msr &= ~MSR_LE;
4095
4096 unlock_user_struct(rt_sf, rt_sf_addr, 1);
4097 return;
4098
4099sigsegv:
4100 unlock_user_struct(rt_sf, rt_sf_addr, 1);
4101 if (logfile)
4102 fprintf (logfile, "segfaulting from setup_rt_frame\n");
Riku Voipio66393fb2009-12-04 15:16:32 +02004103 force_sig(TARGET_SIGSEGV);
Nathan Froydbcd49332009-05-12 19:13:18 -07004104
4105}
4106
4107long do_sigreturn(CPUState *env)
4108{
4109 struct target_sigcontext *sc = NULL;
4110 struct target_mcontext *sr = NULL;
4111 target_ulong sr_addr, sc_addr;
4112 sigset_t blocked;
Anthony Liguoric227f092009-10-01 16:12:16 -05004113 target_sigset_t set;
Nathan Froydbcd49332009-05-12 19:13:18 -07004114
4115 sc_addr = env->gpr[1] + SIGNAL_FRAMESIZE;
4116 if (!lock_user_struct(VERIFY_READ, sc, sc_addr, 1))
4117 goto sigsegv;
4118
4119#if defined(TARGET_PPC64)
4120 set.sig[0] = sc->oldmask + ((long)(sc->_unused[3]) << 32);
4121#else
4122 if(__get_user(set.sig[0], &sc->oldmask) ||
4123 __get_user(set.sig[1], &sc->_unused[3]))
4124 goto sigsegv;
4125#endif
4126 target_to_host_sigset_internal(&blocked, &set);
4127 sigprocmask(SIG_SETMASK, &blocked, NULL);
4128
4129 if (__get_user(sr_addr, &sc->regs))
4130 goto sigsegv;
4131 if (!lock_user_struct(VERIFY_READ, sr, sr_addr, 1))
4132 goto sigsegv;
4133 if (restore_user_regs(env, sr, 1))
4134 goto sigsegv;
4135
4136 unlock_user_struct(sr, sr_addr, 1);
4137 unlock_user_struct(sc, sc_addr, 1);
4138 return -TARGET_QEMU_ESIGRETURN;
4139
4140sigsegv:
4141 unlock_user_struct(sr, sr_addr, 1);
4142 unlock_user_struct(sc, sc_addr, 1);
4143 if (logfile)
4144 fprintf (logfile, "segfaulting from do_sigreturn\n");
Riku Voipio66393fb2009-12-04 15:16:32 +02004145 force_sig(TARGET_SIGSEGV);
Nathan Froydbcd49332009-05-12 19:13:18 -07004146 return 0;
4147}
4148
4149/* See arch/powerpc/kernel/signal_32.c. */
4150static int do_setcontext(struct target_ucontext *ucp, CPUState *env, int sig)
4151{
4152 struct target_mcontext *mcp;
4153 target_ulong mcp_addr;
4154 sigset_t blocked;
Anthony Liguoric227f092009-10-01 16:12:16 -05004155 target_sigset_t set;
Nathan Froydbcd49332009-05-12 19:13:18 -07004156
Aurelien Jarno60e99242010-03-29 02:12:51 +02004157 if (copy_from_user(&set, h2g(ucp) + offsetof(struct target_ucontext, tuc_sigmask),
Nathan Froydbcd49332009-05-12 19:13:18 -07004158 sizeof (set)))
4159 return 1;
4160
4161#if defined(TARGET_PPC64)
4162 fprintf (stderr, "do_setcontext: not implemented\n");
4163 return 0;
4164#else
Aurelien Jarno60e99242010-03-29 02:12:51 +02004165 if (__get_user(mcp_addr, &ucp->tuc_regs))
Nathan Froydbcd49332009-05-12 19:13:18 -07004166 return 1;
4167
4168 if (!lock_user_struct(VERIFY_READ, mcp, mcp_addr, 1))
4169 return 1;
4170
4171 target_to_host_sigset_internal(&blocked, &set);
4172 sigprocmask(SIG_SETMASK, &blocked, NULL);
4173 if (restore_user_regs(env, mcp, sig))
4174 goto sigsegv;
4175
4176 unlock_user_struct(mcp, mcp_addr, 1);
4177 return 0;
4178
4179sigsegv:
4180 unlock_user_struct(mcp, mcp_addr, 1);
4181 return 1;
4182#endif
4183}
4184
4185long do_rt_sigreturn(CPUState *env)
4186{
4187 struct target_rt_sigframe *rt_sf = NULL;
4188 target_ulong rt_sf_addr;
4189
4190 rt_sf_addr = env->gpr[1] + SIGNAL_FRAMESIZE + 16;
4191 if (!lock_user_struct(VERIFY_READ, rt_sf, rt_sf_addr, 1))
4192 goto sigsegv;
4193
4194 if (do_setcontext(&rt_sf->uc, env, 1))
4195 goto sigsegv;
4196
4197 do_sigaltstack(rt_sf_addr
Aurelien Jarno60e99242010-03-29 02:12:51 +02004198 + offsetof(struct target_rt_sigframe, uc.tuc_stack),
Nathan Froydbcd49332009-05-12 19:13:18 -07004199 0, env->gpr[1]);
4200
4201 unlock_user_struct(rt_sf, rt_sf_addr, 1);
4202 return -TARGET_QEMU_ESIGRETURN;
4203
4204sigsegv:
4205 unlock_user_struct(rt_sf, rt_sf_addr, 1);
4206 if (logfile)
4207 fprintf (logfile, "segfaulting from do_rt_sigreturn\n");
Riku Voipio66393fb2009-12-04 15:16:32 +02004208 force_sig(TARGET_SIGSEGV);
Nathan Froydbcd49332009-05-12 19:13:18 -07004209 return 0;
4210}
4211
Laurent Vivier492a8742009-08-03 16:12:17 +02004212#elif defined(TARGET_M68K)
4213
4214struct target_sigcontext {
4215 abi_ulong sc_mask;
4216 abi_ulong sc_usp;
4217 abi_ulong sc_d0;
4218 abi_ulong sc_d1;
4219 abi_ulong sc_a0;
4220 abi_ulong sc_a1;
4221 unsigned short sc_sr;
4222 abi_ulong sc_pc;
4223};
4224
4225struct target_sigframe
4226{
4227 abi_ulong pretcode;
4228 int sig;
4229 int code;
4230 abi_ulong psc;
4231 char retcode[8];
4232 abi_ulong extramask[TARGET_NSIG_WORDS-1];
4233 struct target_sigcontext sc;
4234};
Laurent Vivier71811552009-08-03 16:12:18 +02004235
Anthony Liguoric227f092009-10-01 16:12:16 -05004236typedef int target_greg_t;
Laurent Vivier71811552009-08-03 16:12:18 +02004237#define TARGET_NGREG 18
Anthony Liguoric227f092009-10-01 16:12:16 -05004238typedef target_greg_t target_gregset_t[TARGET_NGREG];
Laurent Vivier71811552009-08-03 16:12:18 +02004239
4240typedef struct target_fpregset {
4241 int f_fpcntl[3];
4242 int f_fpregs[8*3];
Anthony Liguoric227f092009-10-01 16:12:16 -05004243} target_fpregset_t;
Laurent Vivier71811552009-08-03 16:12:18 +02004244
4245struct target_mcontext {
4246 int version;
Anthony Liguoric227f092009-10-01 16:12:16 -05004247 target_gregset_t gregs;
4248 target_fpregset_t fpregs;
Laurent Vivier71811552009-08-03 16:12:18 +02004249};
4250
4251#define TARGET_MCONTEXT_VERSION 2
4252
4253struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02004254 abi_ulong tuc_flags;
4255 abi_ulong tuc_link;
4256 target_stack_t tuc_stack;
4257 struct target_mcontext tuc_mcontext;
4258 abi_long tuc_filler[80];
4259 target_sigset_t tuc_sigmask;
Laurent Vivier71811552009-08-03 16:12:18 +02004260};
4261
4262struct target_rt_sigframe
4263{
4264 abi_ulong pretcode;
4265 int sig;
4266 abi_ulong pinfo;
4267 abi_ulong puc;
4268 char retcode[8];
4269 struct target_siginfo info;
4270 struct target_ucontext uc;
4271};
Laurent Vivier492a8742009-08-03 16:12:17 +02004272
4273static int
4274setup_sigcontext(struct target_sigcontext *sc, CPUState *env, abi_ulong mask)
4275{
4276 int err = 0;
4277
4278 err |= __put_user(mask, &sc->sc_mask);
4279 err |= __put_user(env->aregs[7], &sc->sc_usp);
4280 err |= __put_user(env->dregs[0], &sc->sc_d0);
4281 err |= __put_user(env->dregs[1], &sc->sc_d1);
4282 err |= __put_user(env->aregs[0], &sc->sc_a0);
4283 err |= __put_user(env->aregs[1], &sc->sc_a1);
4284 err |= __put_user(env->sr, &sc->sc_sr);
4285 err |= __put_user(env->pc, &sc->sc_pc);
4286
4287 return err;
4288}
4289
4290static int
4291restore_sigcontext(CPUState *env, struct target_sigcontext *sc, int *pd0)
4292{
4293 int err = 0;
4294 int temp;
4295
4296 err |= __get_user(env->aregs[7], &sc->sc_usp);
4297 err |= __get_user(env->dregs[1], &sc->sc_d1);
4298 err |= __get_user(env->aregs[0], &sc->sc_a0);
4299 err |= __get_user(env->aregs[1], &sc->sc_a1);
4300 err |= __get_user(env->pc, &sc->sc_pc);
4301 err |= __get_user(temp, &sc->sc_sr);
4302 env->sr = (env->sr & 0xff00) | (temp & 0xff);
4303
4304 *pd0 = tswapl(sc->sc_d0);
4305
4306 return err;
4307}
4308
4309/*
4310 * Determine which stack to use..
4311 */
4312static inline abi_ulong
4313get_sigframe(struct target_sigaction *ka, CPUState *regs, size_t frame_size)
4314{
4315 unsigned long sp;
4316
4317 sp = regs->aregs[7];
4318
4319 /* This is the X/Open sanctioned signal stack switching. */
4320 if ((ka->sa_flags & TARGET_SA_ONSTACK) && (sas_ss_flags (sp) == 0)) {
4321 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
4322 }
4323
4324 return ((sp - frame_size) & -8UL);
4325}
4326
4327static void setup_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05004328 target_sigset_t *set, CPUState *env)
Laurent Vivier492a8742009-08-03 16:12:17 +02004329{
4330 struct target_sigframe *frame;
4331 abi_ulong frame_addr;
4332 abi_ulong retcode_addr;
4333 abi_ulong sc_addr;
4334 int err = 0;
4335 int i;
4336
4337 frame_addr = get_sigframe(ka, env, sizeof *frame);
4338 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
4339 goto give_sigsegv;
4340
4341 err |= __put_user(sig, &frame->sig);
4342
4343 sc_addr = frame_addr + offsetof(struct target_sigframe, sc);
4344 err |= __put_user(sc_addr, &frame->psc);
4345
4346 err |= setup_sigcontext(&frame->sc, env, set->sig[0]);
4347 if (err)
4348 goto give_sigsegv;
4349
4350 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
4351 if (__put_user(set->sig[i], &frame->extramask[i - 1]))
4352 goto give_sigsegv;
4353 }
4354
4355 /* Set up to return from userspace. */
4356
4357 retcode_addr = frame_addr + offsetof(struct target_sigframe, retcode);
4358 err |= __put_user(retcode_addr, &frame->pretcode);
4359
4360 /* moveq #,d0; trap #0 */
4361
4362 err |= __put_user(0x70004e40 + (TARGET_NR_sigreturn << 16),
4363 (long *)(frame->retcode));
4364
4365 if (err)
4366 goto give_sigsegv;
4367
4368 /* Set up to return from userspace */
4369
4370 env->aregs[7] = frame_addr;
4371 env->pc = ka->_sa_handler;
4372
4373 unlock_user_struct(frame, frame_addr, 1);
4374 return;
4375
4376give_sigsegv:
4377 unlock_user_struct(frame, frame_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02004378 force_sig(TARGET_SIGSEGV);
Laurent Vivier492a8742009-08-03 16:12:17 +02004379}
4380
Laurent Vivier71811552009-08-03 16:12:18 +02004381static inline int target_rt_setup_ucontext(struct target_ucontext *uc,
4382 CPUState *env)
4383{
Aurelien Jarno60e99242010-03-29 02:12:51 +02004384 target_greg_t *gregs = uc->tuc_mcontext.gregs;
Laurent Vivier71811552009-08-03 16:12:18 +02004385 int err;
4386
Aurelien Jarno60e99242010-03-29 02:12:51 +02004387 err = __put_user(TARGET_MCONTEXT_VERSION, &uc->tuc_mcontext.version);
Laurent Vivier71811552009-08-03 16:12:18 +02004388 err |= __put_user(env->dregs[0], &gregs[0]);
4389 err |= __put_user(env->dregs[1], &gregs[1]);
4390 err |= __put_user(env->dregs[2], &gregs[2]);
4391 err |= __put_user(env->dregs[3], &gregs[3]);
4392 err |= __put_user(env->dregs[4], &gregs[4]);
4393 err |= __put_user(env->dregs[5], &gregs[5]);
4394 err |= __put_user(env->dregs[6], &gregs[6]);
4395 err |= __put_user(env->dregs[7], &gregs[7]);
4396 err |= __put_user(env->aregs[0], &gregs[8]);
4397 err |= __put_user(env->aregs[1], &gregs[9]);
4398 err |= __put_user(env->aregs[2], &gregs[10]);
4399 err |= __put_user(env->aregs[3], &gregs[11]);
4400 err |= __put_user(env->aregs[4], &gregs[12]);
4401 err |= __put_user(env->aregs[5], &gregs[13]);
4402 err |= __put_user(env->aregs[6], &gregs[14]);
4403 err |= __put_user(env->aregs[7], &gregs[15]);
4404 err |= __put_user(env->pc, &gregs[16]);
4405 err |= __put_user(env->sr, &gregs[17]);
4406
4407 return err;
4408}
4409
4410static inline int target_rt_restore_ucontext(CPUState *env,
4411 struct target_ucontext *uc,
4412 int *pd0)
4413{
4414 int temp;
4415 int err;
Aurelien Jarno60e99242010-03-29 02:12:51 +02004416 target_greg_t *gregs = uc->tuc_mcontext.gregs;
Laurent Vivier71811552009-08-03 16:12:18 +02004417
Aurelien Jarno60e99242010-03-29 02:12:51 +02004418 err = __get_user(temp, &uc->tuc_mcontext.version);
Laurent Vivier71811552009-08-03 16:12:18 +02004419 if (temp != TARGET_MCONTEXT_VERSION)
4420 goto badframe;
4421
4422 /* restore passed registers */
4423 err |= __get_user(env->dregs[0], &gregs[0]);
4424 err |= __get_user(env->dregs[1], &gregs[1]);
4425 err |= __get_user(env->dregs[2], &gregs[2]);
4426 err |= __get_user(env->dregs[3], &gregs[3]);
4427 err |= __get_user(env->dregs[4], &gregs[4]);
4428 err |= __get_user(env->dregs[5], &gregs[5]);
4429 err |= __get_user(env->dregs[6], &gregs[6]);
4430 err |= __get_user(env->dregs[7], &gregs[7]);
4431 err |= __get_user(env->aregs[0], &gregs[8]);
4432 err |= __get_user(env->aregs[1], &gregs[9]);
4433 err |= __get_user(env->aregs[2], &gregs[10]);
4434 err |= __get_user(env->aregs[3], &gregs[11]);
4435 err |= __get_user(env->aregs[4], &gregs[12]);
4436 err |= __get_user(env->aregs[5], &gregs[13]);
4437 err |= __get_user(env->aregs[6], &gregs[14]);
4438 err |= __get_user(env->aregs[7], &gregs[15]);
4439 err |= __get_user(env->pc, &gregs[16]);
4440 err |= __get_user(temp, &gregs[17]);
4441 env->sr = (env->sr & 0xff00) | (temp & 0xff);
4442
4443 *pd0 = env->dregs[0];
4444 return err;
4445
4446badframe:
4447 return 1;
4448}
4449
Laurent Vivier492a8742009-08-03 16:12:17 +02004450static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05004451 target_siginfo_t *info,
4452 target_sigset_t *set, CPUState *env)
Laurent Vivier492a8742009-08-03 16:12:17 +02004453{
Laurent Vivier71811552009-08-03 16:12:18 +02004454 struct target_rt_sigframe *frame;
4455 abi_ulong frame_addr;
4456 abi_ulong retcode_addr;
4457 abi_ulong info_addr;
4458 abi_ulong uc_addr;
4459 int err = 0;
4460 int i;
4461
4462 frame_addr = get_sigframe(ka, env, sizeof *frame);
4463 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
4464 goto give_sigsegv;
4465
4466 err |= __put_user(sig, &frame->sig);
4467
4468 info_addr = frame_addr + offsetof(struct target_rt_sigframe, info);
4469 err |= __put_user(info_addr, &frame->pinfo);
4470
4471 uc_addr = frame_addr + offsetof(struct target_rt_sigframe, uc);
4472 err |= __put_user(uc_addr, &frame->puc);
4473
4474 err |= copy_siginfo_to_user(&frame->info, info);
4475
4476 /* Create the ucontext */
4477
Aurelien Jarno60e99242010-03-29 02:12:51 +02004478 err |= __put_user(0, &frame->uc.tuc_flags);
4479 err |= __put_user(0, &frame->uc.tuc_link);
Laurent Vivier71811552009-08-03 16:12:18 +02004480 err |= __put_user(target_sigaltstack_used.ss_sp,
Aurelien Jarno60e99242010-03-29 02:12:51 +02004481 &frame->uc.tuc_stack.ss_sp);
Laurent Vivier71811552009-08-03 16:12:18 +02004482 err |= __put_user(sas_ss_flags(env->aregs[7]),
Aurelien Jarno60e99242010-03-29 02:12:51 +02004483 &frame->uc.tuc_stack.ss_flags);
Laurent Vivier71811552009-08-03 16:12:18 +02004484 err |= __put_user(target_sigaltstack_used.ss_size,
Aurelien Jarno60e99242010-03-29 02:12:51 +02004485 &frame->uc.tuc_stack.ss_size);
Laurent Vivier71811552009-08-03 16:12:18 +02004486 err |= target_rt_setup_ucontext(&frame->uc, env);
4487
4488 if (err)
4489 goto give_sigsegv;
4490
4491 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
Aurelien Jarno60e99242010-03-29 02:12:51 +02004492 if (__put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]))
Laurent Vivier71811552009-08-03 16:12:18 +02004493 goto give_sigsegv;
4494 }
4495
4496 /* Set up to return from userspace. */
4497
4498 retcode_addr = frame_addr + offsetof(struct target_sigframe, retcode);
4499 err |= __put_user(retcode_addr, &frame->pretcode);
4500
4501 /* moveq #,d0; notb d0; trap #0 */
4502
4503 err |= __put_user(0x70004600 + ((TARGET_NR_rt_sigreturn ^ 0xff) << 16),
4504 (long *)(frame->retcode + 0));
4505 err |= __put_user(0x4e40, (short *)(frame->retcode + 4));
4506
4507 if (err)
4508 goto give_sigsegv;
4509
4510 /* Set up to return from userspace */
4511
4512 env->aregs[7] = frame_addr;
4513 env->pc = ka->_sa_handler;
4514
4515 unlock_user_struct(frame, frame_addr, 1);
4516 return;
4517
4518give_sigsegv:
4519 unlock_user_struct(frame, frame_addr, 1);
Riku Voipio66393fb2009-12-04 15:16:32 +02004520 force_sig(TARGET_SIGSEGV);
Laurent Vivier492a8742009-08-03 16:12:17 +02004521}
4522
4523long do_sigreturn(CPUState *env)
4524{
4525 struct target_sigframe *frame;
4526 abi_ulong frame_addr = env->aregs[7] - 4;
Anthony Liguoric227f092009-10-01 16:12:16 -05004527 target_sigset_t target_set;
Laurent Vivier492a8742009-08-03 16:12:17 +02004528 sigset_t set;
4529 int d0, i;
4530
4531 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
4532 goto badframe;
4533
4534 /* set blocked signals */
4535
4536 if (__get_user(target_set.sig[0], &frame->sc.sc_mask))
4537 goto badframe;
4538
4539 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
4540 if (__get_user(target_set.sig[i], &frame->extramask[i - 1]))
4541 goto badframe;
4542 }
4543
4544 target_to_host_sigset_internal(&set, &target_set);
4545 sigprocmask(SIG_SETMASK, &set, NULL);
4546
4547 /* restore registers */
4548
4549 if (restore_sigcontext(env, &frame->sc, &d0))
4550 goto badframe;
4551
4552 unlock_user_struct(frame, frame_addr, 0);
4553 return d0;
4554
4555badframe:
4556 unlock_user_struct(frame, frame_addr, 0);
4557 force_sig(TARGET_SIGSEGV);
4558 return 0;
4559}
4560
4561long do_rt_sigreturn(CPUState *env)
4562{
Laurent Vivier71811552009-08-03 16:12:18 +02004563 struct target_rt_sigframe *frame;
4564 abi_ulong frame_addr = env->aregs[7] - 4;
Anthony Liguoric227f092009-10-01 16:12:16 -05004565 target_sigset_t target_set;
Laurent Vivier71811552009-08-03 16:12:18 +02004566 sigset_t set;
4567 int d0;
4568
4569 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
4570 goto badframe;
4571
4572 target_to_host_sigset_internal(&set, &target_set);
4573 sigprocmask(SIG_SETMASK, &set, NULL);
4574
4575 /* restore registers */
4576
4577 if (target_rt_restore_ucontext(env, &frame->uc, &d0))
4578 goto badframe;
4579
4580 if (do_sigaltstack(frame_addr +
Aurelien Jarno60e99242010-03-29 02:12:51 +02004581 offsetof(struct target_rt_sigframe, uc.tuc_stack),
Laurent Vivier71811552009-08-03 16:12:18 +02004582 0, get_sp_from_cpustate(env)) == -EFAULT)
4583 goto badframe;
4584
4585 unlock_user_struct(frame, frame_addr, 0);
4586 return d0;
4587
4588badframe:
4589 unlock_user_struct(frame, frame_addr, 0);
4590 force_sig(TARGET_SIGSEGV);
4591 return 0;
Laurent Vivier492a8742009-08-03 16:12:17 +02004592}
4593
Richard Henderson6049f4f2009-12-27 18:30:03 -08004594#elif defined(TARGET_ALPHA)
4595
4596struct target_sigcontext {
4597 abi_long sc_onstack;
4598 abi_long sc_mask;
4599 abi_long sc_pc;
4600 abi_long sc_ps;
4601 abi_long sc_regs[32];
4602 abi_long sc_ownedfp;
4603 abi_long sc_fpregs[32];
4604 abi_ulong sc_fpcr;
4605 abi_ulong sc_fp_control;
4606 abi_ulong sc_reserved1;
4607 abi_ulong sc_reserved2;
4608 abi_ulong sc_ssize;
4609 abi_ulong sc_sbase;
4610 abi_ulong sc_traparg_a0;
4611 abi_ulong sc_traparg_a1;
4612 abi_ulong sc_traparg_a2;
4613 abi_ulong sc_fp_trap_pc;
4614 abi_ulong sc_fp_trigger_sum;
4615 abi_ulong sc_fp_trigger_inst;
4616};
4617
4618struct target_ucontext {
Aurelien Jarno60e99242010-03-29 02:12:51 +02004619 abi_ulong tuc_flags;
4620 abi_ulong tuc_link;
4621 abi_ulong tuc_osf_sigmask;
4622 target_stack_t tuc_stack;
4623 struct target_sigcontext tuc_mcontext;
4624 target_sigset_t tuc_sigmask;
Richard Henderson6049f4f2009-12-27 18:30:03 -08004625};
4626
4627struct target_sigframe {
4628 struct target_sigcontext sc;
4629 unsigned int retcode[3];
4630};
4631
4632struct target_rt_sigframe {
4633 target_siginfo_t info;
4634 struct target_ucontext uc;
4635 unsigned int retcode[3];
4636};
4637
4638#define INSN_MOV_R30_R16 0x47fe0410
4639#define INSN_LDI_R0 0x201f0000
4640#define INSN_CALLSYS 0x00000083
4641
4642static int setup_sigcontext(struct target_sigcontext *sc, CPUState *env,
4643 abi_ulong frame_addr, target_sigset_t *set)
4644{
4645 int i, err = 0;
4646
4647 err |= __put_user(on_sig_stack(frame_addr), &sc->sc_onstack);
4648 err |= __put_user(set->sig[0], &sc->sc_mask);
4649 err |= __put_user(env->pc, &sc->sc_pc);
4650 err |= __put_user(8, &sc->sc_ps);
4651
4652 for (i = 0; i < 31; ++i) {
4653 err |= __put_user(env->ir[i], &sc->sc_regs[i]);
4654 }
4655 err |= __put_user(0, &sc->sc_regs[31]);
4656
4657 for (i = 0; i < 31; ++i) {
4658 err |= __put_user(env->fir[i], &sc->sc_fpregs[i]);
4659 }
4660 err |= __put_user(0, &sc->sc_fpregs[31]);
4661 err |= __put_user(cpu_alpha_load_fpcr(env), &sc->sc_fpcr);
4662
4663 err |= __put_user(0, &sc->sc_traparg_a0); /* FIXME */
4664 err |= __put_user(0, &sc->sc_traparg_a1); /* FIXME */
4665 err |= __put_user(0, &sc->sc_traparg_a2); /* FIXME */
4666
4667 return err;
4668}
4669
4670static int restore_sigcontext(CPUState *env, struct target_sigcontext *sc)
4671{
4672 uint64_t fpcr;
4673 int i, err = 0;
4674
4675 err |= __get_user(env->pc, &sc->sc_pc);
4676
4677 for (i = 0; i < 31; ++i) {
4678 err |= __get_user(env->ir[i], &sc->sc_regs[i]);
4679 }
4680 for (i = 0; i < 31; ++i) {
4681 err |= __get_user(env->fir[i], &sc->sc_fpregs[i]);
4682 }
4683
4684 err |= __get_user(fpcr, &sc->sc_fpcr);
4685 cpu_alpha_store_fpcr(env, fpcr);
4686
4687 return err;
4688}
4689
4690static inline abi_ulong get_sigframe(struct target_sigaction *sa,
4691 CPUState *env, unsigned long framesize)
4692{
4693 abi_ulong sp = env->ir[IR_SP];
4694
4695 /* This is the X/Open sanctioned signal stack switching. */
4696 if ((sa->sa_flags & TARGET_SA_ONSTACK) != 0 && !sas_ss_flags(sp)) {
4697 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
4698 }
4699 return (sp - framesize) & -32;
4700}
4701
4702static void setup_frame(int sig, struct target_sigaction *ka,
4703 target_sigset_t *set, CPUState *env)
4704{
4705 abi_ulong frame_addr, r26;
4706 struct target_sigframe *frame;
4707 int err = 0;
4708
4709 frame_addr = get_sigframe(ka, env, sizeof(*frame));
4710 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
4711 goto give_sigsegv;
4712 }
4713
4714 err |= setup_sigcontext(&frame->sc, env, frame_addr, set);
4715
4716 if (ka->sa_restorer) {
4717 r26 = ka->sa_restorer;
4718 } else {
4719 err |= __put_user(INSN_MOV_R30_R16, &frame->retcode[0]);
4720 err |= __put_user(INSN_LDI_R0 + TARGET_NR_sigreturn,
4721 &frame->retcode[1]);
4722 err |= __put_user(INSN_CALLSYS, &frame->retcode[2]);
4723 /* imb() */
4724 r26 = frame_addr;
4725 }
4726
4727 unlock_user_struct(frame, frame_addr, 1);
4728
4729 if (err) {
4730 give_sigsegv:
4731 if (sig == TARGET_SIGSEGV) {
4732 ka->_sa_handler = TARGET_SIG_DFL;
4733 }
4734 force_sig(TARGET_SIGSEGV);
4735 }
4736
4737 env->ir[IR_RA] = r26;
4738 env->ir[IR_PV] = env->pc = ka->_sa_handler;
4739 env->ir[IR_A0] = sig;
4740 env->ir[IR_A1] = 0;
4741 env->ir[IR_A2] = frame_addr + offsetof(struct target_sigframe, sc);
4742 env->ir[IR_SP] = frame_addr;
4743}
4744
4745static void setup_rt_frame(int sig, struct target_sigaction *ka,
4746 target_siginfo_t *info,
4747 target_sigset_t *set, CPUState *env)
4748{
4749 abi_ulong frame_addr, r26;
4750 struct target_rt_sigframe *frame;
4751 int i, err = 0;
4752
4753 frame_addr = get_sigframe(ka, env, sizeof(*frame));
4754 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
4755 goto give_sigsegv;
4756 }
4757
4758 err |= copy_siginfo_to_user(&frame->info, info);
4759
Aurelien Jarno60e99242010-03-29 02:12:51 +02004760 err |= __put_user(0, &frame->uc.tuc_flags);
4761 err |= __put_user(0, &frame->uc.tuc_link);
4762 err |= __put_user(set->sig[0], &frame->uc.tuc_osf_sigmask);
Richard Henderson6049f4f2009-12-27 18:30:03 -08004763 err |= __put_user(target_sigaltstack_used.ss_sp,
Aurelien Jarno60e99242010-03-29 02:12:51 +02004764 &frame->uc.tuc_stack.ss_sp);
Richard Henderson6049f4f2009-12-27 18:30:03 -08004765 err |= __put_user(sas_ss_flags(env->ir[IR_SP]),
Aurelien Jarno60e99242010-03-29 02:12:51 +02004766 &frame->uc.tuc_stack.ss_flags);
Richard Henderson6049f4f2009-12-27 18:30:03 -08004767 err |= __put_user(target_sigaltstack_used.ss_size,
Aurelien Jarno60e99242010-03-29 02:12:51 +02004768 &frame->uc.tuc_stack.ss_size);
4769 err |= setup_sigcontext(&frame->uc.tuc_mcontext, env, frame_addr, set);
Richard Henderson6049f4f2009-12-27 18:30:03 -08004770 for (i = 0; i < TARGET_NSIG_WORDS; ++i) {
Aurelien Jarno60e99242010-03-29 02:12:51 +02004771 err |= __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
Richard Henderson6049f4f2009-12-27 18:30:03 -08004772 }
4773
4774 if (ka->sa_restorer) {
4775 r26 = ka->sa_restorer;
4776 } else {
4777 err |= __put_user(INSN_MOV_R30_R16, &frame->retcode[0]);
4778 err |= __put_user(INSN_LDI_R0 + TARGET_NR_rt_sigreturn,
4779 &frame->retcode[1]);
4780 err |= __put_user(INSN_CALLSYS, &frame->retcode[2]);
4781 /* imb(); */
4782 r26 = frame_addr;
4783 }
4784
4785 if (err) {
4786 give_sigsegv:
4787 if (sig == TARGET_SIGSEGV) {
4788 ka->_sa_handler = TARGET_SIG_DFL;
4789 }
4790 force_sig(TARGET_SIGSEGV);
4791 }
4792
4793 env->ir[IR_RA] = r26;
4794 env->ir[IR_PV] = env->pc = ka->_sa_handler;
4795 env->ir[IR_A0] = sig;
4796 env->ir[IR_A1] = frame_addr + offsetof(struct target_rt_sigframe, info);
4797 env->ir[IR_A2] = frame_addr + offsetof(struct target_rt_sigframe, uc);
4798 env->ir[IR_SP] = frame_addr;
4799}
4800
4801long do_sigreturn(CPUState *env)
4802{
4803 struct target_sigcontext *sc;
4804 abi_ulong sc_addr = env->ir[IR_A0];
4805 target_sigset_t target_set;
4806 sigset_t set;
4807
4808 if (!lock_user_struct(VERIFY_READ, sc, sc_addr, 1)) {
4809 goto badframe;
4810 }
4811
4812 target_sigemptyset(&target_set);
4813 if (__get_user(target_set.sig[0], &sc->sc_mask)) {
4814 goto badframe;
4815 }
4816
4817 target_to_host_sigset_internal(&set, &target_set);
4818 sigprocmask(SIG_SETMASK, &set, NULL);
4819
4820 if (restore_sigcontext(env, sc)) {
4821 goto badframe;
4822 }
4823 unlock_user_struct(sc, sc_addr, 0);
4824 return env->ir[IR_V0];
4825
4826 badframe:
4827 unlock_user_struct(sc, sc_addr, 0);
4828 force_sig(TARGET_SIGSEGV);
4829}
4830
4831long do_rt_sigreturn(CPUState *env)
4832{
4833 abi_ulong frame_addr = env->ir[IR_A0];
4834 struct target_rt_sigframe *frame;
4835 sigset_t set;
4836
4837 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
4838 goto badframe;
4839 }
Aurelien Jarno60e99242010-03-29 02:12:51 +02004840 target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
Richard Henderson6049f4f2009-12-27 18:30:03 -08004841 sigprocmask(SIG_SETMASK, &set, NULL);
4842
Aurelien Jarno60e99242010-03-29 02:12:51 +02004843 if (restore_sigcontext(env, &frame->uc.tuc_mcontext)) {
Richard Henderson6049f4f2009-12-27 18:30:03 -08004844 goto badframe;
4845 }
4846 if (do_sigaltstack(frame_addr + offsetof(struct target_rt_sigframe,
Aurelien Jarno60e99242010-03-29 02:12:51 +02004847 uc.tuc_stack),
Richard Henderson6049f4f2009-12-27 18:30:03 -08004848 0, env->ir[IR_SP]) == -EFAULT) {
4849 goto badframe;
4850 }
4851
4852 unlock_user_struct(frame, frame_addr, 0);
4853 return env->ir[IR_V0];
4854
4855
4856 badframe:
4857 unlock_user_struct(frame, frame_addr, 0);
4858 force_sig(TARGET_SIGSEGV);
4859}
4860
bellardb346ff42003-06-15 20:05:50 +00004861#else
4862
pbrook624f7972008-05-31 16:11:38 +00004863static void setup_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05004864 target_sigset_t *set, CPUState *env)
bellardb346ff42003-06-15 20:05:50 +00004865{
4866 fprintf(stderr, "setup_frame: not implemented\n");
4867}
4868
pbrook624f7972008-05-31 16:11:38 +00004869static void setup_rt_frame(int sig, struct target_sigaction *ka,
Anthony Liguoric227f092009-10-01 16:12:16 -05004870 target_siginfo_t *info,
4871 target_sigset_t *set, CPUState *env)
bellardb346ff42003-06-15 20:05:50 +00004872{
4873 fprintf(stderr, "setup_rt_frame: not implemented\n");
4874}
4875
4876long do_sigreturn(CPUState *env)
4877{
4878 fprintf(stderr, "do_sigreturn: not implemented\n");
bellardf8b0aa22007-11-11 23:03:42 +00004879 return -TARGET_ENOSYS;
bellardb346ff42003-06-15 20:05:50 +00004880}
4881
4882long do_rt_sigreturn(CPUState *env)
4883{
4884 fprintf(stderr, "do_rt_sigreturn: not implemented\n");
bellardf8b0aa22007-11-11 23:03:42 +00004885 return -TARGET_ENOSYS;
bellardb346ff42003-06-15 20:05:50 +00004886}
4887
bellard66fb9762003-03-23 01:06:05 +00004888#endif
4889
pbrook624f7972008-05-31 16:11:38 +00004890void process_pending_signals(CPUState *cpu_env)
bellard66fb9762003-03-23 01:06:05 +00004891{
4892 int sig;
blueswir1992f48a2007-10-14 16:27:31 +00004893 abi_ulong handler;
bellard9de5e442003-03-23 16:49:39 +00004894 sigset_t set, old_set;
Anthony Liguoric227f092009-10-01 16:12:16 -05004895 target_sigset_t target_old_set;
pbrook624f7972008-05-31 16:11:38 +00004896 struct emulated_sigtable *k;
4897 struct target_sigaction *sa;
bellard66fb9762003-03-23 01:06:05 +00004898 struct sigqueue *q;
pbrook624f7972008-05-31 16:11:38 +00004899 TaskState *ts = cpu_env->opaque;
ths3b46e622007-09-17 08:09:54 +00004900
pbrook624f7972008-05-31 16:11:38 +00004901 if (!ts->signal_pending)
bellard31e31b82003-02-18 22:55:36 +00004902 return;
4903
pbrook624f7972008-05-31 16:11:38 +00004904 /* FIXME: This is not threadsafe. */
4905 k = ts->sigtab;
bellard66fb9762003-03-23 01:06:05 +00004906 for(sig = 1; sig <= TARGET_NSIG; sig++) {
4907 if (k->pending)
bellard31e31b82003-02-18 22:55:36 +00004908 goto handle_signal;
bellard66fb9762003-03-23 01:06:05 +00004909 k++;
bellard31e31b82003-02-18 22:55:36 +00004910 }
4911 /* if no signal is pending, just return */
pbrook624f7972008-05-31 16:11:38 +00004912 ts->signal_pending = 0;
bellard31e31b82003-02-18 22:55:36 +00004913 return;
bellard66fb9762003-03-23 01:06:05 +00004914
bellard31e31b82003-02-18 22:55:36 +00004915 handle_signal:
bellard66fb9762003-03-23 01:06:05 +00004916#ifdef DEBUG_SIGNAL
bellardbc8a22c2003-03-30 21:02:40 +00004917 fprintf(stderr, "qemu: process signal %d\n", sig);
bellard66fb9762003-03-23 01:06:05 +00004918#endif
4919 /* dequeue signal */
4920 q = k->first;
4921 k->first = q->next;
4922 if (!k->first)
4923 k->pending = 0;
ths3b46e622007-09-17 08:09:54 +00004924
bellard1fddef42005-04-17 19:16:13 +00004925 sig = gdb_handlesig (cpu_env, sig);
4926 if (!sig) {
aurel32ca587a82008-12-18 22:44:13 +00004927 sa = NULL;
4928 handler = TARGET_SIG_IGN;
4929 } else {
4930 sa = &sigact_table[sig - 1];
4931 handler = sa->_sa_handler;
bellard1fddef42005-04-17 19:16:13 +00004932 }
bellard66fb9762003-03-23 01:06:05 +00004933
bellard66fb9762003-03-23 01:06:05 +00004934 if (handler == TARGET_SIG_DFL) {
aurel32ca587a82008-12-18 22:44:13 +00004935 /* default handler : ignore some signal. The other are job control or fatal */
4936 if (sig == TARGET_SIGTSTP || sig == TARGET_SIGTTIN || sig == TARGET_SIGTTOU) {
4937 kill(getpid(),SIGSTOP);
4938 } else if (sig != TARGET_SIGCHLD &&
4939 sig != TARGET_SIGURG &&
4940 sig != TARGET_SIGWINCH &&
4941 sig != TARGET_SIGCONT) {
bellard66fb9762003-03-23 01:06:05 +00004942 force_sig(sig);
4943 }
4944 } else if (handler == TARGET_SIG_IGN) {
4945 /* ignore sig */
4946 } else if (handler == TARGET_SIG_ERR) {
4947 force_sig(sig);
4948 } else {
bellard9de5e442003-03-23 16:49:39 +00004949 /* compute the blocked signals during the handler execution */
pbrook624f7972008-05-31 16:11:38 +00004950 target_to_host_sigset(&set, &sa->sa_mask);
bellard9de5e442003-03-23 16:49:39 +00004951 /* SA_NODEFER indicates that the current signal should not be
4952 blocked during the handler */
pbrook624f7972008-05-31 16:11:38 +00004953 if (!(sa->sa_flags & TARGET_SA_NODEFER))
bellard9de5e442003-03-23 16:49:39 +00004954 sigaddset(&set, target_to_host_signal(sig));
ths3b46e622007-09-17 08:09:54 +00004955
bellard9de5e442003-03-23 16:49:39 +00004956 /* block signals in the handler using Linux */
4957 sigprocmask(SIG_BLOCK, &set, &old_set);
4958 /* save the previous blocked signal state to restore it at the
4959 end of the signal execution (see do_sigreturn) */
bellard92319442004-06-19 16:58:13 +00004960 host_to_target_sigset_internal(&target_old_set, &old_set);
bellard9de5e442003-03-23 16:49:39 +00004961
bellardbc8a22c2003-03-30 21:02:40 +00004962 /* if the CPU is in VM86 mode, we restore the 32 bit values */
j_mayer84409dd2007-04-06 08:56:50 +00004963#if defined(TARGET_I386) && !defined(TARGET_X86_64)
bellardbc8a22c2003-03-30 21:02:40 +00004964 {
4965 CPUX86State *env = cpu_env;
4966 if (env->eflags & VM_MASK)
4967 save_v86_state(env);
4968 }
4969#endif
bellard9de5e442003-03-23 16:49:39 +00004970 /* prepare the stack frame of the virtual CPU */
pbrook624f7972008-05-31 16:11:38 +00004971 if (sa->sa_flags & TARGET_SA_SIGINFO)
4972 setup_rt_frame(sig, sa, &q->info, &target_old_set, cpu_env);
bellard66fb9762003-03-23 01:06:05 +00004973 else
pbrook624f7972008-05-31 16:11:38 +00004974 setup_frame(sig, sa, &target_old_set, cpu_env);
4975 if (sa->sa_flags & TARGET_SA_RESETHAND)
4976 sa->_sa_handler = TARGET_SIG_DFL;
bellard31e31b82003-02-18 22:55:36 +00004977 }
bellard66fb9762003-03-23 01:06:05 +00004978 if (q != &k->info)
pbrook624f7972008-05-31 16:11:38 +00004979 free_sigqueue(cpu_env, q);
bellard31e31b82003-02-18 22:55:36 +00004980}