blob: e483d9c05689e393e2f21552fdf6fea949c12246 [file] [log] [blame]
Peter Maydellda30d852011-12-05 19:42:18 +00001/*
2 * Emulation of Linux signals : MIPS 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
35struct target_sigcontext {
36 uint32_t sc_regmask; /* Unused */
37 uint32_t sc_status;
38 uint64_t sc_pc;
39 uint64_t sc_regs[32];
40 uint64_t sc_fpregs[32];
41 uint32_t sc_ownedfp; /* Unused */
42 uint32_t sc_fpc_csr;
43 uint32_t sc_fpc_eir; /* Unused */
44 uint32_t sc_used_math;
45 uint32_t sc_dsp; /* dsp status, was sc_ssflags */
46 uint32_t pad0;
47 uint64_t sc_mdhi;
48 uint64_t sc_mdlo;
49 target_ulong sc_hi1; /* Was sc_cause */
50 target_ulong sc_lo1; /* Was sc_badvaddr */
51 target_ulong sc_hi2; /* Was sc_sigset[4] */
52 target_ulong sc_lo2;
53 target_ulong sc_hi3;
54 target_ulong sc_lo3;
55};
56
57struct sigframe {
58 uint32_t sf_ass[4]; /* argument save space for o32 */
59 uint32_t sf_code[2]; /* signal trampoline */
60 struct target_sigcontext sf_sc;
61 target_sigset_t sf_mask;
62};
63
64struct target_ucontext {
65 target_ulong tuc_flags;
66 target_ulong tuc_link;
67 target_stack_t tuc_stack;
68 target_ulong pad0;
69 struct target_sigcontext tuc_mcontext;
70 target_sigset_t tuc_sigmask;
71};
72
73struct target_rt_sigframe {
74 uint32_t rs_ass[4]; /* argument save space for o32 */
75 uint32_t rs_code[2]; /* signal trampoline */
76 struct target_siginfo rs_info;
77 struct target_ucontext rs_uc;
78};
79
80/* Install trampoline to jump back from signal handler */
81static inline int install_sigtramp(unsigned int *tramp, unsigned int syscall)
82{
83 int err;
84
85 /*
86 * Set up the return code ...
87 *
88 * li v0, __NR__foo_sigreturn
89 * syscall
90 */
91
92 err = __put_user(0x24020000 + syscall, tramp + 0);
93 err |= __put_user(0x0000000c , tramp + 1);
94 /* flush_cache_sigtramp((unsigned long) tramp); */
95 return err;
96}
97
98static inline int
99setup_sigcontext(CPUState *regs, struct target_sigcontext *sc)
100{
101 int err = 0;
102
103 err |= __put_user(regs->active_tc.PC, &sc->sc_pc);
104
105#define save_gp_reg(i) do { \
106 err |= __put_user(regs->active_tc.gpr[i], &sc->sc_regs[i]); \
107 } while(0)
108 __put_user(0, &sc->sc_regs[0]); save_gp_reg(1); save_gp_reg(2);
109 save_gp_reg(3); save_gp_reg(4); save_gp_reg(5); save_gp_reg(6);
110 save_gp_reg(7); save_gp_reg(8); save_gp_reg(9); save_gp_reg(10);
111 save_gp_reg(11); save_gp_reg(12); save_gp_reg(13); save_gp_reg(14);
112 save_gp_reg(15); save_gp_reg(16); save_gp_reg(17); save_gp_reg(18);
113 save_gp_reg(19); save_gp_reg(20); save_gp_reg(21); save_gp_reg(22);
114 save_gp_reg(23); save_gp_reg(24); save_gp_reg(25); save_gp_reg(26);
115 save_gp_reg(27); save_gp_reg(28); save_gp_reg(29); save_gp_reg(30);
116 save_gp_reg(31);
117#undef save_gp_reg
118
119 err |= __put_user(regs->active_tc.HI[0], &sc->sc_mdhi);
120 err |= __put_user(regs->active_tc.LO[0], &sc->sc_mdlo);
121
122 /* Not used yet, but might be useful if we ever have DSP suppport */
123#if 0
124 if (cpu_has_dsp) {
125 err |= __put_user(mfhi1(), &sc->sc_hi1);
126 err |= __put_user(mflo1(), &sc->sc_lo1);
127 err |= __put_user(mfhi2(), &sc->sc_hi2);
128 err |= __put_user(mflo2(), &sc->sc_lo2);
129 err |= __put_user(mfhi3(), &sc->sc_hi3);
130 err |= __put_user(mflo3(), &sc->sc_lo3);
131 err |= __put_user(rddsp(DSP_MASK), &sc->sc_dsp);
132 }
133 /* same with 64 bit */
134#ifdef CONFIG_64BIT
135 err |= __put_user(regs->hi, &sc->sc_hi[0]);
136 err |= __put_user(regs->lo, &sc->sc_lo[0]);
137 if (cpu_has_dsp) {
138 err |= __put_user(mfhi1(), &sc->sc_hi[1]);
139 err |= __put_user(mflo1(), &sc->sc_lo[1]);
140 err |= __put_user(mfhi2(), &sc->sc_hi[2]);
141 err |= __put_user(mflo2(), &sc->sc_lo[2]);
142 err |= __put_user(mfhi3(), &sc->sc_hi[3]);
143 err |= __put_user(mflo3(), &sc->sc_lo[3]);
144 err |= __put_user(rddsp(DSP_MASK), &sc->sc_dsp);
145 }
146#endif
147#endif
148
149#if 0
150 err |= __put_user(!!used_math(), &sc->sc_used_math);
151
152 if (!used_math())
153 goto out;
154
155 /*
156 * Save FPU state to signal context. Signal handler will "inherit"
157 * current FPU state.
158 */
159 preempt_disable();
160
161 if (!is_fpu_owner()) {
162 own_fpu();
163 restore_fp(current);
164 }
165 err |= save_fp_context(sc);
166
167 preempt_enable();
168 out:
169#endif
170 return err;
171}
172
173static inline int
174restore_sigcontext(CPUState *regs, struct target_sigcontext *sc)
175{
176 int err = 0;
177
178 err |= __get_user(regs->CP0_EPC, &sc->sc_pc);
179
180 err |= __get_user(regs->active_tc.HI[0], &sc->sc_mdhi);
181 err |= __get_user(regs->active_tc.LO[0], &sc->sc_mdlo);
182
183#define restore_gp_reg(i) do { \
184 err |= __get_user(regs->active_tc.gpr[i], &sc->sc_regs[i]); \
185 } while(0)
186 restore_gp_reg( 1); restore_gp_reg( 2); restore_gp_reg( 3);
187 restore_gp_reg( 4); restore_gp_reg( 5); restore_gp_reg( 6);
188 restore_gp_reg( 7); restore_gp_reg( 8); restore_gp_reg( 9);
189 restore_gp_reg(10); restore_gp_reg(11); restore_gp_reg(12);
190 restore_gp_reg(13); restore_gp_reg(14); restore_gp_reg(15);
191 restore_gp_reg(16); restore_gp_reg(17); restore_gp_reg(18);
192 restore_gp_reg(19); restore_gp_reg(20); restore_gp_reg(21);
193 restore_gp_reg(22); restore_gp_reg(23); restore_gp_reg(24);
194 restore_gp_reg(25); restore_gp_reg(26); restore_gp_reg(27);
195 restore_gp_reg(28); restore_gp_reg(29); restore_gp_reg(30);
196 restore_gp_reg(31);
197#undef restore_gp_reg
198
199#if 0
200 if (cpu_has_dsp) {
201 err |= __get_user(treg, &sc->sc_hi1); mthi1(treg);
202 err |= __get_user(treg, &sc->sc_lo1); mtlo1(treg);
203 err |= __get_user(treg, &sc->sc_hi2); mthi2(treg);
204 err |= __get_user(treg, &sc->sc_lo2); mtlo2(treg);
205 err |= __get_user(treg, &sc->sc_hi3); mthi3(treg);
206 err |= __get_user(treg, &sc->sc_lo3); mtlo3(treg);
207 err |= __get_user(treg, &sc->sc_dsp); wrdsp(treg, DSP_MASK);
208 }
209#ifdef CONFIG_64BIT
210 err |= __get_user(regs->hi, &sc->sc_hi[0]);
211 err |= __get_user(regs->lo, &sc->sc_lo[0]);
212 if (cpu_has_dsp) {
213 err |= __get_user(treg, &sc->sc_hi[1]); mthi1(treg);
214 err |= __get_user(treg, &sc->sc_lo[1]); mthi1(treg);
215 err |= __get_user(treg, &sc->sc_hi[2]); mthi2(treg);
216 err |= __get_user(treg, &sc->sc_lo[2]); mthi2(treg);
217 err |= __get_user(treg, &sc->sc_hi[3]); mthi3(treg);
218 err |= __get_user(treg, &sc->sc_lo[3]); mthi3(treg);
219 err |= __get_user(treg, &sc->sc_dsp); wrdsp(treg, DSP_MASK);
220 }
221#endif
222
223 err |= __get_user(used_math, &sc->sc_used_math);
224 conditional_used_math(used_math);
225
226 preempt_disable();
227
228 if (used_math()) {
229 /* restore fpu context if we have used it before */
230 own_fpu();
231 err |= restore_fp_context(sc);
232 } else {
233 /* signal handler may have used FPU. Give it up. */
234 lose_fpu();
235 }
236
237 preempt_enable();
238#endif
239 return err;
240}
241/*
242 * Determine which stack to use..
243 */
244static inline abi_ulong
245get_sigframe(struct target_sigaction *ka, CPUState *regs, size_t frame_size)
246{
247 unsigned long sp;
248
249 /* Default to using normal stack */
250 sp = regs->active_tc.gpr[29];
251
252 /*
253 * FPU emulator may have it's own trampoline active just
254 * above the user stack, 16-bytes before the next lowest
255 * 16 byte boundary. Try to avoid trashing it.
256 */
257 sp -= 32;
258
259 /* This is the X/Open sanctioned signal stack switching. */
260 if ((ka->sa_flags & TARGET_SA_ONSTACK) && (sas_ss_flags (sp) == 0)) {
261 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
262 }
263
264 return (sp - frame_size) & ~7;
265}
266
267/* compare linux/arch/mips/kernel/signal.c:setup_frame() */
268void setup_frame(int sig, struct target_sigaction * ka,
269 target_sigset_t *set, CPUState *regs)
270{
271 struct sigframe *frame;
272 abi_ulong frame_addr;
273 int i;
274
275 frame_addr = get_sigframe(ka, regs, sizeof(*frame));
276 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
277 goto give_sigsegv;
278
279 install_sigtramp(frame->sf_code, TARGET_NR_sigreturn);
280
281 if(setup_sigcontext(regs, &frame->sf_sc))
282 goto give_sigsegv;
283
284 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
285 if(__put_user(set->sig[i], &frame->sf_mask.sig[i]))
286 goto give_sigsegv;
287 }
288
289 /*
290 * Arguments to signal handler:
291 *
292 * a0 = signal number
293 * a1 = 0 (should be cause)
294 * a2 = pointer to struct sigcontext
295 *
296 * $25 and PC point to the signal handler, $29 points to the
297 * struct sigframe.
298 */
299 regs->active_tc.gpr[ 4] = sig;
300 regs->active_tc.gpr[ 5] = 0;
301 regs->active_tc.gpr[ 6] = frame_addr + offsetof(struct sigframe, sf_sc);
302 regs->active_tc.gpr[29] = frame_addr;
303 regs->active_tc.gpr[31] = frame_addr + offsetof(struct sigframe, sf_code);
304 /* The original kernel code sets CP0_EPC to the handler
305 * since it returns to userland using eret
306 * we cannot do this here, and we must set PC directly */
307 regs->active_tc.PC = regs->active_tc.gpr[25] = ka->_sa_handler;
308 unlock_user_struct(frame, frame_addr, 1);
309 return;
310
311give_sigsegv:
312 unlock_user_struct(frame, frame_addr, 1);
313 force_sig(TARGET_SIGSEGV/*, current*/);
314 return;
315}
316
317long do_sigreturn(CPUState *regs)
318{
319 struct sigframe *frame;
320 abi_ulong frame_addr;
321 sigset_t blocked;
322 target_sigset_t target_set;
323 int i;
324
325#if defined(DEBUG_SIGNAL)
326 fprintf(stderr, "do_sigreturn\n");
327#endif
328 frame_addr = regs->active_tc.gpr[29];
329 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
330 goto badframe;
331
332 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
333 if(__get_user(target_set.sig[i], &frame->sf_mask.sig[i]))
334 goto badframe;
335 }
336
337 target_to_host_sigset_internal(&blocked, &target_set);
338 sigprocmask(SIG_SETMASK, &blocked, NULL);
339
340 if (restore_sigcontext(regs, &frame->sf_sc))
341 goto badframe;
342
343#if 0
344 /*
345 * Don't let your children do this ...
346 */
347 __asm__ __volatile__(
348 "move\t$29, %0\n\t"
349 "j\tsyscall_exit"
350 :/* no outputs */
351 :"r" (&regs));
352 /* Unreached */
353#endif
354
355 regs->active_tc.PC = regs->CP0_EPC;
356 /* I am not sure this is right, but it seems to work
357 * maybe a problem with nested signals ? */
358 regs->CP0_EPC = 0;
359 return -TARGET_QEMU_ESIGRETURN;
360
361badframe:
362 force_sig(TARGET_SIGSEGV/*, current*/);
363 return 0;
364}
365
366void setup_rt_frame(int sig, struct target_sigaction *ka,
367 target_siginfo_t *info,
368 target_sigset_t *set, CPUState *env)
369{
370 struct target_rt_sigframe *frame;
371 abi_ulong frame_addr;
372 int i;
373
374 frame_addr = get_sigframe(ka, env, sizeof(*frame));
375 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
376 goto give_sigsegv;
377
378 install_sigtramp(frame->rs_code, TARGET_NR_rt_sigreturn);
379
380 copy_siginfo_to_user(&frame->rs_info, info);
381
382 __put_user(0, &frame->rs_uc.tuc_flags);
383 __put_user(0, &frame->rs_uc.tuc_link);
384 __put_user(target_sigaltstack_used.ss_sp, &frame->rs_uc.tuc_stack.ss_sp);
385 __put_user(target_sigaltstack_used.ss_size, &frame->rs_uc.tuc_stack.ss_size);
386 __put_user(sas_ss_flags(get_sp_from_cpustate(env)),
387 &frame->rs_uc.tuc_stack.ss_flags);
388
389 setup_sigcontext(env, &frame->rs_uc.tuc_mcontext);
390
391 for(i = 0; i < TARGET_NSIG_WORDS; i++) {
392 __put_user(set->sig[i], &frame->rs_uc.tuc_sigmask.sig[i]);
393 }
394
395 /*
396 * Arguments to signal handler:
397 *
398 * a0 = signal number
399 * a1 = pointer to struct siginfo
400 * a2 = pointer to struct ucontext
401 *
402 * $25 and PC point to the signal handler, $29 points to the
403 * struct sigframe.
404 */
405 env->active_tc.gpr[ 4] = sig;
406 env->active_tc.gpr[ 5] = frame_addr
407 + offsetof(struct target_rt_sigframe, rs_info);
408 env->active_tc.gpr[ 6] = frame_addr
409 + offsetof(struct target_rt_sigframe, rs_uc);
410 env->active_tc.gpr[29] = frame_addr;
411 env->active_tc.gpr[31] = frame_addr
412 + offsetof(struct target_rt_sigframe, rs_code);
413 /* The original kernel code sets CP0_EPC to the handler
414 * since it returns to userland using eret
415 * we cannot do this here, and we must set PC directly */
416 env->active_tc.PC = env->active_tc.gpr[25] = ka->_sa_handler;
417 unlock_user_struct(frame, frame_addr, 1);
418 return;
419
420give_sigsegv:
421 unlock_user_struct(frame, frame_addr, 1);
422 force_sig(TARGET_SIGSEGV/*, current*/);
423 return;
424}
425
426long do_rt_sigreturn(CPUState *env)
427{
428 struct target_rt_sigframe *frame;
429 abi_ulong frame_addr;
430 sigset_t blocked;
431
432#if defined(DEBUG_SIGNAL)
433 fprintf(stderr, "do_rt_sigreturn\n");
434#endif
435 frame_addr = env->active_tc.gpr[29];
436 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
437 goto badframe;
438
439 target_to_host_sigset(&blocked, &frame->rs_uc.tuc_sigmask);
440 sigprocmask(SIG_SETMASK, &blocked, NULL);
441
442 if (restore_sigcontext(env, &frame->rs_uc.tuc_mcontext))
443 goto badframe;
444
445 if (do_sigaltstack(frame_addr +
446 offsetof(struct target_rt_sigframe, rs_uc.tuc_stack),
447 0, get_sp_from_cpustate(env)) == -EFAULT)
448 goto badframe;
449
450 env->active_tc.PC = env->CP0_EPC;
451 /* I am not sure this is right, but it seems to work
452 * maybe a problem with nested signals ? */
453 env->CP0_EPC = 0;
454 return -TARGET_QEMU_ESIGRETURN;
455
456badframe:
457 force_sig(TARGET_SIGSEGV/*, current*/);
458 return 0;
459}
460