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 "user-internals.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
{
77 target_stack_t tuc_stack
;
78 struct target_sigcontext tuc_mcontext
;
79 target_sigset_t tuc_sigmask
;
82 struct target_rt_sigframe
{
83 uint32_t rs_ass
[4]; /* argument save space for o32 */
84 uint32_t rs_code
[2]; /* signal trampoline */
85 struct target_siginfo rs_info
;
86 struct target_ucontext rs_uc
;
89 /* Install trampoline to jump back from signal handler */
90 static void install_sigtramp(uint32_t *tramp
, unsigned int syscall
)
93 * Set up the return code ...
95 * li v0, __NR__foo_sigreturn
99 __put_user(0x24020000 + syscall
, tramp
+ 0);
100 __put_user(0x0000000c , tramp
+ 1);
103 static inline void setup_sigcontext(CPUMIPSState
*regs
,
104 struct target_sigcontext
*sc
)
108 __put_user(exception_resume_pc(regs
), &sc
->sc_pc
);
109 regs
->hflags
&= ~MIPS_HFLAG_BMASK
;
111 __put_user(0, &sc
->sc_regs
[0]);
112 for (i
= 1; i
< 32; ++i
) {
113 __put_user(regs
->active_tc
.gpr
[i
], &sc
->sc_regs
[i
]);
116 __put_user(regs
->active_tc
.HI
[0], &sc
->sc_mdhi
);
117 __put_user(regs
->active_tc
.LO
[0], &sc
->sc_mdlo
);
119 /* Rather than checking for dsp existence, always copy. The storage
120 would just be garbage otherwise. */
121 __put_user(regs
->active_tc
.HI
[1], &sc
->sc_hi1
);
122 __put_user(regs
->active_tc
.HI
[2], &sc
->sc_hi2
);
123 __put_user(regs
->active_tc
.HI
[3], &sc
->sc_hi3
);
124 __put_user(regs
->active_tc
.LO
[1], &sc
->sc_lo1
);
125 __put_user(regs
->active_tc
.LO
[2], &sc
->sc_lo2
);
126 __put_user(regs
->active_tc
.LO
[3], &sc
->sc_lo3
);
128 uint32_t dsp
= cpu_rddsp(0x3ff, regs
);
129 __put_user(dsp
, &sc
->sc_dsp
);
132 __put_user(1, &sc
->sc_used_math
);
134 for (i
= 0; i
< 32; ++i
) {
135 __put_user(regs
->active_fpu
.fpr
[i
].d
, &sc
->sc_fpregs
[i
]);
140 restore_sigcontext(CPUMIPSState
*regs
, struct target_sigcontext
*sc
)
144 __get_user(regs
->CP0_EPC
, &sc
->sc_pc
);
146 __get_user(regs
->active_tc
.HI
[0], &sc
->sc_mdhi
);
147 __get_user(regs
->active_tc
.LO
[0], &sc
->sc_mdlo
);
149 for (i
= 1; i
< 32; ++i
) {
150 __get_user(regs
->active_tc
.gpr
[i
], &sc
->sc_regs
[i
]);
153 __get_user(regs
->active_tc
.HI
[1], &sc
->sc_hi1
);
154 __get_user(regs
->active_tc
.HI
[2], &sc
->sc_hi2
);
155 __get_user(regs
->active_tc
.HI
[3], &sc
->sc_hi3
);
156 __get_user(regs
->active_tc
.LO
[1], &sc
->sc_lo1
);
157 __get_user(regs
->active_tc
.LO
[2], &sc
->sc_lo2
);
158 __get_user(regs
->active_tc
.LO
[3], &sc
->sc_lo3
);
161 __get_user(dsp
, &sc
->sc_dsp
);
162 cpu_wrdsp(dsp
, 0x3ff, regs
);
165 for (i
= 0; i
< 32; ++i
) {
166 __get_user(regs
->active_fpu
.fpr
[i
].d
, &sc
->sc_fpregs
[i
]);
171 * Determine which stack to use..
173 static inline abi_ulong
174 get_sigframe(struct target_sigaction
*ka
, CPUMIPSState
*regs
, size_t frame_size
)
179 * FPU emulator may have its own trampoline active just
180 * above the user stack, 16-bytes before the next lowest
181 * 16 byte boundary. Try to avoid trashing it.
183 sp
= target_sigsp(get_sp_from_cpustate(regs
) - 32, ka
);
185 return (sp
- frame_size
) & ~7;
188 static void mips_set_hflags_isa_mode_from_pc(CPUMIPSState
*env
)
190 if (env
->insn_flags
& (ASE_MIPS16
| ASE_MICROMIPS
)) {
191 env
->hflags
&= ~MIPS_HFLAG_M16
;
192 env
->hflags
|= (env
->active_tc
.PC
& 1) << MIPS_HFLAG_M16_SHIFT
;
193 env
->active_tc
.PC
&= ~(target_ulong
) 1;
197 # if defined(TARGET_ABI_MIPSO32)
198 /* compare linux/arch/mips/kernel/signal.c:setup_frame() */
199 void setup_frame(int sig
, struct target_sigaction
* ka
,
200 target_sigset_t
*set
, CPUMIPSState
*regs
)
202 struct sigframe
*frame
;
203 abi_ulong frame_addr
;
206 frame_addr
= get_sigframe(ka
, regs
, sizeof(*frame
));
207 trace_user_setup_frame(regs
, frame_addr
);
208 if (!lock_user_struct(VERIFY_WRITE
, frame
, frame_addr
, 0)) {
212 setup_sigcontext(regs
, &frame
->sf_sc
);
214 for(i
= 0; i
< TARGET_NSIG_WORDS
; i
++) {
215 __put_user(set
->sig
[i
], &frame
->sf_mask
.sig
[i
]);
219 * Arguments to signal handler:
222 * a1 = 0 (should be cause)
223 * a2 = pointer to struct sigcontext
225 * $25 and PC point to the signal handler, $29 points to the
228 regs
->active_tc
.gpr
[ 4] = sig
;
229 regs
->active_tc
.gpr
[ 5] = 0;
230 regs
->active_tc
.gpr
[ 6] = frame_addr
+ offsetof(struct sigframe
, sf_sc
);
231 regs
->active_tc
.gpr
[29] = frame_addr
;
232 regs
->active_tc
.gpr
[31] = default_sigreturn
;
233 /* The original kernel code sets CP0_EPC to the handler
234 * since it returns to userland using eret
235 * we cannot do this here, and we must set PC directly */
236 regs
->active_tc
.PC
= regs
->active_tc
.gpr
[25] = ka
->_sa_handler
;
237 mips_set_hflags_isa_mode_from_pc(regs
);
238 unlock_user_struct(frame
, frame_addr
, 1);
245 long do_sigreturn(CPUMIPSState
*regs
)
247 struct sigframe
*frame
;
248 abi_ulong frame_addr
;
250 target_sigset_t target_set
;
253 frame_addr
= regs
->active_tc
.gpr
[29];
254 trace_user_do_sigreturn(regs
, frame_addr
);
255 if (!lock_user_struct(VERIFY_READ
, frame
, frame_addr
, 1))
258 for(i
= 0; i
< TARGET_NSIG_WORDS
; i
++) {
259 __get_user(target_set
.sig
[i
], &frame
->sf_mask
.sig
[i
]);
262 target_to_host_sigset_internal(&blocked
, &target_set
);
263 set_sigmask(&blocked
);
265 restore_sigcontext(regs
, &frame
->sf_sc
);
269 * Don't let your children do this ...
271 __asm__
__volatile__(
279 regs
->active_tc
.PC
= regs
->CP0_EPC
;
280 mips_set_hflags_isa_mode_from_pc(regs
);
281 /* I am not sure this is right, but it seems to work
282 * maybe a problem with nested signals ? */
284 return -QEMU_ESIGRETURN
;
287 force_sig(TARGET_SIGSEGV
);
288 return -QEMU_ESIGRETURN
;
292 void setup_rt_frame(int sig
, struct target_sigaction
*ka
,
293 target_siginfo_t
*info
,
294 target_sigset_t
*set
, CPUMIPSState
*env
)
296 struct target_rt_sigframe
*frame
;
297 abi_ulong frame_addr
;
300 frame_addr
= get_sigframe(ka
, env
, sizeof(*frame
));
301 trace_user_setup_rt_frame(env
, frame_addr
);
302 if (!lock_user_struct(VERIFY_WRITE
, frame
, frame_addr
, 0)) {
306 tswap_siginfo(&frame
->rs_info
, info
);
308 __put_user(0, &frame
->rs_uc
.tuc_flags
);
309 __put_user(0, &frame
->rs_uc
.tuc_link
);
310 target_save_altstack(&frame
->rs_uc
.tuc_stack
, env
);
312 setup_sigcontext(env
, &frame
->rs_uc
.tuc_mcontext
);
314 for(i
= 0; i
< TARGET_NSIG_WORDS
; i
++) {
315 __put_user(set
->sig
[i
], &frame
->rs_uc
.tuc_sigmask
.sig
[i
]);
319 * Arguments to signal handler:
322 * a1 = pointer to siginfo_t
323 * a2 = pointer to ucontext_t
325 * $25 and PC point to the signal handler, $29 points to the
328 env
->active_tc
.gpr
[ 4] = sig
;
329 env
->active_tc
.gpr
[ 5] = frame_addr
330 + offsetof(struct target_rt_sigframe
, rs_info
);
331 env
->active_tc
.gpr
[ 6] = frame_addr
332 + offsetof(struct target_rt_sigframe
, rs_uc
);
333 env
->active_tc
.gpr
[29] = frame_addr
;
334 env
->active_tc
.gpr
[31] = default_rt_sigreturn
;
337 * The original kernel code sets CP0_EPC to the handler
338 * since it returns to userland using eret
339 * we cannot do this here, and we must set PC directly
341 env
->active_tc
.PC
= env
->active_tc
.gpr
[25] = ka
->_sa_handler
;
342 mips_set_hflags_isa_mode_from_pc(env
);
343 unlock_user_struct(frame
, frame_addr
, 1);
347 unlock_user_struct(frame
, frame_addr
, 1);
351 long do_rt_sigreturn(CPUMIPSState
*env
)
353 struct target_rt_sigframe
*frame
;
354 abi_ulong frame_addr
;
357 frame_addr
= env
->active_tc
.gpr
[29];
358 trace_user_do_rt_sigreturn(env
, frame_addr
);
359 if (!lock_user_struct(VERIFY_READ
, frame
, frame_addr
, 1)) {
363 target_to_host_sigset(&blocked
, &frame
->rs_uc
.tuc_sigmask
);
364 set_sigmask(&blocked
);
366 restore_sigcontext(env
, &frame
->rs_uc
.tuc_mcontext
);
367 target_restore_altstack(&frame
->rs_uc
.tuc_stack
, env
);
369 env
->active_tc
.PC
= env
->CP0_EPC
;
370 mips_set_hflags_isa_mode_from_pc(env
);
371 /* I am not sure this is right, but it seems to work
372 * maybe a problem with nested signals ? */
374 return -QEMU_ESIGRETURN
;
377 force_sig(TARGET_SIGSEGV
);
378 return -QEMU_ESIGRETURN
;
381 void setup_sigtramp(abi_ulong sigtramp_page
)
383 uint32_t *tramp
= lock_user(VERIFY_WRITE
, sigtramp_page
, 2 * 8, 0);
384 assert(tramp
!= NULL
);
386 #ifdef TARGET_ARCH_HAS_SETUP_FRAME
387 default_sigreturn
= sigtramp_page
;
388 install_sigtramp(tramp
, TARGET_NR_sigreturn
);
391 default_rt_sigreturn
= sigtramp_page
+ 8;
392 install_sigtramp(tramp
+ 2, TARGET_NR_rt_sigreturn
);
394 unlock_user(tramp
, sigtramp_page
, 2 * 8);