]>
Commit | Line | Data |
---|---|---|
31e31b8a | 1 | /* |
66fb9763 | 2 | * Emulation of Linux signals |
31e31b8a FB |
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, write to the Free Software | |
18 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
19 | */ | |
20 | #include <stdlib.h> | |
21 | #include <stdio.h> | |
66fb9763 | 22 | #include <string.h> |
31e31b8a | 23 | #include <stdarg.h> |
2677e107 | 24 | #include <unistd.h> |
31e31b8a | 25 | #include <signal.h> |
66fb9763 | 26 | #include <errno.h> |
31e31b8a FB |
27 | #include <sys/ucontext.h> |
28 | ||
0d330196 FB |
29 | #ifdef __ia64__ |
30 | #undef uc_mcontext | |
31 | #undef uc_sigmask | |
32 | #undef uc_stack | |
33 | #undef uc_link | |
34 | #endif | |
35 | ||
3ef693a0 | 36 | #include "qemu.h" |
66fb9763 FB |
37 | |
38 | //#define DEBUG_SIGNAL | |
39 | ||
40 | #define MAX_SIGQUEUE_SIZE 1024 | |
41 | ||
42 | struct sigqueue { | |
43 | struct sigqueue *next; | |
9de5e440 | 44 | target_siginfo_t info; |
66fb9763 | 45 | }; |
31e31b8a FB |
46 | |
47 | struct emulated_sigaction { | |
48 | struct target_sigaction sa; | |
66fb9763 FB |
49 | int pending; /* true if signal is pending */ |
50 | struct sigqueue *first; | |
51 | struct sigqueue info; /* in order to always have memory for the | |
52 | first signal, we put it here */ | |
31e31b8a FB |
53 | }; |
54 | ||
66fb9763 FB |
55 | static struct emulated_sigaction sigact_table[TARGET_NSIG]; |
56 | static struct sigqueue sigqueue_table[MAX_SIGQUEUE_SIZE]; /* siginfo queue */ | |
57 | static struct sigqueue *first_free; /* first free siginfo queue entry */ | |
58 | static int signal_pending; /* non zero if a signal may be pending */ | |
31e31b8a | 59 | |
66fb9763 FB |
60 | static void host_signal_handler(int host_signum, siginfo_t *info, |
61 | void *puc); | |
62 | ||
63 | /* XXX: do it properly */ | |
31e31b8a FB |
64 | static inline int host_to_target_signal(int sig) |
65 | { | |
66 | return sig; | |
67 | } | |
68 | ||
69 | static inline int target_to_host_signal(int sig) | |
70 | { | |
71 | return sig; | |
72 | } | |
73 | ||
66fb9763 FB |
74 | void host_to_target_sigset(target_sigset_t *d, sigset_t *s) |
75 | { | |
76 | int i; | |
77 | for(i = 0;i < TARGET_NSIG_WORDS; i++) { | |
78 | d->sig[i] = tswapl(((unsigned long *)s)[i]); | |
79 | } | |
80 | } | |
81 | ||
82 | void target_to_host_sigset(sigset_t *d, target_sigset_t *s) | |
83 | { | |
84 | int i; | |
85 | for(i = 0;i < TARGET_NSIG_WORDS; i++) { | |
86 | ((unsigned long *)d)[i] = tswapl(s->sig[i]); | |
87 | } | |
88 | } | |
89 | ||
90 | void host_to_target_old_sigset(target_ulong *old_sigset, | |
91 | const sigset_t *sigset) | |
92 | { | |
93 | *old_sigset = tswap32(*(unsigned long *)sigset & 0xffffffff); | |
94 | } | |
95 | ||
96 | void target_to_host_old_sigset(sigset_t *sigset, | |
97 | const target_ulong *old_sigset) | |
98 | { | |
99 | sigemptyset(sigset); | |
100 | *(unsigned long *)sigset = tswapl(*old_sigset); | |
101 | } | |
102 | ||
9de5e440 FB |
103 | /* siginfo conversion */ |
104 | ||
105 | static inline void host_to_target_siginfo_noswap(target_siginfo_t *tinfo, | |
106 | const siginfo_t *info) | |
66fb9763 | 107 | { |
9de5e440 FB |
108 | int sig; |
109 | sig = host_to_target_signal(info->si_signo); | |
110 | tinfo->si_signo = sig; | |
111 | tinfo->si_errno = 0; | |
112 | tinfo->si_code = 0; | |
447db213 FB |
113 | if (sig == SIGILL || sig == SIGFPE || sig == SIGSEGV || |
114 | sig == SIGBUS || sig == SIGTRAP) { | |
9de5e440 FB |
115 | /* should never come here, but who knows. The information for |
116 | the target is irrelevant */ | |
117 | tinfo->_sifields._sigfault._addr = 0; | |
118 | } else if (sig >= TARGET_SIGRTMIN) { | |
119 | tinfo->_sifields._rt._pid = info->si_pid; | |
120 | tinfo->_sifields._rt._uid = info->si_uid; | |
121 | /* XXX: potential problem if 64 bit */ | |
122 | tinfo->_sifields._rt._sigval.sival_ptr = | |
123 | (target_ulong)info->si_value.sival_ptr; | |
124 | } | |
125 | } | |
126 | ||
127 | static void tswap_siginfo(target_siginfo_t *tinfo, | |
128 | const target_siginfo_t *info) | |
129 | { | |
130 | int sig; | |
131 | sig = info->si_signo; | |
132 | tinfo->si_signo = tswap32(sig); | |
66fb9763 FB |
133 | tinfo->si_errno = tswap32(info->si_errno); |
134 | tinfo->si_code = tswap32(info->si_code); | |
447db213 FB |
135 | if (sig == SIGILL || sig == SIGFPE || sig == SIGSEGV || |
136 | sig == SIGBUS || sig == SIGTRAP) { | |
9de5e440 FB |
137 | tinfo->_sifields._sigfault._addr = |
138 | tswapl(info->_sifields._sigfault._addr); | |
139 | } else if (sig >= TARGET_SIGRTMIN) { | |
140 | tinfo->_sifields._rt._pid = tswap32(info->_sifields._rt._pid); | |
141 | tinfo->_sifields._rt._uid = tswap32(info->_sifields._rt._uid); | |
142 | tinfo->_sifields._rt._sigval.sival_ptr = | |
143 | tswapl(info->_sifields._rt._sigval.sival_ptr); | |
144 | } | |
145 | } | |
146 | ||
147 | ||
148 | void host_to_target_siginfo(target_siginfo_t *tinfo, const siginfo_t *info) | |
149 | { | |
150 | host_to_target_siginfo_noswap(tinfo, info); | |
151 | tswap_siginfo(tinfo, tinfo); | |
66fb9763 FB |
152 | } |
153 | ||
9de5e440 FB |
154 | /* XXX: we support only POSIX RT signals are used. */ |
155 | /* XXX: find a solution for 64 bit (additionnal malloced data is needed) */ | |
156 | void target_to_host_siginfo(siginfo_t *info, const target_siginfo_t *tinfo) | |
66fb9763 FB |
157 | { |
158 | info->si_signo = tswap32(tinfo->si_signo); | |
159 | info->si_errno = tswap32(tinfo->si_errno); | |
160 | info->si_code = tswap32(tinfo->si_code); | |
9de5e440 FB |
161 | info->si_pid = tswap32(tinfo->_sifields._rt._pid); |
162 | info->si_uid = tswap32(tinfo->_sifields._rt._uid); | |
163 | info->si_value.sival_ptr = | |
164 | (void *)tswapl(tinfo->_sifields._rt._sigval.sival_ptr); | |
66fb9763 FB |
165 | } |
166 | ||
31e31b8a FB |
167 | void signal_init(void) |
168 | { | |
169 | struct sigaction act; | |
170 | int i; | |
171 | ||
9de5e440 FB |
172 | /* set all host signal handlers. ALL signals are blocked during |
173 | the handlers to serialize them. */ | |
174 | sigfillset(&act.sa_mask); | |
31e31b8a FB |
175 | act.sa_flags = SA_SIGINFO; |
176 | act.sa_sigaction = host_signal_handler; | |
177 | for(i = 1; i < NSIG; i++) { | |
c9087c2a | 178 | sigaction(i, &act, NULL); |
31e31b8a FB |
179 | } |
180 | ||
181 | memset(sigact_table, 0, sizeof(sigact_table)); | |
66fb9763 FB |
182 | |
183 | first_free = &sigqueue_table[0]; | |
184 | for(i = 0; i < MAX_SIGQUEUE_SIZE - 1; i++) | |
185 | sigqueue_table[i].next = &sigqueue_table[i + 1]; | |
186 | sigqueue_table[MAX_SIGQUEUE_SIZE - 1].next = NULL; | |
187 | } | |
188 | ||
189 | /* signal queue handling */ | |
190 | ||
191 | static inline struct sigqueue *alloc_sigqueue(void) | |
192 | { | |
193 | struct sigqueue *q = first_free; | |
194 | if (!q) | |
195 | return NULL; | |
196 | first_free = q->next; | |
197 | return q; | |
31e31b8a FB |
198 | } |
199 | ||
66fb9763 FB |
200 | static inline void free_sigqueue(struct sigqueue *q) |
201 | { | |
202 | q->next = first_free; | |
203 | first_free = q; | |
204 | } | |
205 | ||
9de5e440 FB |
206 | /* abort execution with signal */ |
207 | void __attribute((noreturn)) force_sig(int sig) | |
66fb9763 FB |
208 | { |
209 | int host_sig; | |
66fb9763 | 210 | host_sig = target_to_host_signal(sig); |
bc8a22cc | 211 | fprintf(stderr, "qemu: uncaught target signal %d (%s) - exiting\n", |
66fb9763 | 212 | sig, strsignal(host_sig)); |
9de5e440 | 213 | #if 1 |
66fb9763 | 214 | _exit(-host_sig); |
9de5e440 FB |
215 | #else |
216 | { | |
217 | struct sigaction act; | |
218 | sigemptyset(&act.sa_mask); | |
219 | act.sa_flags = SA_SIGINFO; | |
220 | act.sa_sigaction = SIG_DFL; | |
221 | sigaction(SIGABRT, &act, NULL); | |
222 | abort(); | |
223 | } | |
224 | #endif | |
66fb9763 FB |
225 | } |
226 | ||
9de5e440 FB |
227 | /* queue a signal so that it will be send to the virtual CPU as soon |
228 | as possible */ | |
229 | int queue_signal(int sig, target_siginfo_t *info) | |
31e31b8a | 230 | { |
66fb9763 | 231 | struct emulated_sigaction *k; |
9de5e440 | 232 | struct sigqueue *q, **pq; |
66fb9763 FB |
233 | target_ulong handler; |
234 | ||
9de5e440 | 235 | #if defined(DEBUG_SIGNAL) |
bc8a22cc | 236 | fprintf(stderr, "queue_signal: sig=%d\n", |
9de5e440 | 237 | sig); |
66fb9763 | 238 | #endif |
9de5e440 | 239 | k = &sigact_table[sig - 1]; |
66fb9763 FB |
240 | handler = k->sa._sa_handler; |
241 | if (handler == TARGET_SIG_DFL) { | |
242 | /* default handler : ignore some signal. The other are fatal */ | |
243 | if (sig != TARGET_SIGCHLD && | |
244 | sig != TARGET_SIGURG && | |
245 | sig != TARGET_SIGWINCH) { | |
246 | force_sig(sig); | |
9de5e440 FB |
247 | } else { |
248 | return 0; /* indicate ignored */ | |
66fb9763 FB |
249 | } |
250 | } else if (handler == TARGET_SIG_IGN) { | |
251 | /* ignore signal */ | |
9de5e440 | 252 | return 0; |
66fb9763 FB |
253 | } else if (handler == TARGET_SIG_ERR) { |
254 | force_sig(sig); | |
255 | } else { | |
9de5e440 FB |
256 | pq = &k->first; |
257 | if (sig < TARGET_SIGRTMIN) { | |
258 | /* if non real time signal, we queue exactly one signal */ | |
259 | if (!k->pending) | |
260 | q = &k->info; | |
261 | else | |
262 | return 0; | |
263 | } else { | |
264 | if (!k->pending) { | |
265 | /* first signal */ | |
266 | q = &k->info; | |
267 | } else { | |
268 | q = alloc_sigqueue(); | |
269 | if (!q) | |
270 | return -EAGAIN; | |
271 | while (*pq != NULL) | |
272 | pq = &(*pq)->next; | |
273 | } | |
274 | } | |
275 | *pq = q; | |
276 | q->info = *info; | |
277 | q->next = NULL; | |
278 | k->pending = 1; | |
279 | /* signal that a new signal is pending */ | |
280 | signal_pending = 1; | |
281 | return 1; /* indicates that the signal was queued */ | |
282 | } | |
283 | } | |
284 | ||
285 | #if defined(DEBUG_SIGNAL) | |
286 | #ifdef __i386__ | |
287 | static void dump_regs(struct ucontext *uc) | |
288 | { | |
289 | fprintf(stderr, | |
290 | "EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n" | |
291 | "ESI=%08x EDI=%08x EBP=%08x ESP=%08x\n" | |
292 | "EFL=%08x EIP=%08x\n", | |
293 | uc->uc_mcontext.gregs[EAX], | |
294 | uc->uc_mcontext.gregs[EBX], | |
295 | uc->uc_mcontext.gregs[ECX], | |
296 | uc->uc_mcontext.gregs[EDX], | |
297 | uc->uc_mcontext.gregs[ESI], | |
298 | uc->uc_mcontext.gregs[EDI], | |
299 | uc->uc_mcontext.gregs[EBP], | |
300 | uc->uc_mcontext.gregs[ESP], | |
301 | uc->uc_mcontext.gregs[EFL], | |
302 | uc->uc_mcontext.gregs[EIP]); | |
303 | } | |
304 | #else | |
305 | static void dump_regs(struct ucontext *uc) | |
306 | { | |
307 | } | |
308 | #endif | |
309 | ||
310 | #endif | |
311 | ||
312 | static void host_signal_handler(int host_signum, siginfo_t *info, | |
313 | void *puc) | |
314 | { | |
315 | int sig; | |
316 | target_siginfo_t tinfo; | |
317 | ||
318 | /* the CPU emulator uses some host signals to detect exceptions, | |
319 | we we forward to it some signals */ | |
320 | if (host_signum == SIGSEGV || host_signum == SIGBUS) { | |
b346ff46 | 321 | if (cpu_signal_handler(host_signum, info, puc)) |
9de5e440 FB |
322 | return; |
323 | } | |
324 | ||
325 | /* get target signal number */ | |
326 | sig = host_to_target_signal(host_signum); | |
327 | if (sig < 1 || sig > TARGET_NSIG) | |
328 | return; | |
329 | #if defined(DEBUG_SIGNAL) | |
bc8a22cc | 330 | fprintf(stderr, "qemu: got signal %d\n", sig); |
9de5e440 FB |
331 | dump_regs(puc); |
332 | #endif | |
333 | host_to_target_siginfo_noswap(&tinfo, info); | |
334 | if (queue_signal(sig, &tinfo) == 1) { | |
335 | /* interrupt the virtual CPU as soon as possible */ | |
b346ff46 | 336 | cpu_interrupt(global_env); |
66fb9763 FB |
337 | } |
338 | } | |
339 | ||
340 | int do_sigaction(int sig, const struct target_sigaction *act, | |
341 | struct target_sigaction *oact) | |
342 | { | |
343 | struct emulated_sigaction *k; | |
344 | ||
345 | if (sig < 1 || sig > TARGET_NSIG) | |
346 | return -EINVAL; | |
347 | k = &sigact_table[sig - 1]; | |
348 | #if defined(DEBUG_SIGNAL) && 0 | |
349 | fprintf(stderr, "sigaction sig=%d act=0x%08x, oact=0x%08x\n", | |
350 | sig, (int)act, (int)oact); | |
351 | #endif | |
352 | if (oact) { | |
353 | oact->_sa_handler = tswapl(k->sa._sa_handler); | |
354 | oact->sa_flags = tswapl(k->sa.sa_flags); | |
355 | oact->sa_restorer = tswapl(k->sa.sa_restorer); | |
356 | oact->sa_mask = k->sa.sa_mask; | |
357 | } | |
358 | if (act) { | |
359 | k->sa._sa_handler = tswapl(act->_sa_handler); | |
360 | k->sa.sa_flags = tswapl(act->sa_flags); | |
361 | k->sa.sa_restorer = tswapl(act->sa_restorer); | |
362 | k->sa.sa_mask = act->sa_mask; | |
363 | } | |
364 | return 0; | |
365 | } | |
366 | ||
367 | #ifdef TARGET_I386 | |
368 | ||
369 | /* from the Linux kernel */ | |
370 | ||
371 | struct target_fpreg { | |
372 | uint16_t significand[4]; | |
373 | uint16_t exponent; | |
374 | }; | |
375 | ||
376 | struct target_fpxreg { | |
377 | uint16_t significand[4]; | |
378 | uint16_t exponent; | |
379 | uint16_t padding[3]; | |
380 | }; | |
381 | ||
382 | struct target_xmmreg { | |
383 | target_ulong element[4]; | |
384 | }; | |
385 | ||
386 | struct target_fpstate { | |
387 | /* Regular FPU environment */ | |
388 | target_ulong cw; | |
389 | target_ulong sw; | |
390 | target_ulong tag; | |
391 | target_ulong ipoff; | |
392 | target_ulong cssel; | |
393 | target_ulong dataoff; | |
394 | target_ulong datasel; | |
395 | struct target_fpreg _st[8]; | |
396 | uint16_t status; | |
397 | uint16_t magic; /* 0xffff = regular FPU data only */ | |
398 | ||
399 | /* FXSR FPU environment */ | |
400 | target_ulong _fxsr_env[6]; /* FXSR FPU env is ignored */ | |
401 | target_ulong mxcsr; | |
402 | target_ulong reserved; | |
403 | struct target_fpxreg _fxsr_st[8]; /* FXSR FPU reg data is ignored */ | |
404 | struct target_xmmreg _xmm[8]; | |
405 | target_ulong padding[56]; | |
406 | }; | |
407 | ||
408 | #define X86_FXSR_MAGIC 0x0000 | |
409 | ||
410 | struct target_sigcontext { | |
411 | uint16_t gs, __gsh; | |
412 | uint16_t fs, __fsh; | |
413 | uint16_t es, __esh; | |
414 | uint16_t ds, __dsh; | |
415 | target_ulong edi; | |
416 | target_ulong esi; | |
417 | target_ulong ebp; | |
418 | target_ulong esp; | |
419 | target_ulong ebx; | |
420 | target_ulong edx; | |
421 | target_ulong ecx; | |
422 | target_ulong eax; | |
423 | target_ulong trapno; | |
424 | target_ulong err; | |
425 | target_ulong eip; | |
426 | uint16_t cs, __csh; | |
427 | target_ulong eflags; | |
428 | target_ulong esp_at_signal; | |
429 | uint16_t ss, __ssh; | |
430 | target_ulong fpstate; /* pointer */ | |
431 | target_ulong oldmask; | |
432 | target_ulong cr2; | |
433 | }; | |
434 | ||
435 | typedef struct target_sigaltstack { | |
436 | target_ulong ss_sp; | |
437 | int ss_flags; | |
438 | target_ulong ss_size; | |
439 | } target_stack_t; | |
440 | ||
441 | struct target_ucontext { | |
442 | target_ulong uc_flags; | |
443 | target_ulong uc_link; | |
444 | target_stack_t uc_stack; | |
445 | struct target_sigcontext uc_mcontext; | |
446 | target_sigset_t uc_sigmask; /* mask last for extensibility */ | |
447 | }; | |
448 | ||
449 | struct sigframe | |
450 | { | |
451 | target_ulong pretcode; | |
452 | int sig; | |
453 | struct target_sigcontext sc; | |
454 | struct target_fpstate fpstate; | |
455 | target_ulong extramask[TARGET_NSIG_WORDS-1]; | |
456 | char retcode[8]; | |
457 | }; | |
458 | ||
459 | struct rt_sigframe | |
460 | { | |
461 | target_ulong pretcode; | |
462 | int sig; | |
463 | target_ulong pinfo; | |
464 | target_ulong puc; | |
465 | struct target_siginfo info; | |
466 | struct target_ucontext uc; | |
467 | struct target_fpstate fpstate; | |
468 | char retcode[8]; | |
469 | }; | |
470 | ||
471 | /* | |
472 | * Set up a signal frame. | |
473 | */ | |
474 | ||
475 | #define __put_user(x,ptr)\ | |
476 | ({\ | |
477 | int size = sizeof(*ptr);\ | |
478 | switch(size) {\ | |
479 | case 1:\ | |
480 | stb(ptr, (typeof(*ptr))(x));\ | |
481 | break;\ | |
482 | case 2:\ | |
483 | stw(ptr, (typeof(*ptr))(x));\ | |
484 | break;\ | |
485 | case 4:\ | |
486 | stl(ptr, (typeof(*ptr))(x));\ | |
487 | break;\ | |
488 | case 8:\ | |
489 | stq(ptr, (typeof(*ptr))(x));\ | |
490 | break;\ | |
491 | default:\ | |
492 | abort();\ | |
493 | }\ | |
494 | 0;\ | |
495 | }) | |
496 | ||
497 | #define get_user(val, ptr) (typeof(*ptr))(*(ptr)) | |
498 | ||
499 | ||
500 | #define __copy_to_user(dst, src, size)\ | |
501 | ({\ | |
502 | memcpy(dst, src, size);\ | |
503 | 0;\ | |
504 | }) | |
505 | ||
9de5e440 FB |
506 | static inline int copy_siginfo_to_user(target_siginfo_t *tinfo, |
507 | const target_siginfo_t *info) | |
66fb9763 | 508 | { |
9de5e440 | 509 | tswap_siginfo(tinfo, info); |
66fb9763 FB |
510 | return 0; |
511 | } | |
512 | ||
513 | /* XXX: save x87 state */ | |
514 | static int | |
515 | setup_sigcontext(struct target_sigcontext *sc, struct target_fpstate *fpstate, | |
516 | CPUX86State *env, unsigned long mask) | |
517 | { | |
518 | int err = 0; | |
519 | ||
520 | err |= __put_user(env->segs[R_GS], (unsigned int *)&sc->gs); | |
521 | err |= __put_user(env->segs[R_FS], (unsigned int *)&sc->fs); | |
522 | err |= __put_user(env->segs[R_ES], (unsigned int *)&sc->es); | |
523 | err |= __put_user(env->segs[R_DS], (unsigned int *)&sc->ds); | |
524 | err |= __put_user(env->regs[R_EDI], &sc->edi); | |
525 | err |= __put_user(env->regs[R_ESI], &sc->esi); | |
526 | err |= __put_user(env->regs[R_EBP], &sc->ebp); | |
527 | err |= __put_user(env->regs[R_ESP], &sc->esp); | |
528 | err |= __put_user(env->regs[R_EBX], &sc->ebx); | |
529 | err |= __put_user(env->regs[R_EDX], &sc->edx); | |
530 | err |= __put_user(env->regs[R_ECX], &sc->ecx); | |
531 | err |= __put_user(env->regs[R_EAX], &sc->eax); | |
66099dd9 FB |
532 | err |= __put_user(env->exception_index, &sc->trapno); |
533 | err |= __put_user(env->error_code, &sc->err); | |
66fb9763 FB |
534 | err |= __put_user(env->eip, &sc->eip); |
535 | err |= __put_user(env->segs[R_CS], (unsigned int *)&sc->cs); | |
536 | err |= __put_user(env->eflags, &sc->eflags); | |
537 | err |= __put_user(env->regs[R_ESP], &sc->esp_at_signal); | |
538 | err |= __put_user(env->segs[R_SS], (unsigned int *)&sc->ss); | |
ed2dcdf6 FB |
539 | |
540 | cpu_x86_fsave(env, (void *)fpstate, 1); | |
541 | fpstate->status = fpstate->sw; | |
542 | err |= __put_user(0xffff, &fpstate->magic); | |
543 | err |= __put_user(fpstate, &sc->fpstate); | |
544 | ||
66fb9763 FB |
545 | /* non-iBCS2 extensions.. */ |
546 | err |= __put_user(mask, &sc->oldmask); | |
c9087c2a | 547 | err |= __put_user(env->cr2, &sc->cr2); |
66fb9763 | 548 | return err; |
31e31b8a FB |
549 | } |
550 | ||
66fb9763 FB |
551 | /* |
552 | * Determine which stack to use.. | |
553 | */ | |
31e31b8a | 554 | |
66fb9763 FB |
555 | static inline void * |
556 | get_sigframe(struct emulated_sigaction *ka, CPUX86State *env, size_t frame_size) | |
31e31b8a | 557 | { |
66fb9763 FB |
558 | unsigned long esp; |
559 | ||
560 | /* Default to using normal stack */ | |
561 | esp = env->regs[R_ESP]; | |
562 | #if 0 | |
563 | /* This is the X/Open sanctioned signal stack switching. */ | |
564 | if (ka->sa.sa_flags & SA_ONSTACK) { | |
565 | if (sas_ss_flags(esp) == 0) | |
566 | esp = current->sas_ss_sp + current->sas_ss_size; | |
567 | } | |
568 | ||
569 | /* This is the legacy signal stack switching. */ | |
570 | else if ((regs->xss & 0xffff) != __USER_DS && | |
571 | !(ka->sa.sa_flags & SA_RESTORER) && | |
572 | ka->sa.sa_restorer) { | |
573 | esp = (unsigned long) ka->sa.sa_restorer; | |
574 | } | |
575 | #endif | |
576 | return (void *)((esp - frame_size) & -8ul); | |
577 | } | |
578 | ||
66fb9763 FB |
579 | static void setup_frame(int sig, struct emulated_sigaction *ka, |
580 | target_sigset_t *set, CPUX86State *env) | |
581 | { | |
582 | struct sigframe *frame; | |
583 | int err = 0; | |
584 | ||
585 | frame = get_sigframe(ka, env, sizeof(*frame)); | |
586 | ||
587 | #if 0 | |
588 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) | |
589 | goto give_sigsegv; | |
590 | #endif | |
591 | err |= __put_user((/*current->exec_domain | |
592 | && current->exec_domain->signal_invmap | |
593 | && sig < 32 | |
594 | ? current->exec_domain->signal_invmap[sig] | |
595 | : */ sig), | |
596 | &frame->sig); | |
597 | if (err) | |
598 | goto give_sigsegv; | |
599 | ||
600 | setup_sigcontext(&frame->sc, &frame->fpstate, env, set->sig[0]); | |
601 | if (err) | |
602 | goto give_sigsegv; | |
603 | ||
604 | if (TARGET_NSIG_WORDS > 1) { | |
605 | err |= __copy_to_user(frame->extramask, &set->sig[1], | |
606 | sizeof(frame->extramask)); | |
607 | } | |
608 | if (err) | |
609 | goto give_sigsegv; | |
610 | ||
611 | /* Set up to return from userspace. If provided, use a stub | |
612 | already in userspace. */ | |
613 | if (ka->sa.sa_flags & TARGET_SA_RESTORER) { | |
614 | err |= __put_user(ka->sa.sa_restorer, &frame->pretcode); | |
615 | } else { | |
616 | err |= __put_user(frame->retcode, &frame->pretcode); | |
617 | /* This is popl %eax ; movl $,%eax ; int $0x80 */ | |
618 | err |= __put_user(0xb858, (short *)(frame->retcode+0)); | |
619 | err |= __put_user(TARGET_NR_sigreturn, (int *)(frame->retcode+2)); | |
620 | err |= __put_user(0x80cd, (short *)(frame->retcode+6)); | |
621 | } | |
622 | ||
623 | if (err) | |
624 | goto give_sigsegv; | |
625 | ||
626 | /* Set up registers for signal handler */ | |
627 | env->regs[R_ESP] = (unsigned long) frame; | |
628 | env->eip = (unsigned long) ka->sa._sa_handler; | |
629 | ||
630 | cpu_x86_load_seg(env, R_DS, __USER_DS); | |
631 | cpu_x86_load_seg(env, R_ES, __USER_DS); | |
632 | cpu_x86_load_seg(env, R_SS, __USER_DS); | |
633 | cpu_x86_load_seg(env, R_CS, __USER_CS); | |
634 | env->eflags &= ~TF_MASK; | |
635 | ||
636 | return; | |
637 | ||
638 | give_sigsegv: | |
639 | if (sig == TARGET_SIGSEGV) | |
640 | ka->sa._sa_handler = TARGET_SIG_DFL; | |
641 | force_sig(TARGET_SIGSEGV /* , current */); | |
642 | } | |
643 | ||
9de5e440 FB |
644 | static void setup_rt_frame(int sig, struct emulated_sigaction *ka, |
645 | target_siginfo_t *info, | |
66fb9763 FB |
646 | target_sigset_t *set, CPUX86State *env) |
647 | { | |
648 | struct rt_sigframe *frame; | |
649 | int err = 0; | |
650 | ||
651 | frame = get_sigframe(ka, env, sizeof(*frame)); | |
652 | ||
653 | #if 0 | |
654 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) | |
655 | goto give_sigsegv; | |
656 | #endif | |
657 | ||
658 | err |= __put_user((/*current->exec_domain | |
659 | && current->exec_domain->signal_invmap | |
660 | && sig < 32 | |
661 | ? current->exec_domain->signal_invmap[sig] | |
662 | : */sig), | |
663 | &frame->sig); | |
664 | err |= __put_user((target_ulong)&frame->info, &frame->pinfo); | |
665 | err |= __put_user((target_ulong)&frame->uc, &frame->puc); | |
666 | err |= copy_siginfo_to_user(&frame->info, info); | |
667 | if (err) | |
668 | goto give_sigsegv; | |
31e31b8a | 669 | |
66fb9763 FB |
670 | /* Create the ucontext. */ |
671 | err |= __put_user(0, &frame->uc.uc_flags); | |
672 | err |= __put_user(0, &frame->uc.uc_link); | |
673 | err |= __put_user(/*current->sas_ss_sp*/ 0, &frame->uc.uc_stack.ss_sp); | |
674 | err |= __put_user(/* sas_ss_flags(regs->esp) */ 0, | |
675 | &frame->uc.uc_stack.ss_flags); | |
676 | err |= __put_user(/* current->sas_ss_size */ 0, &frame->uc.uc_stack.ss_size); | |
677 | err |= setup_sigcontext(&frame->uc.uc_mcontext, &frame->fpstate, | |
678 | env, set->sig[0]); | |
679 | err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); | |
680 | if (err) | |
681 | goto give_sigsegv; | |
31e31b8a | 682 | |
66fb9763 FB |
683 | /* Set up to return from userspace. If provided, use a stub |
684 | already in userspace. */ | |
685 | if (ka->sa.sa_flags & TARGET_SA_RESTORER) { | |
686 | err |= __put_user(ka->sa.sa_restorer, &frame->pretcode); | |
687 | } else { | |
688 | err |= __put_user(frame->retcode, &frame->pretcode); | |
689 | /* This is movl $,%eax ; int $0x80 */ | |
690 | err |= __put_user(0xb8, (char *)(frame->retcode+0)); | |
691 | err |= __put_user(TARGET_NR_rt_sigreturn, (int *)(frame->retcode+1)); | |
692 | err |= __put_user(0x80cd, (short *)(frame->retcode+5)); | |
693 | } | |
694 | ||
695 | if (err) | |
696 | goto give_sigsegv; | |
697 | ||
698 | /* Set up registers for signal handler */ | |
699 | env->regs[R_ESP] = (unsigned long) frame; | |
700 | env->eip = (unsigned long) ka->sa._sa_handler; | |
701 | ||
702 | cpu_x86_load_seg(env, R_DS, __USER_DS); | |
703 | cpu_x86_load_seg(env, R_ES, __USER_DS); | |
704 | cpu_x86_load_seg(env, R_SS, __USER_DS); | |
705 | cpu_x86_load_seg(env, R_CS, __USER_CS); | |
706 | env->eflags &= ~TF_MASK; | |
707 | ||
708 | return; | |
709 | ||
710 | give_sigsegv: | |
711 | if (sig == TARGET_SIGSEGV) | |
712 | ka->sa._sa_handler = TARGET_SIG_DFL; | |
713 | force_sig(TARGET_SIGSEGV /* , current */); | |
714 | } | |
715 | ||
716 | static int | |
717 | restore_sigcontext(CPUX86State *env, struct target_sigcontext *sc, int *peax) | |
718 | { | |
719 | unsigned int err = 0; | |
720 | ||
66fb9763 FB |
721 | cpu_x86_load_seg(env, R_GS, lduw(&sc->gs)); |
722 | cpu_x86_load_seg(env, R_FS, lduw(&sc->fs)); | |
723 | cpu_x86_load_seg(env, R_ES, lduw(&sc->es)); | |
724 | cpu_x86_load_seg(env, R_DS, lduw(&sc->ds)); | |
725 | ||
726 | env->regs[R_EDI] = ldl(&sc->edi); | |
727 | env->regs[R_ESI] = ldl(&sc->esi); | |
728 | env->regs[R_EBP] = ldl(&sc->ebp); | |
729 | env->regs[R_ESP] = ldl(&sc->esp); | |
730 | env->regs[R_EBX] = ldl(&sc->ebx); | |
731 | env->regs[R_EDX] = ldl(&sc->edx); | |
732 | env->regs[R_ECX] = ldl(&sc->ecx); | |
733 | env->eip = ldl(&sc->eip); | |
734 | ||
735 | cpu_x86_load_seg(env, R_CS, lduw(&sc->cs) | 3); | |
736 | cpu_x86_load_seg(env, R_SS, lduw(&sc->ss) | 3); | |
737 | ||
738 | { | |
739 | unsigned int tmpflags; | |
740 | tmpflags = ldl(&sc->eflags); | |
741 | env->eflags = (env->eflags & ~0x40DD5) | (tmpflags & 0x40DD5); | |
742 | // regs->orig_eax = -1; /* disable syscall checks */ | |
743 | } | |
744 | ||
66fb9763 FB |
745 | { |
746 | struct _fpstate * buf; | |
ed2dcdf6 | 747 | buf = (void *)ldl(&sc->fpstate); |
66fb9763 | 748 | if (buf) { |
ed2dcdf6 | 749 | #if 0 |
66fb9763 FB |
750 | if (verify_area(VERIFY_READ, buf, sizeof(*buf))) |
751 | goto badframe; | |
ed2dcdf6 FB |
752 | #endif |
753 | cpu_x86_frstor(env, (void *)buf, 1); | |
66fb9763 FB |
754 | } |
755 | } | |
ed2dcdf6 | 756 | |
66fb9763 FB |
757 | *peax = ldl(&sc->eax); |
758 | return err; | |
759 | #if 0 | |
760 | badframe: | |
761 | return 1; | |
762 | #endif | |
763 | } | |
764 | ||
765 | long do_sigreturn(CPUX86State *env) | |
766 | { | |
767 | struct sigframe *frame = (struct sigframe *)(env->regs[R_ESP] - 8); | |
768 | target_sigset_t target_set; | |
769 | sigset_t set; | |
770 | int eax, i; | |
771 | ||
447db213 FB |
772 | #if defined(DEBUG_SIGNAL) |
773 | fprintf(stderr, "do_sigreturn\n"); | |
774 | #endif | |
66fb9763 FB |
775 | /* set blocked signals */ |
776 | target_set.sig[0] = frame->sc.oldmask; | |
777 | for(i = 1; i < TARGET_NSIG_WORDS; i++) | |
778 | target_set.sig[i] = frame->extramask[i - 1]; | |
779 | ||
780 | target_to_host_sigset(&set, &target_set); | |
781 | sigprocmask(SIG_SETMASK, &set, NULL); | |
782 | ||
783 | /* restore registers */ | |
784 | if (restore_sigcontext(env, &frame->sc, &eax)) | |
785 | goto badframe; | |
786 | return eax; | |
787 | ||
788 | badframe: | |
789 | force_sig(TARGET_SIGSEGV); | |
790 | return 0; | |
791 | } | |
792 | ||
793 | long do_rt_sigreturn(CPUX86State *env) | |
794 | { | |
795 | struct rt_sigframe *frame = (struct rt_sigframe *)(env->regs[R_ESP] - 4); | |
796 | target_sigset_t target_set; | |
797 | sigset_t set; | |
798 | // stack_t st; | |
799 | int eax; | |
800 | ||
801 | #if 0 | |
802 | if (verify_area(VERIFY_READ, frame, sizeof(*frame))) | |
803 | goto badframe; | |
804 | #endif | |
805 | memcpy(&target_set, &frame->uc.uc_sigmask, sizeof(target_sigset_t)); | |
806 | ||
807 | target_to_host_sigset(&set, &target_set); | |
808 | sigprocmask(SIG_SETMASK, &set, NULL); | |
809 | ||
810 | if (restore_sigcontext(env, &frame->uc.uc_mcontext, &eax)) | |
811 | goto badframe; | |
812 | ||
813 | #if 0 | |
814 | if (__copy_from_user(&st, &frame->uc.uc_stack, sizeof(st))) | |
815 | goto badframe; | |
816 | /* It is more difficult to avoid calling this function than to | |
817 | call it and ignore errors. */ | |
818 | do_sigaltstack(&st, NULL, regs->esp); | |
819 | #endif | |
820 | return eax; | |
821 | ||
822 | badframe: | |
823 | force_sig(TARGET_SIGSEGV); | |
824 | return 0; | |
825 | } | |
826 | ||
b346ff46 FB |
827 | #else |
828 | ||
829 | static void setup_frame(int sig, struct emulated_sigaction *ka, | |
830 | target_sigset_t *set, CPUState *env) | |
831 | { | |
832 | fprintf(stderr, "setup_frame: not implemented\n"); | |
833 | } | |
834 | ||
835 | static void setup_rt_frame(int sig, struct emulated_sigaction *ka, | |
836 | target_siginfo_t *info, | |
837 | target_sigset_t *set, CPUState *env) | |
838 | { | |
839 | fprintf(stderr, "setup_rt_frame: not implemented\n"); | |
840 | } | |
841 | ||
842 | long do_sigreturn(CPUState *env) | |
843 | { | |
844 | fprintf(stderr, "do_sigreturn: not implemented\n"); | |
845 | return -ENOSYS; | |
846 | } | |
847 | ||
848 | long do_rt_sigreturn(CPUState *env) | |
849 | { | |
850 | fprintf(stderr, "do_rt_sigreturn: not implemented\n"); | |
851 | return -ENOSYS; | |
852 | } | |
853 | ||
66fb9763 FB |
854 | #endif |
855 | ||
856 | void process_pending_signals(void *cpu_env) | |
857 | { | |
858 | int sig; | |
859 | target_ulong handler; | |
9de5e440 FB |
860 | sigset_t set, old_set; |
861 | target_sigset_t target_old_set; | |
66fb9763 FB |
862 | struct emulated_sigaction *k; |
863 | struct sigqueue *q; | |
864 | ||
31e31b8a FB |
865 | if (!signal_pending) |
866 | return; | |
867 | ||
66fb9763 FB |
868 | k = sigact_table; |
869 | for(sig = 1; sig <= TARGET_NSIG; sig++) { | |
870 | if (k->pending) | |
31e31b8a | 871 | goto handle_signal; |
66fb9763 | 872 | k++; |
31e31b8a FB |
873 | } |
874 | /* if no signal is pending, just return */ | |
875 | signal_pending = 0; | |
876 | return; | |
66fb9763 | 877 | |
31e31b8a | 878 | handle_signal: |
66fb9763 | 879 | #ifdef DEBUG_SIGNAL |
bc8a22cc | 880 | fprintf(stderr, "qemu: process signal %d\n", sig); |
66fb9763 FB |
881 | #endif |
882 | /* dequeue signal */ | |
883 | q = k->first; | |
884 | k->first = q->next; | |
885 | if (!k->first) | |
886 | k->pending = 0; | |
887 | ||
888 | handler = k->sa._sa_handler; | |
889 | if (handler == TARGET_SIG_DFL) { | |
890 | /* default handler : ignore some signal. The other are fatal */ | |
891 | if (sig != TARGET_SIGCHLD && | |
892 | sig != TARGET_SIGURG && | |
893 | sig != TARGET_SIGWINCH) { | |
894 | force_sig(sig); | |
895 | } | |
896 | } else if (handler == TARGET_SIG_IGN) { | |
897 | /* ignore sig */ | |
898 | } else if (handler == TARGET_SIG_ERR) { | |
899 | force_sig(sig); | |
900 | } else { | |
9de5e440 FB |
901 | /* compute the blocked signals during the handler execution */ |
902 | target_to_host_sigset(&set, &k->sa.sa_mask); | |
903 | /* SA_NODEFER indicates that the current signal should not be | |
904 | blocked during the handler */ | |
905 | if (!(k->sa.sa_flags & TARGET_SA_NODEFER)) | |
906 | sigaddset(&set, target_to_host_signal(sig)); | |
907 | ||
908 | /* block signals in the handler using Linux */ | |
909 | sigprocmask(SIG_BLOCK, &set, &old_set); | |
910 | /* save the previous blocked signal state to restore it at the | |
911 | end of the signal execution (see do_sigreturn) */ | |
912 | host_to_target_sigset(&target_old_set, &old_set); | |
913 | ||
bc8a22cc FB |
914 | /* if the CPU is in VM86 mode, we restore the 32 bit values */ |
915 | #ifdef TARGET_I386 | |
916 | { | |
917 | CPUX86State *env = cpu_env; | |
918 | if (env->eflags & VM_MASK) | |
919 | save_v86_state(env); | |
920 | } | |
921 | #endif | |
9de5e440 | 922 | /* prepare the stack frame of the virtual CPU */ |
66fb9763 | 923 | if (k->sa.sa_flags & TARGET_SA_SIGINFO) |
9de5e440 | 924 | setup_rt_frame(sig, k, &q->info, &target_old_set, cpu_env); |
66fb9763 | 925 | else |
9de5e440 | 926 | setup_frame(sig, k, &target_old_set, cpu_env); |
66fb9763 FB |
927 | if (k->sa.sa_flags & TARGET_SA_RESETHAND) |
928 | k->sa._sa_handler = TARGET_SIG_DFL; | |
31e31b8a | 929 | } |
66fb9763 FB |
930 | if (q != &k->info) |
931 | free_sigqueue(q); | |
932 | } | |
31e31b8a FB |
933 | |
934 |