2 * Emulation of Linux signals
4 * Copyright (c) 2003 Fabrice Bellard
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.
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.
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/>.
19 #include "qemu/osdep.h"
21 #include "signal-common.h"
22 #include "linux-user/trace.h"
24 # if defined(TARGET_ABI_MIPSO32)
25 struct target_sigcontext
{
26 uint32_t sc_regmask
; /* Unused */
30 uint64_t sc_fpregs
[32];
31 uint32_t sc_ownedfp
; /* Unused */
33 uint32_t sc_fpc_eir
; /* Unused */
34 uint32_t sc_used_math
;
35 uint32_t sc_dsp
; /* dsp status, was sc_ssflags */
39 target_ulong sc_hi1
; /* Was sc_cause */
40 target_ulong sc_lo1
; /* Was sc_badvaddr */
41 target_ulong sc_hi2
; /* Was sc_sigset[4] */
46 # else /* N32 || N64 */
47 struct target_sigcontext
{
49 uint64_t sc_fpregs
[32];
60 uint32_t sc_used_math
;
67 uint32_t sf_ass
[4]; /* argument save space for o32 */
68 uint32_t sf_code
[2]; /* signal trampoline */
69 struct target_sigcontext sf_sc
;
70 target_sigset_t sf_mask
;
73 struct target_ucontext
{
76 target_stack_t tuc_stack
;
77 struct target_sigcontext tuc_mcontext
;
78 target_sigset_t tuc_sigmask
;
81 struct target_rt_sigframe
{
82 uint32_t rs_ass
[4]; /* argument save space for o32 */
83 uint32_t rs_code
[2]; /* signal trampoline */
84 struct target_siginfo rs_info
;
85 struct target_ucontext rs_uc
;
88 /* Install trampoline to jump back from signal handler */
89 static inline int install_sigtramp(unsigned int *tramp
, unsigned int syscall
)
94 * Set up the return code ...
96 * li v0, __NR__foo_sigreturn
100 __put_user(0x24020000 + syscall
, tramp
+ 0);
101 __put_user(0x0000000c , tramp
+ 1);
105 static inline void setup_sigcontext(CPUMIPSState
*regs
,
106 struct target_sigcontext
*sc
)
110 __put_user(exception_resume_pc(regs
), &sc
->sc_pc
);
111 regs
->hflags
&= ~MIPS_HFLAG_BMASK
;
113 __put_user(0, &sc
->sc_regs
[0]);
114 for (i
= 1; i
< 32; ++i
) {
115 __put_user(regs
->active_tc
.gpr
[i
], &sc
->sc_regs
[i
]);
118 __put_user(regs
->active_tc
.HI
[0], &sc
->sc_mdhi
);
119 __put_user(regs
->active_tc
.LO
[0], &sc
->sc_mdlo
);
121 /* Rather than checking for dsp existence, always copy. The storage
122 would just be garbage otherwise. */
123 __put_user(regs
->active_tc
.HI
[1], &sc
->sc_hi1
);
124 __put_user(regs
->active_tc
.HI
[2], &sc
->sc_hi2
);
125 __put_user(regs
->active_tc
.HI
[3], &sc
->sc_hi3
);
126 __put_user(regs
->active_tc
.LO
[1], &sc
->sc_lo1
);
127 __put_user(regs
->active_tc
.LO
[2], &sc
->sc_lo2
);
128 __put_user(regs
->active_tc
.LO
[3], &sc
->sc_lo3
);
130 uint32_t dsp
= cpu_rddsp(0x3ff, regs
);
131 __put_user(dsp
, &sc
->sc_dsp
);
134 __put_user(1, &sc
->sc_used_math
);
136 for (i
= 0; i
< 32; ++i
) {
137 __put_user(regs
->active_fpu
.fpr
[i
].d
, &sc
->sc_fpregs
[i
]);
142 restore_sigcontext(CPUMIPSState
*regs
, struct target_sigcontext
*sc
)
146 __get_user(regs
->CP0_EPC
, &sc
->sc_pc
);
148 __get_user(regs
->active_tc
.HI
[0], &sc
->sc_mdhi
);
149 __get_user(regs
->active_tc
.LO
[0], &sc
->sc_mdlo
);
151 for (i
= 1; i
< 32; ++i
) {
152 __get_user(regs
->active_tc
.gpr
[i
], &sc
->sc_regs
[i
]);
155 __get_user(regs
->active_tc
.HI
[1], &sc
->sc_hi1
);
156 __get_user(regs
->active_tc
.HI
[2], &sc
->sc_hi2
);
157 __get_user(regs
->active_tc
.HI
[3], &sc
->sc_hi3
);
158 __get_user(regs
->active_tc
.LO
[1], &sc
->sc_lo1
);
159 __get_user(regs
->active_tc
.LO
[2], &sc
->sc_lo2
);
160 __get_user(regs
->active_tc
.LO
[3], &sc
->sc_lo3
);
163 __get_user(dsp
, &sc
->sc_dsp
);
164 cpu_wrdsp(dsp
, 0x3ff, regs
);
167 for (i
= 0; i
< 32; ++i
) {
168 __get_user(regs
->active_fpu
.fpr
[i
].d
, &sc
->sc_fpregs
[i
]);
173 * Determine which stack to use..
175 static inline abi_ulong
176 get_sigframe(struct target_sigaction
*ka
, CPUMIPSState
*regs
, size_t frame_size
)
181 * FPU emulator may have its own trampoline active just
182 * above the user stack, 16-bytes before the next lowest
183 * 16 byte boundary. Try to avoid trashing it.
185 sp
= target_sigsp(get_sp_from_cpustate(regs
) - 32, ka
);
187 return (sp
- frame_size
) & ~7;
190 static void mips_set_hflags_isa_mode_from_pc(CPUMIPSState
*env
)
192 if (env
->insn_flags
& (ASE_MIPS16
| ASE_MICROMIPS
)) {
193 env
->hflags
&= ~MIPS_HFLAG_M16
;
194 env
->hflags
|= (env
->active_tc
.PC
& 1) << MIPS_HFLAG_M16_SHIFT
;
195 env
->active_tc
.PC
&= ~(target_ulong
) 1;
199 # if defined(TARGET_ABI_MIPSO32)
200 /* compare linux/arch/mips/kernel/signal.c:setup_frame() */
201 void setup_frame(int sig
, struct target_sigaction
* ka
,
202 target_sigset_t
*set
, CPUMIPSState
*regs
)
204 struct sigframe
*frame
;
205 abi_ulong frame_addr
;
208 frame_addr
= get_sigframe(ka
, regs
, sizeof(*frame
));
209 trace_user_setup_frame(regs
, frame_addr
);
210 if (!lock_user_struct(VERIFY_WRITE
, frame
, frame_addr
, 0)) {
214 install_sigtramp(frame
->sf_code
, TARGET_NR_sigreturn
);
216 setup_sigcontext(regs
, &frame
->sf_sc
);
218 for(i
= 0; i
< TARGET_NSIG_WORDS
; i
++) {
219 __put_user(set
->sig
[i
], &frame
->sf_mask
.sig
[i
]);
223 * Arguments to signal handler:
226 * a1 = 0 (should be cause)
227 * a2 = pointer to struct sigcontext
229 * $25 and PC point to the signal handler, $29 points to the
232 regs
->active_tc
.gpr
[ 4] = sig
;
233 regs
->active_tc
.gpr
[ 5] = 0;
234 regs
->active_tc
.gpr
[ 6] = frame_addr
+ offsetof(struct sigframe
, sf_sc
);
235 regs
->active_tc
.gpr
[29] = frame_addr
;
236 regs
->active_tc
.gpr
[31] = frame_addr
+ offsetof(struct sigframe
, sf_code
);
237 /* The original kernel code sets CP0_EPC to the handler
238 * since it returns to userland using eret
239 * we cannot do this here, and we must set PC directly */
240 regs
->active_tc
.PC
= regs
->active_tc
.gpr
[25] = ka
->_sa_handler
;
241 mips_set_hflags_isa_mode_from_pc(regs
);
242 unlock_user_struct(frame
, frame_addr
, 1);
249 long do_sigreturn(CPUMIPSState
*regs
)
251 struct sigframe
*frame
;
252 abi_ulong frame_addr
;
254 target_sigset_t target_set
;
257 frame_addr
= regs
->active_tc
.gpr
[29];
258 trace_user_do_sigreturn(regs
, frame_addr
);
259 if (!lock_user_struct(VERIFY_READ
, frame
, frame_addr
, 1))
262 for(i
= 0; i
< TARGET_NSIG_WORDS
; i
++) {
263 __get_user(target_set
.sig
[i
], &frame
->sf_mask
.sig
[i
]);
266 target_to_host_sigset_internal(&blocked
, &target_set
);
267 set_sigmask(&blocked
);
269 restore_sigcontext(regs
, &frame
->sf_sc
);
273 * Don't let your children do this ...
275 __asm__
__volatile__(
283 regs
->active_tc
.PC
= regs
->CP0_EPC
;
284 mips_set_hflags_isa_mode_from_pc(regs
);
285 /* I am not sure this is right, but it seems to work
286 * maybe a problem with nested signals ? */
288 return -TARGET_QEMU_ESIGRETURN
;
291 force_sig(TARGET_SIGSEGV
);
292 return -TARGET_QEMU_ESIGRETURN
;
296 void setup_rt_frame(int sig
, struct target_sigaction
*ka
,
297 target_siginfo_t
*info
,
298 target_sigset_t
*set
, CPUMIPSState
*env
)
300 struct target_rt_sigframe
*frame
;
301 abi_ulong frame_addr
;
304 frame_addr
= get_sigframe(ka
, env
, sizeof(*frame
));
305 trace_user_setup_rt_frame(env
, frame_addr
);
306 if (!lock_user_struct(VERIFY_WRITE
, frame
, frame_addr
, 0)) {
310 install_sigtramp(frame
->rs_code
, TARGET_NR_rt_sigreturn
);
312 tswap_siginfo(&frame
->rs_info
, info
);
314 __put_user(0, &frame
->rs_uc
.tuc_flags
);
315 __put_user(0, &frame
->rs_uc
.tuc_link
);
316 target_save_altstack(&frame
->rs_uc
.tuc_stack
, env
);
318 setup_sigcontext(env
, &frame
->rs_uc
.tuc_mcontext
);
320 for(i
= 0; i
< TARGET_NSIG_WORDS
; i
++) {
321 __put_user(set
->sig
[i
], &frame
->rs_uc
.tuc_sigmask
.sig
[i
]);
325 * Arguments to signal handler:
328 * a1 = pointer to siginfo_t
329 * a2 = pointer to ucontext_t
331 * $25 and PC point to the signal handler, $29 points to the
334 env
->active_tc
.gpr
[ 4] = sig
;
335 env
->active_tc
.gpr
[ 5] = frame_addr
336 + offsetof(struct target_rt_sigframe
, rs_info
);
337 env
->active_tc
.gpr
[ 6] = frame_addr
338 + offsetof(struct target_rt_sigframe
, rs_uc
);
339 env
->active_tc
.gpr
[29] = frame_addr
;
340 env
->active_tc
.gpr
[31] = frame_addr
341 + offsetof(struct target_rt_sigframe
, rs_code
);
342 /* The original kernel code sets CP0_EPC to the handler
343 * since it returns to userland using eret
344 * we cannot do this here, and we must set PC directly */
345 env
->active_tc
.PC
= env
->active_tc
.gpr
[25] = ka
->_sa_handler
;
346 mips_set_hflags_isa_mode_from_pc(env
);
347 unlock_user_struct(frame
, frame_addr
, 1);
351 unlock_user_struct(frame
, frame_addr
, 1);
355 long do_rt_sigreturn(CPUMIPSState
*env
)
357 struct target_rt_sigframe
*frame
;
358 abi_ulong frame_addr
;
361 frame_addr
= env
->active_tc
.gpr
[29];
362 trace_user_do_rt_sigreturn(env
, frame_addr
);
363 if (!lock_user_struct(VERIFY_READ
, frame
, frame_addr
, 1)) {
367 target_to_host_sigset(&blocked
, &frame
->rs_uc
.tuc_sigmask
);
368 set_sigmask(&blocked
);
370 restore_sigcontext(env
, &frame
->rs_uc
.tuc_mcontext
);
372 if (do_sigaltstack(frame_addr
+
373 offsetof(struct target_rt_sigframe
, rs_uc
.tuc_stack
),
374 0, get_sp_from_cpustate(env
)) == -EFAULT
)
377 env
->active_tc
.PC
= env
->CP0_EPC
;
378 mips_set_hflags_isa_mode_from_pc(env
);
379 /* I am not sure this is right, but it seems to work
380 * maybe a problem with nested signals ? */
382 return -TARGET_QEMU_ESIGRETURN
;
385 force_sig(TARGET_SIGSEGV
);
386 return -TARGET_QEMU_ESIGRETURN
;