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 "target_signal.h"
22 #include "signal-common.h"
23 #include "linux-user/trace.h"
25 # if defined(TARGET_ABI_MIPSO32)
26 struct target_sigcontext
{
27 uint32_t sc_regmask
; /* Unused */
31 uint64_t sc_fpregs
[32];
32 uint32_t sc_ownedfp
; /* Unused */
34 uint32_t sc_fpc_eir
; /* Unused */
35 uint32_t sc_used_math
;
36 uint32_t sc_dsp
; /* dsp status, was sc_ssflags */
40 target_ulong sc_hi1
; /* Was sc_cause */
41 target_ulong sc_lo1
; /* Was sc_badvaddr */
42 target_ulong sc_hi2
; /* Was sc_sigset[4] */
47 # else /* N32 || N64 */
48 struct target_sigcontext
{
50 uint64_t sc_fpregs
[32];
61 uint32_t sc_used_math
;
68 uint32_t sf_ass
[4]; /* argument save space for o32 */
69 uint32_t sf_code
[2]; /* signal trampoline */
70 struct target_sigcontext sf_sc
;
71 target_sigset_t sf_mask
;
74 struct target_ucontext
{
75 target_ulong tuc_flags
;
76 target_ulong tuc_link
;
77 target_stack_t tuc_stack
;
79 struct target_sigcontext tuc_mcontext
;
80 target_sigset_t tuc_sigmask
;
83 struct target_rt_sigframe
{
84 uint32_t rs_ass
[4]; /* argument save space for o32 */
85 uint32_t rs_code
[2]; /* signal trampoline */
86 struct target_siginfo rs_info
;
87 struct target_ucontext rs_uc
;
90 /* Install trampoline to jump back from signal handler */
91 static inline int install_sigtramp(unsigned int *tramp
, unsigned int syscall
)
96 * Set up the return code ...
98 * li v0, __NR__foo_sigreturn
102 __put_user(0x24020000 + syscall
, tramp
+ 0);
103 __put_user(0x0000000c , tramp
+ 1);
107 static inline void setup_sigcontext(CPUMIPSState
*regs
,
108 struct target_sigcontext
*sc
)
112 __put_user(exception_resume_pc(regs
), &sc
->sc_pc
);
113 regs
->hflags
&= ~MIPS_HFLAG_BMASK
;
115 __put_user(0, &sc
->sc_regs
[0]);
116 for (i
= 1; i
< 32; ++i
) {
117 __put_user(regs
->active_tc
.gpr
[i
], &sc
->sc_regs
[i
]);
120 __put_user(regs
->active_tc
.HI
[0], &sc
->sc_mdhi
);
121 __put_user(regs
->active_tc
.LO
[0], &sc
->sc_mdlo
);
123 /* Rather than checking for dsp existence, always copy. The storage
124 would just be garbage otherwise. */
125 __put_user(regs
->active_tc
.HI
[1], &sc
->sc_hi1
);
126 __put_user(regs
->active_tc
.HI
[2], &sc
->sc_hi2
);
127 __put_user(regs
->active_tc
.HI
[3], &sc
->sc_hi3
);
128 __put_user(regs
->active_tc
.LO
[1], &sc
->sc_lo1
);
129 __put_user(regs
->active_tc
.LO
[2], &sc
->sc_lo2
);
130 __put_user(regs
->active_tc
.LO
[3], &sc
->sc_lo3
);
132 uint32_t dsp
= cpu_rddsp(0x3ff, regs
);
133 __put_user(dsp
, &sc
->sc_dsp
);
136 __put_user(1, &sc
->sc_used_math
);
138 for (i
= 0; i
< 32; ++i
) {
139 __put_user(regs
->active_fpu
.fpr
[i
].d
, &sc
->sc_fpregs
[i
]);
144 restore_sigcontext(CPUMIPSState
*regs
, struct target_sigcontext
*sc
)
148 __get_user(regs
->CP0_EPC
, &sc
->sc_pc
);
150 __get_user(regs
->active_tc
.HI
[0], &sc
->sc_mdhi
);
151 __get_user(regs
->active_tc
.LO
[0], &sc
->sc_mdlo
);
153 for (i
= 1; i
< 32; ++i
) {
154 __get_user(regs
->active_tc
.gpr
[i
], &sc
->sc_regs
[i
]);
157 __get_user(regs
->active_tc
.HI
[1], &sc
->sc_hi1
);
158 __get_user(regs
->active_tc
.HI
[2], &sc
->sc_hi2
);
159 __get_user(regs
->active_tc
.HI
[3], &sc
->sc_hi3
);
160 __get_user(regs
->active_tc
.LO
[1], &sc
->sc_lo1
);
161 __get_user(regs
->active_tc
.LO
[2], &sc
->sc_lo2
);
162 __get_user(regs
->active_tc
.LO
[3], &sc
->sc_lo3
);
165 __get_user(dsp
, &sc
->sc_dsp
);
166 cpu_wrdsp(dsp
, 0x3ff, regs
);
169 for (i
= 0; i
< 32; ++i
) {
170 __get_user(regs
->active_fpu
.fpr
[i
].d
, &sc
->sc_fpregs
[i
]);
175 * Determine which stack to use..
177 static inline abi_ulong
178 get_sigframe(struct target_sigaction
*ka
, CPUMIPSState
*regs
, size_t frame_size
)
183 * FPU emulator may have its own trampoline active just
184 * above the user stack, 16-bytes before the next lowest
185 * 16 byte boundary. Try to avoid trashing it.
187 sp
= target_sigsp(get_sp_from_cpustate(regs
) - 32, ka
);
189 return (sp
- frame_size
) & ~7;
192 static void mips_set_hflags_isa_mode_from_pc(CPUMIPSState
*env
)
194 if (env
->insn_flags
& (ASE_MIPS16
| ASE_MICROMIPS
)) {
195 env
->hflags
&= ~MIPS_HFLAG_M16
;
196 env
->hflags
|= (env
->active_tc
.PC
& 1) << MIPS_HFLAG_M16_SHIFT
;
197 env
->active_tc
.PC
&= ~(target_ulong
) 1;
201 # if defined(TARGET_ABI_MIPSO32)
202 /* compare linux/arch/mips/kernel/signal.c:setup_frame() */
203 void setup_frame(int sig
, struct target_sigaction
* ka
,
204 target_sigset_t
*set
, CPUMIPSState
*regs
)
206 struct sigframe
*frame
;
207 abi_ulong frame_addr
;
210 frame_addr
= get_sigframe(ka
, regs
, sizeof(*frame
));
211 trace_user_setup_frame(regs
, frame_addr
);
212 if (!lock_user_struct(VERIFY_WRITE
, frame
, frame_addr
, 0)) {
216 install_sigtramp(frame
->sf_code
, TARGET_NR_sigreturn
);
218 setup_sigcontext(regs
, &frame
->sf_sc
);
220 for(i
= 0; i
< TARGET_NSIG_WORDS
; i
++) {
221 __put_user(set
->sig
[i
], &frame
->sf_mask
.sig
[i
]);
225 * Arguments to signal handler:
228 * a1 = 0 (should be cause)
229 * a2 = pointer to struct sigcontext
231 * $25 and PC point to the signal handler, $29 points to the
234 regs
->active_tc
.gpr
[ 4] = sig
;
235 regs
->active_tc
.gpr
[ 5] = 0;
236 regs
->active_tc
.gpr
[ 6] = frame_addr
+ offsetof(struct sigframe
, sf_sc
);
237 regs
->active_tc
.gpr
[29] = frame_addr
;
238 regs
->active_tc
.gpr
[31] = frame_addr
+ offsetof(struct sigframe
, sf_code
);
239 /* The original kernel code sets CP0_EPC to the handler
240 * since it returns to userland using eret
241 * we cannot do this here, and we must set PC directly */
242 regs
->active_tc
.PC
= regs
->active_tc
.gpr
[25] = ka
->_sa_handler
;
243 mips_set_hflags_isa_mode_from_pc(regs
);
244 unlock_user_struct(frame
, frame_addr
, 1);
251 long do_sigreturn(CPUMIPSState
*regs
)
253 struct sigframe
*frame
;
254 abi_ulong frame_addr
;
256 target_sigset_t target_set
;
259 frame_addr
= regs
->active_tc
.gpr
[29];
260 trace_user_do_sigreturn(regs
, frame_addr
);
261 if (!lock_user_struct(VERIFY_READ
, frame
, frame_addr
, 1))
264 for(i
= 0; i
< TARGET_NSIG_WORDS
; i
++) {
265 __get_user(target_set
.sig
[i
], &frame
->sf_mask
.sig
[i
]);
268 target_to_host_sigset_internal(&blocked
, &target_set
);
269 set_sigmask(&blocked
);
271 restore_sigcontext(regs
, &frame
->sf_sc
);
275 * Don't let your children do this ...
277 __asm__
__volatile__(
285 regs
->active_tc
.PC
= regs
->CP0_EPC
;
286 mips_set_hflags_isa_mode_from_pc(regs
);
287 /* I am not sure this is right, but it seems to work
288 * maybe a problem with nested signals ? */
290 return -TARGET_QEMU_ESIGRETURN
;
293 force_sig(TARGET_SIGSEGV
);
294 return -TARGET_QEMU_ESIGRETURN
;
298 void setup_rt_frame(int sig
, struct target_sigaction
*ka
,
299 target_siginfo_t
*info
,
300 target_sigset_t
*set
, CPUMIPSState
*env
)
302 struct target_rt_sigframe
*frame
;
303 abi_ulong frame_addr
;
306 frame_addr
= get_sigframe(ka
, env
, sizeof(*frame
));
307 trace_user_setup_rt_frame(env
, frame_addr
);
308 if (!lock_user_struct(VERIFY_WRITE
, frame
, frame_addr
, 0)) {
312 install_sigtramp(frame
->rs_code
, TARGET_NR_rt_sigreturn
);
314 tswap_siginfo(&frame
->rs_info
, info
);
316 __put_user(0, &frame
->rs_uc
.tuc_flags
);
317 __put_user(0, &frame
->rs_uc
.tuc_link
);
318 target_save_altstack(&frame
->rs_uc
.tuc_stack
, env
);
320 setup_sigcontext(env
, &frame
->rs_uc
.tuc_mcontext
);
322 for(i
= 0; i
< TARGET_NSIG_WORDS
; i
++) {
323 __put_user(set
->sig
[i
], &frame
->rs_uc
.tuc_sigmask
.sig
[i
]);
327 * Arguments to signal handler:
330 * a1 = pointer to siginfo_t
331 * a2 = pointer to ucontext_t
333 * $25 and PC point to the signal handler, $29 points to the
336 env
->active_tc
.gpr
[ 4] = sig
;
337 env
->active_tc
.gpr
[ 5] = frame_addr
338 + offsetof(struct target_rt_sigframe
, rs_info
);
339 env
->active_tc
.gpr
[ 6] = frame_addr
340 + offsetof(struct target_rt_sigframe
, rs_uc
);
341 env
->active_tc
.gpr
[29] = frame_addr
;
342 env
->active_tc
.gpr
[31] = frame_addr
343 + offsetof(struct target_rt_sigframe
, rs_code
);
344 /* The original kernel code sets CP0_EPC to the handler
345 * since it returns to userland using eret
346 * we cannot do this here, and we must set PC directly */
347 env
->active_tc
.PC
= env
->active_tc
.gpr
[25] = ka
->_sa_handler
;
348 mips_set_hflags_isa_mode_from_pc(env
);
349 unlock_user_struct(frame
, frame_addr
, 1);
353 unlock_user_struct(frame
, frame_addr
, 1);
357 long do_rt_sigreturn(CPUMIPSState
*env
)
359 struct target_rt_sigframe
*frame
;
360 abi_ulong frame_addr
;
363 frame_addr
= env
->active_tc
.gpr
[29];
364 trace_user_do_rt_sigreturn(env
, frame_addr
);
365 if (!lock_user_struct(VERIFY_READ
, frame
, frame_addr
, 1)) {
369 target_to_host_sigset(&blocked
, &frame
->rs_uc
.tuc_sigmask
);
370 set_sigmask(&blocked
);
372 restore_sigcontext(env
, &frame
->rs_uc
.tuc_mcontext
);
374 if (do_sigaltstack(frame_addr
+
375 offsetof(struct target_rt_sigframe
, rs_uc
.tuc_stack
),
376 0, get_sp_from_cpustate(env
)) == -EFAULT
)
379 env
->active_tc
.PC
= env
->CP0_EPC
;
380 mips_set_hflags_isa_mode_from_pc(env
);
381 /* I am not sure this is right, but it seems to work
382 * maybe a problem with nested signals ? */
384 return -TARGET_QEMU_ESIGRETURN
;
387 force_sig(TARGET_SIGSEGV
);
388 return -TARGET_QEMU_ESIGRETURN
;