blob: 316b01c04a14ad542de99660710fd1b13371d5a3 [file] [log] [blame]
Peter Maydellda30d852011-12-05 19:42:18 +00001/*
2 * Emulation of Linux signals : i386 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
20#include <stdlib.h>
21#include <stdio.h>
22#include <string.h>
23#include <stdarg.h>
24#include <unistd.h>
25#include <errno.h>
26#include <assert.h>
27#include <sys/ucontext.h>
28#include <sys/resource.h>
29
30#include "qemu.h"
31#include "qemu-common.h"
32#include "signal-common.h"
33#include "target_signal.h"
34
35/* from the Linux kernel */
36
37struct target_fpreg {
38 uint16_t significand[4];
39 uint16_t exponent;
40};
41
42struct target_fpxreg {
43 uint16_t significand[4];
44 uint16_t exponent;
45 uint16_t padding[3];
46};
47
48struct target_xmmreg {
49 abi_ulong element[4];
50};
51
52struct target_fpstate {
53 /* Regular FPU environment */
54 abi_ulong cw;
55 abi_ulong sw;
56 abi_ulong tag;
57 abi_ulong ipoff;
58 abi_ulong cssel;
59 abi_ulong dataoff;
60 abi_ulong datasel;
61 struct target_fpreg _st[8];
62 uint16_t status;
63 uint16_t magic; /* 0xffff = regular FPU data only */
64
65 /* FXSR FPU environment */
66 abi_ulong _fxsr_env[6]; /* FXSR FPU env is ignored */
67 abi_ulong mxcsr;
68 abi_ulong reserved;
69 struct target_fpxreg _fxsr_st[8]; /* FXSR FPU reg data is ignored */
70 struct target_xmmreg _xmm[8];
71 abi_ulong padding[56];
72};
73
74#define X86_FXSR_MAGIC 0x0000
75
76struct target_sigcontext {
77 uint16_t gs, __gsh;
78 uint16_t fs, __fsh;
79 uint16_t es, __esh;
80 uint16_t ds, __dsh;
81 abi_ulong edi;
82 abi_ulong esi;
83 abi_ulong ebp;
84 abi_ulong esp;
85 abi_ulong ebx;
86 abi_ulong edx;
87 abi_ulong ecx;
88 abi_ulong eax;
89 abi_ulong trapno;
90 abi_ulong err;
91 abi_ulong eip;
92 uint16_t cs, __csh;
93 abi_ulong eflags;
94 abi_ulong esp_at_signal;
95 uint16_t ss, __ssh;
96 abi_ulong fpstate; /* pointer */
97 abi_ulong oldmask;
98 abi_ulong cr2;
99};
100
101struct target_ucontext {
102 abi_ulong tuc_flags;
103 abi_ulong tuc_link;
104 target_stack_t tuc_stack;
105 struct target_sigcontext tuc_mcontext;
106 target_sigset_t tuc_sigmask; /* mask last for extensibility */
107};
108
109struct sigframe
110{
111 abi_ulong pretcode;
112 int sig;
113 struct target_sigcontext sc;
114 struct target_fpstate fpstate;
115 abi_ulong extramask[TARGET_NSIG_WORDS-1];
116 char retcode[8];
117};
118
119struct rt_sigframe
120{
121 abi_ulong pretcode;
122 int sig;
123 abi_ulong pinfo;
124 abi_ulong puc;
125 struct target_siginfo info;
126 struct target_ucontext uc;
127 struct target_fpstate fpstate;
128 char retcode[8];
129};
130
131/*
132 * Set up a signal frame.
133 */
134
135/* XXX: save x87 state */
136static int
137setup_sigcontext(struct target_sigcontext *sc, struct target_fpstate *fpstate,
138 CPUX86State *env, abi_ulong mask, abi_ulong fpstate_addr)
139{
140 int err = 0;
141 uint16_t magic;
142
143 /* already locked in setup_frame() */
144 err |= __put_user(env->segs[R_GS].selector, (unsigned int *)&sc->gs);
145 err |= __put_user(env->segs[R_FS].selector, (unsigned int *)&sc->fs);
146 err |= __put_user(env->segs[R_ES].selector, (unsigned int *)&sc->es);
147 err |= __put_user(env->segs[R_DS].selector, (unsigned int *)&sc->ds);
148 err |= __put_user(env->regs[R_EDI], &sc->edi);
149 err |= __put_user(env->regs[R_ESI], &sc->esi);
150 err |= __put_user(env->regs[R_EBP], &sc->ebp);
151 err |= __put_user(env->regs[R_ESP], &sc->esp);
152 err |= __put_user(env->regs[R_EBX], &sc->ebx);
153 err |= __put_user(env->regs[R_EDX], &sc->edx);
154 err |= __put_user(env->regs[R_ECX], &sc->ecx);
155 err |= __put_user(env->regs[R_EAX], &sc->eax);
156 err |= __put_user(env->exception_index, &sc->trapno);
157 err |= __put_user(env->error_code, &sc->err);
158 err |= __put_user(env->eip, &sc->eip);
159 err |= __put_user(env->segs[R_CS].selector, (unsigned int *)&sc->cs);
160 err |= __put_user(env->eflags, &sc->eflags);
161 err |= __put_user(env->regs[R_ESP], &sc->esp_at_signal);
162 err |= __put_user(env->segs[R_SS].selector, (unsigned int *)&sc->ss);
163
164 cpu_x86_fsave(env, fpstate_addr, 1);
165 fpstate->status = fpstate->sw;
166 magic = 0xffff;
167 err |= __put_user(magic, &fpstate->magic);
168 err |= __put_user(fpstate_addr, &sc->fpstate);
169
170 /* non-iBCS2 extensions.. */
171 err |= __put_user(mask, &sc->oldmask);
172 err |= __put_user(env->cr[2], &sc->cr2);
173 return err;
174}
175
176/*
177 * Determine which stack to use..
178 */
179
180static inline abi_ulong
181get_sigframe(struct target_sigaction *ka, CPUX86State *env, size_t frame_size)
182{
183 unsigned long esp;
184
185 /* Default to using normal stack */
186 esp = env->regs[R_ESP];
187 /* This is the X/Open sanctioned signal stack switching. */
188 if (ka->sa_flags & TARGET_SA_ONSTACK) {
189 if (sas_ss_flags(esp) == 0)
190 esp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
191 }
192
193 /* This is the legacy signal stack switching. */
194 else
195 if ((env->segs[R_SS].selector & 0xffff) != __USER_DS &&
196 !(ka->sa_flags & TARGET_SA_RESTORER) &&
197 ka->sa_restorer) {
198 esp = (unsigned long) ka->sa_restorer;
199 }
200 return (esp - frame_size) & -8ul;
201}
202
203/* compare linux/arch/i386/kernel/signal.c:setup_frame() */
204void setup_frame(int sig, struct target_sigaction *ka,
205 target_sigset_t *set, CPUX86State *env)
206{
207 abi_ulong frame_addr;
208 struct sigframe *frame;
209 int i, err = 0;
210
211 frame_addr = get_sigframe(ka, env, sizeof(*frame));
212
213 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
214 goto give_sigsegv;
215
216 err |= __put_user(current_exec_domain_sig(sig),
217 &frame->sig);
218 if (err)
219 goto give_sigsegv;
220
221 setup_sigcontext(&frame->sc, &frame->fpstate, env, set->sig[0],
222 frame_addr + offsetof(struct sigframe, fpstate));
223 if (err)
224 goto give_sigsegv;
225
226 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
227 if (__put_user(set->sig[i], &frame->extramask[i - 1]))
228 goto give_sigsegv;
229 }
230
231 /* Set up to return from userspace. If provided, use a stub
232 already in userspace. */
233 if (ka->sa_flags & TARGET_SA_RESTORER) {
234 err |= __put_user(ka->sa_restorer, &frame->pretcode);
235 } else {
236 uint16_t val16;
237 abi_ulong retcode_addr;
238 retcode_addr = frame_addr + offsetof(struct sigframe, retcode);
239 err |= __put_user(retcode_addr, &frame->pretcode);
240 /* This is popl %eax ; movl $,%eax ; int $0x80 */
241 val16 = 0xb858;
242 err |= __put_user(val16, (uint16_t *)(frame->retcode+0));
243 err |= __put_user(TARGET_NR_sigreturn, (int *)(frame->retcode+2));
244 val16 = 0x80cd;
245 err |= __put_user(val16, (uint16_t *)(frame->retcode+6));
246 }
247
248 if (err)
249 goto give_sigsegv;
250
251 /* Set up registers for signal handler */
252 env->regs[R_ESP] = frame_addr;
253 env->eip = ka->_sa_handler;
254
255 cpu_x86_load_seg(env, R_DS, __USER_DS);
256 cpu_x86_load_seg(env, R_ES, __USER_DS);
257 cpu_x86_load_seg(env, R_SS, __USER_DS);
258 cpu_x86_load_seg(env, R_CS, __USER_CS);
259 env->eflags &= ~TF_MASK;
260
261 unlock_user_struct(frame, frame_addr, 1);
262
263 return;
264
265give_sigsegv:
266 unlock_user_struct(frame, frame_addr, 1);
267 if (sig == TARGET_SIGSEGV)
268 ka->_sa_handler = TARGET_SIG_DFL;
269 force_sig(TARGET_SIGSEGV /* , current */);
270}
271
272/* compare linux/arch/i386/kernel/signal.c:setup_rt_frame() */
273void setup_rt_frame(int sig, struct target_sigaction *ka,
274 target_siginfo_t *info,
275 target_sigset_t *set, CPUX86State *env)
276{
277 abi_ulong frame_addr, addr;
278 struct rt_sigframe *frame;
279 int i, err = 0;
280
281 frame_addr = get_sigframe(ka, env, sizeof(*frame));
282
283 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
284 goto give_sigsegv;
285
286 err |= __put_user(current_exec_domain_sig(sig),
287 &frame->sig);
288 addr = frame_addr + offsetof(struct rt_sigframe, info);
289 err |= __put_user(addr, &frame->pinfo);
290 addr = frame_addr + offsetof(struct rt_sigframe, uc);
291 err |= __put_user(addr, &frame->puc);
292 err |= copy_siginfo_to_user(&frame->info, info);
293 if (err)
294 goto give_sigsegv;
295
296 /* Create the ucontext. */
297 err |= __put_user(0, &frame->uc.tuc_flags);
298 err |= __put_user(0, &frame->uc.tuc_link);
299 err |= __put_user(target_sigaltstack_used.ss_sp,
300 &frame->uc.tuc_stack.ss_sp);
301 err |= __put_user(sas_ss_flags(get_sp_from_cpustate(env)),
302 &frame->uc.tuc_stack.ss_flags);
303 err |= __put_user(target_sigaltstack_used.ss_size,
304 &frame->uc.tuc_stack.ss_size);
305 err |= setup_sigcontext(&frame->uc.tuc_mcontext, &frame->fpstate,
306 env, set->sig[0],
307 frame_addr + offsetof(struct rt_sigframe, fpstate));
308 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
309 if (__put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]))
310 goto give_sigsegv;
311 }
312
313 /* Set up to return from userspace. If provided, use a stub
314 already in userspace. */
315 if (ka->sa_flags & TARGET_SA_RESTORER) {
316 err |= __put_user(ka->sa_restorer, &frame->pretcode);
317 } else {
318 uint16_t val16;
319 addr = frame_addr + offsetof(struct rt_sigframe, retcode);
320 err |= __put_user(addr, &frame->pretcode);
321 /* This is movl $,%eax ; int $0x80 */
322 err |= __put_user(0xb8, (char *)(frame->retcode+0));
323 err |= __put_user(TARGET_NR_rt_sigreturn, (int *)(frame->retcode+1));
324 val16 = 0x80cd;
325 err |= __put_user(val16, (uint16_t *)(frame->retcode+5));
326 }
327
328 if (err)
329 goto give_sigsegv;
330
331 /* Set up registers for signal handler */
332 env->regs[R_ESP] = frame_addr;
333 env->eip = ka->_sa_handler;
334
335 cpu_x86_load_seg(env, R_DS, __USER_DS);
336 cpu_x86_load_seg(env, R_ES, __USER_DS);
337 cpu_x86_load_seg(env, R_SS, __USER_DS);
338 cpu_x86_load_seg(env, R_CS, __USER_CS);
339 env->eflags &= ~TF_MASK;
340
341 unlock_user_struct(frame, frame_addr, 1);
342
343 return;
344
345give_sigsegv:
346 unlock_user_struct(frame, frame_addr, 1);
347 if (sig == TARGET_SIGSEGV)
348 ka->_sa_handler = TARGET_SIG_DFL;
349 force_sig(TARGET_SIGSEGV /* , current */);
350}
351
352static int
353restore_sigcontext(CPUX86State *env, struct target_sigcontext *sc, int *peax)
354{
355 unsigned int err = 0;
356 abi_ulong fpstate_addr;
357 unsigned int tmpflags;
358
359 cpu_x86_load_seg(env, R_GS, tswap16(sc->gs));
360 cpu_x86_load_seg(env, R_FS, tswap16(sc->fs));
361 cpu_x86_load_seg(env, R_ES, tswap16(sc->es));
362 cpu_x86_load_seg(env, R_DS, tswap16(sc->ds));
363
364 env->regs[R_EDI] = tswapl(sc->edi);
365 env->regs[R_ESI] = tswapl(sc->esi);
366 env->regs[R_EBP] = tswapl(sc->ebp);
367 env->regs[R_ESP] = tswapl(sc->esp);
368 env->regs[R_EBX] = tswapl(sc->ebx);
369 env->regs[R_EDX] = tswapl(sc->edx);
370 env->regs[R_ECX] = tswapl(sc->ecx);
371 env->eip = tswapl(sc->eip);
372
373 cpu_x86_load_seg(env, R_CS, lduw_p(&sc->cs) | 3);
374 cpu_x86_load_seg(env, R_SS, lduw_p(&sc->ss) | 3);
375
376 tmpflags = tswapl(sc->eflags);
377 env->eflags = (env->eflags & ~0x40DD5) | (tmpflags & 0x40DD5);
378 // regs->orig_eax = -1; /* disable syscall checks */
379
380 fpstate_addr = tswapl(sc->fpstate);
381 if (fpstate_addr != 0) {
382 if (!access_ok(VERIFY_READ, fpstate_addr,
383 sizeof(struct target_fpstate)))
384 goto badframe;
385 cpu_x86_frstor(env, fpstate_addr, 1);
386 }
387
388 *peax = tswapl(sc->eax);
389 return err;
390badframe:
391 return 1;
392}
393
394long do_sigreturn(CPUX86State *env)
395{
396 struct sigframe *frame;
397 abi_ulong frame_addr = env->regs[R_ESP] - 8;
398 target_sigset_t target_set;
399 sigset_t set;
400 int eax, i;
401
402#if defined(DEBUG_SIGNAL)
403 fprintf(stderr, "do_sigreturn\n");
404#endif
405 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
406 goto badframe;
407 /* set blocked signals */
408 if (__get_user(target_set.sig[0], &frame->sc.oldmask))
409 goto badframe;
410 for(i = 1; i < TARGET_NSIG_WORDS; i++) {
411 if (__get_user(target_set.sig[i], &frame->extramask[i - 1]))
412 goto badframe;
413 }
414
415 target_to_host_sigset_internal(&set, &target_set);
416 sigprocmask(SIG_SETMASK, &set, NULL);
417
418 /* restore registers */
419 if (restore_sigcontext(env, &frame->sc, &eax))
420 goto badframe;
421 unlock_user_struct(frame, frame_addr, 0);
422 return eax;
423
424badframe:
425 unlock_user_struct(frame, frame_addr, 0);
426 force_sig(TARGET_SIGSEGV);
427 return 0;
428}
429
430long do_rt_sigreturn(CPUX86State *env)
431{
432 abi_ulong frame_addr;
433 struct rt_sigframe *frame;
434 sigset_t set;
435 int eax;
436
437 frame_addr = env->regs[R_ESP] - 4;
438 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
439 goto badframe;
440 target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
441 sigprocmask(SIG_SETMASK, &set, NULL);
442
443 if (restore_sigcontext(env, &frame->uc.tuc_mcontext, &eax))
444 goto badframe;
445
446 if (do_sigaltstack(frame_addr + offsetof(struct rt_sigframe, uc.tuc_stack), 0,
447 get_sp_from_cpustate(env)) == -EFAULT)
448 goto badframe;
449
450 unlock_user_struct(frame, frame_addr, 0);
451 return eax;
452
453badframe:
454 unlock_user_struct(frame, frame_addr, 0);
455 force_sig(TARGET_SIGSEGV);
456 return 0;
457}
458