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
{
74 target_ulong tuc_flags
;
75 target_ulong tuc_link
;
76 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 inline int install_sigtramp(unsigned int *tramp
, unsigned int syscall
)
95 * Set up the return code ...
97 * li v0, __NR__foo_sigreturn
101 __put_user(0x24020000 + syscall
, tramp
+ 0);
102 __put_user(0x0000000c , tramp
+ 1);
106 static inline void setup_sigcontext(CPUMIPSState
*regs
,
107 struct target_sigcontext
*sc
)
111 __put_user(exception_resume_pc(regs
), &sc
->sc_pc
);
112 regs
->hflags
&= ~MIPS_HFLAG_BMASK
;
114 __put_user(0, &sc
->sc_regs
[0]);
115 for (i
= 1; i
< 32; ++i
) {
116 __put_user(regs
->active_tc
.gpr
[i
], &sc
->sc_regs
[i
]);
119 __put_user(regs
->active_tc
.HI
[0], &sc
->sc_mdhi
);
120 __put_user(regs
->active_tc
.LO
[0], &sc
->sc_mdlo
);
122 /* Rather than checking for dsp existence, always copy. The storage
123 would just be garbage otherwise. */
124 __put_user(regs
->active_tc
.HI
[1], &sc
->sc_hi1
);
125 __put_user(regs
->active_tc
.HI
[2], &sc
->sc_hi2
);
126 __put_user(regs
->active_tc
.HI
[3], &sc
->sc_hi3
);
127 __put_user(regs
->active_tc
.LO
[1], &sc
->sc_lo1
);
128 __put_user(regs
->active_tc
.LO
[2], &sc
->sc_lo2
);
129 __put_user(regs
->active_tc
.LO
[3], &sc
->sc_lo3
);
131 uint32_t dsp
= cpu_rddsp(0x3ff, regs
);
132 __put_user(dsp
, &sc
->sc_dsp
);
135 __put_user(1, &sc
->sc_used_math
);
137 for (i
= 0; i
< 32; ++i
) {
138 __put_user(regs
->active_fpu
.fpr
[i
].d
, &sc
->sc_fpregs
[i
]);
143 restore_sigcontext(CPUMIPSState
*regs
, struct target_sigcontext
*sc
)
147 __get_user(regs
->CP0_EPC
, &sc
->sc_pc
);
149 __get_user(regs
->active_tc
.HI
[0], &sc
->sc_mdhi
);
150 __get_user(regs
->active_tc
.LO
[0], &sc
->sc_mdlo
);
152 for (i
= 1; i
< 32; ++i
) {
153 __get_user(regs
->active_tc
.gpr
[i
], &sc
->sc_regs
[i
]);
156 __get_user(regs
->active_tc
.HI
[1], &sc
->sc_hi1
);
157 __get_user(regs
->active_tc
.HI
[2], &sc
->sc_hi2
);
158 __get_user(regs
->active_tc
.HI
[3], &sc
->sc_hi3
);
159 __get_user(regs
->active_tc
.LO
[1], &sc
->sc_lo1
);
160 __get_user(regs
->active_tc
.LO
[2], &sc
->sc_lo2
);
161 __get_user(regs
->active_tc
.LO
[3], &sc
->sc_lo3
);
164 __get_user(dsp
, &sc
->sc_dsp
);
165 cpu_wrdsp(dsp
, 0x3ff, regs
);
168 for (i
= 0; i
< 32; ++i
) {
169 __get_user(regs
->active_fpu
.fpr
[i
].d
, &sc
->sc_fpregs
[i
]);
174 * Determine which stack to use..
176 static inline abi_ulong
177 get_sigframe(struct target_sigaction
*ka
, CPUMIPSState
*regs
, size_t frame_size
)
182 * FPU emulator may have its own trampoline active just
183 * above the user stack, 16-bytes before the next lowest
184 * 16 byte boundary. Try to avoid trashing it.
186 sp
= target_sigsp(get_sp_from_cpustate(regs
) - 32, ka
);
188 return (sp
- frame_size
) & ~7;
191 static void mips_set_hflags_isa_mode_from_pc(CPUMIPSState
*env
)
193 if (env
->insn_flags
& (ASE_MIPS16
| ASE_MICROMIPS
)) {
194 env
->hflags
&= ~MIPS_HFLAG_M16
;
195 env
->hflags
|= (env
->active_tc
.PC
& 1) << MIPS_HFLAG_M16_SHIFT
;
196 env
->active_tc
.PC
&= ~(target_ulong
) 1;
200 # if defined(TARGET_ABI_MIPSO32)
201 /* compare linux/arch/mips/kernel/signal.c:setup_frame() */
202 void setup_frame(int sig
, struct target_sigaction
* ka
,
203 target_sigset_t
*set
, CPUMIPSState
*regs
)
205 struct sigframe
*frame
;
206 abi_ulong frame_addr
;
209 frame_addr
= get_sigframe(ka
, regs
, sizeof(*frame
));
210 trace_user_setup_frame(regs
, frame_addr
);
211 if (!lock_user_struct(VERIFY_WRITE
, frame
, frame_addr
, 0)) {
215 install_sigtramp(frame
->sf_code
, TARGET_NR_sigreturn
);
217 setup_sigcontext(regs
, &frame
->sf_sc
);
219 for(i
= 0; i
< TARGET_NSIG_WORDS
; i
++) {
220 __put_user(set
->sig
[i
], &frame
->sf_mask
.sig
[i
]);
224 * Arguments to signal handler:
227 * a1 = 0 (should be cause)
228 * a2 = pointer to struct sigcontext
230 * $25 and PC point to the signal handler, $29 points to the
233 regs
->active_tc
.gpr
[ 4] = sig
;
234 regs
->active_tc
.gpr
[ 5] = 0;
235 regs
->active_tc
.gpr
[ 6] = frame_addr
+ offsetof(struct sigframe
, sf_sc
);
236 regs
->active_tc
.gpr
[29] = frame_addr
;
237 regs
->active_tc
.gpr
[31] = frame_addr
+ offsetof(struct sigframe
, sf_code
);
238 /* The original kernel code sets CP0_EPC to the handler
239 * since it returns to userland using eret
240 * we cannot do this here, and we must set PC directly */
241 regs
->active_tc
.PC
= regs
->active_tc
.gpr
[25] = ka
->_sa_handler
;
242 mips_set_hflags_isa_mode_from_pc(regs
);
243 unlock_user_struct(frame
, frame_addr
, 1);
250 long do_sigreturn(CPUMIPSState
*regs
)
252 struct sigframe
*frame
;
253 abi_ulong frame_addr
;
255 target_sigset_t target_set
;
258 frame_addr
= regs
->active_tc
.gpr
[29];
259 trace_user_do_sigreturn(regs
, frame_addr
);
260 if (!lock_user_struct(VERIFY_READ
, frame
, frame_addr
, 1))
263 for(i
= 0; i
< TARGET_NSIG_WORDS
; i
++) {
264 __get_user(target_set
.sig
[i
], &frame
->sf_mask
.sig
[i
]);
267 target_to_host_sigset_internal(&blocked
, &target_set
);
268 set_sigmask(&blocked
);
270 restore_sigcontext(regs
, &frame
->sf_sc
);
274 * Don't let your children do this ...
276 __asm__
__volatile__(
284 regs
->active_tc
.PC
= regs
->CP0_EPC
;
285 mips_set_hflags_isa_mode_from_pc(regs
);
286 /* I am not sure this is right, but it seems to work
287 * maybe a problem with nested signals ? */
289 return -TARGET_QEMU_ESIGRETURN
;
292 force_sig(TARGET_SIGSEGV
);
293 return -TARGET_QEMU_ESIGRETURN
;
297 void setup_rt_frame(int sig
, struct target_sigaction
*ka
,
298 target_siginfo_t
*info
,
299 target_sigset_t
*set
, CPUMIPSState
*env
)
301 struct target_rt_sigframe
*frame
;
302 abi_ulong frame_addr
;
305 frame_addr
= get_sigframe(ka
, env
, sizeof(*frame
));
306 trace_user_setup_rt_frame(env
, frame_addr
);
307 if (!lock_user_struct(VERIFY_WRITE
, frame
, frame_addr
, 0)) {
311 install_sigtramp(frame
->rs_code
, TARGET_NR_rt_sigreturn
);
313 tswap_siginfo(&frame
->rs_info
, info
);
315 __put_user(0, &frame
->rs_uc
.tuc_flags
);
316 __put_user(0, &frame
->rs_uc
.tuc_link
);
317 target_save_altstack(&frame
->rs_uc
.tuc_stack
, env
);
319 setup_sigcontext(env
, &frame
->rs_uc
.tuc_mcontext
);
321 for(i
= 0; i
< TARGET_NSIG_WORDS
; i
++) {
322 __put_user(set
->sig
[i
], &frame
->rs_uc
.tuc_sigmask
.sig
[i
]);
326 * Arguments to signal handler:
329 * a1 = pointer to siginfo_t
330 * a2 = pointer to ucontext_t
332 * $25 and PC point to the signal handler, $29 points to the
335 env
->active_tc
.gpr
[ 4] = sig
;
336 env
->active_tc
.gpr
[ 5] = frame_addr
337 + offsetof(struct target_rt_sigframe
, rs_info
);
338 env
->active_tc
.gpr
[ 6] = frame_addr
339 + offsetof(struct target_rt_sigframe
, rs_uc
);
340 env
->active_tc
.gpr
[29] = frame_addr
;
341 env
->active_tc
.gpr
[31] = frame_addr
342 + offsetof(struct target_rt_sigframe
, rs_code
);
343 /* The original kernel code sets CP0_EPC to the handler
344 * since it returns to userland using eret
345 * we cannot do this here, and we must set PC directly */
346 env
->active_tc
.PC
= env
->active_tc
.gpr
[25] = ka
->_sa_handler
;
347 mips_set_hflags_isa_mode_from_pc(env
);
348 unlock_user_struct(frame
, frame_addr
, 1);
352 unlock_user_struct(frame
, frame_addr
, 1);
356 long do_rt_sigreturn(CPUMIPSState
*env
)
358 struct target_rt_sigframe
*frame
;
359 abi_ulong frame_addr
;
362 frame_addr
= env
->active_tc
.gpr
[29];
363 trace_user_do_rt_sigreturn(env
, frame_addr
);
364 if (!lock_user_struct(VERIFY_READ
, frame
, frame_addr
, 1)) {
368 target_to_host_sigset(&blocked
, &frame
->rs_uc
.tuc_sigmask
);
369 set_sigmask(&blocked
);
371 restore_sigcontext(env
, &frame
->rs_uc
.tuc_mcontext
);
373 if (do_sigaltstack(frame_addr
+
374 offsetof(struct target_rt_sigframe
, rs_uc
.tuc_stack
),
375 0, get_sp_from_cpustate(env
)) == -EFAULT
)
378 env
->active_tc
.PC
= env
->CP0_EPC
;
379 mips_set_hflags_isa_mode_from_pc(env
);
380 /* I am not sure this is right, but it seems to work
381 * maybe a problem with nested signals ? */
383 return -TARGET_QEMU_ESIGRETURN
;
386 force_sig(TARGET_SIGSEGV
);
387 return -TARGET_QEMU_ESIGRETURN
;