blob: eb00532311153d28d45fb3d8473085460a5d3ab2 [file] [log] [blame]
Peter Maydellda30d852011-12-05 19:42:18 +00001/*
2 * Emulation of Linux signals : m68k specific code
3 *
4 * 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
17 * along with this program; if not, see <http://www.gnu.org/licenses/>.
18 */
19#include <stdlib.h>
20#include <stdio.h>
21#include <string.h>
22#include <stdarg.h>
23#include <unistd.h>
24#include <errno.h>
25#include <assert.h>
26#include <sys/ucontext.h>
27#include <sys/resource.h>
28
29#include "qemu.h"
30#include "qemu-common.h"
31#include "signal-common.h"
32#include "target_signal.h"
33
34struct target_sigcontext {
35 abi_ulong sc_mask;
36 abi_ulong sc_usp;
37 abi_ulong sc_d0;
38 abi_ulong sc_d1;
39 abi_ulong sc_a0;
40 abi_ulong sc_a1;
41 unsigned short sc_sr;
42 abi_ulong sc_pc;
43};
44
45struct target_sigframe
46{
47 abi_ulong pretcode;
48 int sig;
49 int code;
50 abi_ulong psc;
51 char retcode[8];
52 abi_ulong extramask[TARGET_NSIG_WORDS-1];
53 struct target_sigcontext sc;
54};
55
56typedef int target_greg_t;
57#define TARGET_NGREG 18
58typedef target_greg_t target_gregset_t[TARGET_NGREG];
59
60typedef struct target_fpregset {
61 int f_fpcntl[3];
62 int f_fpregs[8*3];
63} target_fpregset_t;
64
65struct target_mcontext {
66 int version;
67 target_gregset_t gregs;
68 target_fpregset_t fpregs;
69};
70
71#define TARGET_MCONTEXT_VERSION 2
72
73struct target_ucontext {
74 abi_ulong tuc_flags;
75 abi_ulong tuc_link;
76 target_stack_t tuc_stack;
77 struct target_mcontext tuc_mcontext;
78 abi_long tuc_filler[80];
79 target_sigset_t tuc_sigmask;
80};
81
82struct target_rt_sigframe
83{
84 abi_ulong pretcode;
85 int sig;
86 abi_ulong pinfo;
87 abi_ulong puc;
88 char retcode[8];
89 struct target_siginfo info;
90 struct target_ucontext uc;
91};
92
93static int
94setup_sigcontext(struct target_sigcontext *sc, CPUState *env, abi_ulong mask)
95{
96 int err = 0;
97
98 err |= __put_user(mask, &sc->sc_mask);
99 err |= __put_user(env->aregs[7], &sc->sc_usp);
100 err |= __put_user(env->dregs[0], &sc->sc_d0);
101 err |= __put_user(env->dregs[1], &sc->sc_d1);
102 err |= __put_user(env->aregs[0], &sc->sc_a0);
103 err |= __put_user(env->aregs[1], &sc->sc_a1);
104 err |= __put_user(env->sr, &sc->sc_sr);
105 err |= __put_user(env->pc, &sc->sc_pc);
106
107 return err;
108}
109
110static int
111restore_sigcontext(CPUState *env, struct target_sigcontext *sc, int *pd0)
112{
113 int err = 0;
114 int temp;
115
116 err |= __get_user(env->aregs[7], &sc->sc_usp);
117 err |= __get_user(env->dregs[1], &sc->sc_d1);
118 err |= __get_user(env->aregs[0], &sc->sc_a0);
119 err |= __get_user(env->aregs[1], &sc->sc_a1);
120 err |= __get_user(env->pc, &sc->sc_pc);
121 err |= __get_user(temp, &sc->sc_sr);
122 env->sr = (env->sr & 0xff00) | (temp & 0xff);
123
124 *pd0 = tswapl(sc->sc_d0);
125
126 return err;
127}
128
129/*
130 * Determine which stack to use..
131 */
132static inline abi_ulong
133get_sigframe(struct target_sigaction *ka, CPUState *regs, size_t frame_size)
134{
135 unsigned long sp;
136
137 sp = regs->aregs[7];
138
139 /* This is the X/Open sanctioned signal stack switching. */
140 if ((ka->sa_flags & TARGET_SA_ONSTACK) && (sas_ss_flags (sp) == 0)) {
141 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
142 }
143
144 return ((sp - frame_size) & -8UL);
145}
146
147void setup_frame(int sig, struct target_sigaction *ka,
148 target_sigset_t *set, CPUState *env)
149{
150 struct target_sigframe *frame;
151 abi_ulong frame_addr;
152 abi_ulong retcode_addr;
153 abi_ulong sc_addr;
154 int err = 0;
155 int i;
156
157 frame_addr = get_sigframe(ka, env, sizeof *frame);
158 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
159 goto give_sigsegv;
160
161 err |= __put_user(sig, &frame->sig);
162
163 sc_addr = frame_addr + offsetof(struct target_sigframe, sc);
164 err |= __put_user(sc_addr, &frame->psc);
165
166 err |= setup_sigcontext(&frame->sc, env, set->sig[0]);
167 if (err)
168 goto give_sigsegv;
169
170 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
171 if (__put_user(set->sig[i], &frame->extramask[i - 1]))
172 goto give_sigsegv;
173 }
174
175 /* Set up to return from userspace. */
176
177 retcode_addr = frame_addr + offsetof(struct target_sigframe, retcode);
178 err |= __put_user(retcode_addr, &frame->pretcode);
179
180 /* moveq #,d0; trap #0 */
181
182 err |= __put_user(0x70004e40 + (TARGET_NR_sigreturn << 16),
183 (long *)(frame->retcode));
184
185 if (err)
186 goto give_sigsegv;
187
188 /* Set up to return from userspace */
189
190 env->aregs[7] = frame_addr;
191 env->pc = ka->_sa_handler;
192
193 unlock_user_struct(frame, frame_addr, 1);
194 return;
195
196give_sigsegv:
197 unlock_user_struct(frame, frame_addr, 1);
198 force_sig(TARGET_SIGSEGV);
199}
200
201static inline int target_rt_setup_ucontext(struct target_ucontext *uc,
202 CPUState *env)
203{
204 target_greg_t *gregs = uc->tuc_mcontext.gregs;
205 int err;
206
207 err = __put_user(TARGET_MCONTEXT_VERSION, &uc->tuc_mcontext.version);
208 err |= __put_user(env->dregs[0], &gregs[0]);
209 err |= __put_user(env->dregs[1], &gregs[1]);
210 err |= __put_user(env->dregs[2], &gregs[2]);
211 err |= __put_user(env->dregs[3], &gregs[3]);
212 err |= __put_user(env->dregs[4], &gregs[4]);
213 err |= __put_user(env->dregs[5], &gregs[5]);
214 err |= __put_user(env->dregs[6], &gregs[6]);
215 err |= __put_user(env->dregs[7], &gregs[7]);
216 err |= __put_user(env->aregs[0], &gregs[8]);
217 err |= __put_user(env->aregs[1], &gregs[9]);
218 err |= __put_user(env->aregs[2], &gregs[10]);
219 err |= __put_user(env->aregs[3], &gregs[11]);
220 err |= __put_user(env->aregs[4], &gregs[12]);
221 err |= __put_user(env->aregs[5], &gregs[13]);
222 err |= __put_user(env->aregs[6], &gregs[14]);
223 err |= __put_user(env->aregs[7], &gregs[15]);
224 err |= __put_user(env->pc, &gregs[16]);
225 err |= __put_user(env->sr, &gregs[17]);
226
227 return err;
228}
229
230static inline int target_rt_restore_ucontext(CPUState *env,
231 struct target_ucontext *uc,
232 int *pd0)
233{
234 int temp;
235 int err;
236 target_greg_t *gregs = uc->tuc_mcontext.gregs;
237
238 err = __get_user(temp, &uc->tuc_mcontext.version);
239 if (temp != TARGET_MCONTEXT_VERSION)
240 goto badframe;
241
242 /* restore passed registers */
243 err |= __get_user(env->dregs[0], &gregs[0]);
244 err |= __get_user(env->dregs[1], &gregs[1]);
245 err |= __get_user(env->dregs[2], &gregs[2]);
246 err |= __get_user(env->dregs[3], &gregs[3]);
247 err |= __get_user(env->dregs[4], &gregs[4]);
248 err |= __get_user(env->dregs[5], &gregs[5]);
249 err |= __get_user(env->dregs[6], &gregs[6]);
250 err |= __get_user(env->dregs[7], &gregs[7]);
251 err |= __get_user(env->aregs[0], &gregs[8]);
252 err |= __get_user(env->aregs[1], &gregs[9]);
253 err |= __get_user(env->aregs[2], &gregs[10]);
254 err |= __get_user(env->aregs[3], &gregs[11]);
255 err |= __get_user(env->aregs[4], &gregs[12]);
256 err |= __get_user(env->aregs[5], &gregs[13]);
257 err |= __get_user(env->aregs[6], &gregs[14]);
258 err |= __get_user(env->aregs[7], &gregs[15]);
259 err |= __get_user(env->pc, &gregs[16]);
260 err |= __get_user(temp, &gregs[17]);
261 env->sr = (env->sr & 0xff00) | (temp & 0xff);
262
263 *pd0 = env->dregs[0];
264 return err;
265
266badframe:
267 return 1;
268}
269
270void setup_rt_frame(int sig, struct target_sigaction *ka,
271 target_siginfo_t *info,
272 target_sigset_t *set, CPUState *env)
273{
274 struct target_rt_sigframe *frame;
275 abi_ulong frame_addr;
276 abi_ulong retcode_addr;
277 abi_ulong info_addr;
278 abi_ulong uc_addr;
279 int err = 0;
280 int i;
281
282 frame_addr = get_sigframe(ka, env, sizeof *frame);
283 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
284 goto give_sigsegv;
285
286 err |= __put_user(sig, &frame->sig);
287
288 info_addr = frame_addr + offsetof(struct target_rt_sigframe, info);
289 err |= __put_user(info_addr, &frame->pinfo);
290
291 uc_addr = frame_addr + offsetof(struct target_rt_sigframe, uc);
292 err |= __put_user(uc_addr, &frame->puc);
293
294 err |= copy_siginfo_to_user(&frame->info, info);
295
296 /* Create the ucontext */
297
298 err |= __put_user(0, &frame->uc.tuc_flags);
299 err |= __put_user(0, &frame->uc.tuc_link);
300 err |= __put_user(target_sigaltstack_used.ss_sp,
301 &frame->uc.tuc_stack.ss_sp);
302 err |= __put_user(sas_ss_flags(env->aregs[7]),
303 &frame->uc.tuc_stack.ss_flags);
304 err |= __put_user(target_sigaltstack_used.ss_size,
305 &frame->uc.tuc_stack.ss_size);
306 err |= target_rt_setup_ucontext(&frame->uc, env);
307
308 if (err)
309 goto give_sigsegv;
310
311 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
312 if (__put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]))
313 goto give_sigsegv;
314 }
315
316 /* Set up to return from userspace. */
317
318 retcode_addr = frame_addr + offsetof(struct target_sigframe, retcode);
319 err |= __put_user(retcode_addr, &frame->pretcode);
320
321 /* moveq #,d0; notb d0; trap #0 */
322
323 err |= __put_user(0x70004600 + ((TARGET_NR_rt_sigreturn ^ 0xff) << 16),
324 (long *)(frame->retcode + 0));
325 err |= __put_user(0x4e40, (short *)(frame->retcode + 4));
326
327 if (err)
328 goto give_sigsegv;
329
330 /* Set up to return from userspace */
331
332 env->aregs[7] = frame_addr;
333 env->pc = ka->_sa_handler;
334
335 unlock_user_struct(frame, frame_addr, 1);
336 return;
337
338give_sigsegv:
339 unlock_user_struct(frame, frame_addr, 1);
340 force_sig(TARGET_SIGSEGV);
341}
342
343long do_sigreturn(CPUState *env)
344{
345 struct target_sigframe *frame;
346 abi_ulong frame_addr = env->aregs[7] - 4;
347 target_sigset_t target_set;
348 sigset_t set;
349 int d0, i;
350
351 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
352 goto badframe;
353
354 /* set blocked signals */
355
356 if (__get_user(target_set.sig[0], &frame->sc.sc_mask))
357 goto badframe;
358
359 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
360 if (__get_user(target_set.sig[i], &frame->extramask[i - 1]))
361 goto badframe;
362 }
363
364 target_to_host_sigset_internal(&set, &target_set);
365 sigprocmask(SIG_SETMASK, &set, NULL);
366
367 /* restore registers */
368
369 if (restore_sigcontext(env, &frame->sc, &d0))
370 goto badframe;
371
372 unlock_user_struct(frame, frame_addr, 0);
373 return d0;
374
375badframe:
376 unlock_user_struct(frame, frame_addr, 0);
377 force_sig(TARGET_SIGSEGV);
378 return 0;
379}
380
381long do_rt_sigreturn(CPUState *env)
382{
383 struct target_rt_sigframe *frame;
384 abi_ulong frame_addr = env->aregs[7] - 4;
385 target_sigset_t target_set;
386 sigset_t set;
387 int d0;
388
389 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
390 goto badframe;
391
392 target_to_host_sigset_internal(&set, &target_set);
393 sigprocmask(SIG_SETMASK, &set, NULL);
394
395 /* restore registers */
396
397 if (target_rt_restore_ucontext(env, &frame->uc, &d0))
398 goto badframe;
399
400 if (do_sigaltstack(frame_addr +
401 offsetof(struct target_rt_sigframe, uc.tuc_stack),
402 0, get_sp_from_cpustate(env)) == -EFAULT)
403 goto badframe;
404
405 unlock_user_struct(frame, frame_addr, 0);
406 return d0;
407
408badframe:
409 unlock_user_struct(frame, frame_addr, 0);
410 force_sig(TARGET_SIGSEGV);
411 return 0;
412}