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 struct target_sigcontext
{
32 abi_long sc_fpregs
[32];
34 abi_ulong sc_fp_control
;
35 abi_ulong sc_reserved1
;
36 abi_ulong sc_reserved2
;
39 abi_ulong sc_traparg_a0
;
40 abi_ulong sc_traparg_a1
;
41 abi_ulong sc_traparg_a2
;
42 abi_ulong sc_fp_trap_pc
;
43 abi_ulong sc_fp_trigger_sum
;
44 abi_ulong sc_fp_trigger_inst
;
47 struct target_ucontext
{
50 abi_ulong tuc_osf_sigmask
;
51 target_stack_t tuc_stack
;
52 struct target_sigcontext tuc_mcontext
;
53 target_sigset_t tuc_sigmask
;
56 struct target_sigframe
{
57 struct target_sigcontext sc
;
58 unsigned int retcode
[3];
61 struct target_rt_sigframe
{
62 target_siginfo_t info
;
63 struct target_ucontext uc
;
64 unsigned int retcode
[3];
67 #define INSN_MOV_R30_R16 0x47fe0410
68 #define INSN_LDI_R0 0x201f0000
69 #define INSN_CALLSYS 0x00000083
71 static void setup_sigcontext(struct target_sigcontext
*sc
, CPUAlphaState
*env
,
72 abi_ulong frame_addr
, target_sigset_t
*set
)
76 __put_user(on_sig_stack(frame_addr
), &sc
->sc_onstack
);
77 __put_user(set
->sig
[0], &sc
->sc_mask
);
78 __put_user(env
->pc
, &sc
->sc_pc
);
79 __put_user(8, &sc
->sc_ps
);
81 for (i
= 0; i
< 31; ++i
) {
82 __put_user(env
->ir
[i
], &sc
->sc_regs
[i
]);
84 __put_user(0, &sc
->sc_regs
[31]);
86 for (i
= 0; i
< 31; ++i
) {
87 __put_user(env
->fir
[i
], &sc
->sc_fpregs
[i
]);
89 __put_user(0, &sc
->sc_fpregs
[31]);
90 __put_user(cpu_alpha_load_fpcr(env
), &sc
->sc_fpcr
);
92 __put_user(0, &sc
->sc_traparg_a0
); /* FIXME */
93 __put_user(0, &sc
->sc_traparg_a1
); /* FIXME */
94 __put_user(0, &sc
->sc_traparg_a2
); /* FIXME */
97 static void restore_sigcontext(CPUAlphaState
*env
,
98 struct target_sigcontext
*sc
)
103 __get_user(env
->pc
, &sc
->sc_pc
);
105 for (i
= 0; i
< 31; ++i
) {
106 __get_user(env
->ir
[i
], &sc
->sc_regs
[i
]);
108 for (i
= 0; i
< 31; ++i
) {
109 __get_user(env
->fir
[i
], &sc
->sc_fpregs
[i
]);
112 __get_user(fpcr
, &sc
->sc_fpcr
);
113 cpu_alpha_store_fpcr(env
, fpcr
);
116 static inline abi_ulong
get_sigframe(struct target_sigaction
*sa
,
118 unsigned long framesize
)
122 sp
= target_sigsp(get_sp_from_cpustate(env
), sa
);
124 return (sp
- framesize
) & -32;
127 void setup_frame(int sig
, struct target_sigaction
*ka
,
128 target_sigset_t
*set
, CPUAlphaState
*env
)
130 abi_ulong frame_addr
, r26
;
131 struct target_sigframe
*frame
;
134 frame_addr
= get_sigframe(ka
, env
, sizeof(*frame
));
135 trace_user_setup_frame(env
, frame_addr
);
136 if (!lock_user_struct(VERIFY_WRITE
, frame
, frame_addr
, 0)) {
140 setup_sigcontext(&frame
->sc
, env
, frame_addr
, set
);
142 if (ka
->sa_restorer
) {
143 r26
= ka
->sa_restorer
;
145 __put_user(INSN_MOV_R30_R16
, &frame
->retcode
[0]);
146 __put_user(INSN_LDI_R0
+ TARGET_NR_sigreturn
,
148 __put_user(INSN_CALLSYS
, &frame
->retcode
[2]);
150 r26
= frame_addr
+ offsetof(struct target_sigframe
, retcode
);
153 unlock_user_struct(frame
, frame_addr
, 1);
161 env
->ir
[IR_RA
] = r26
;
162 env
->ir
[IR_PV
] = env
->pc
= ka
->_sa_handler
;
163 env
->ir
[IR_A0
] = sig
;
165 env
->ir
[IR_A2
] = frame_addr
+ offsetof(struct target_sigframe
, sc
);
166 env
->ir
[IR_SP
] = frame_addr
;
169 void setup_rt_frame(int sig
, struct target_sigaction
*ka
,
170 target_siginfo_t
*info
,
171 target_sigset_t
*set
, CPUAlphaState
*env
)
173 abi_ulong frame_addr
, r26
;
174 struct target_rt_sigframe
*frame
;
177 frame_addr
= get_sigframe(ka
, env
, sizeof(*frame
));
178 trace_user_setup_rt_frame(env
, frame_addr
);
179 if (!lock_user_struct(VERIFY_WRITE
, frame
, frame_addr
, 0)) {
183 tswap_siginfo(&frame
->info
, info
);
185 __put_user(0, &frame
->uc
.tuc_flags
);
186 __put_user(0, &frame
->uc
.tuc_link
);
187 __put_user(set
->sig
[0], &frame
->uc
.tuc_osf_sigmask
);
189 target_save_altstack(&frame
->uc
.tuc_stack
, env
);
191 setup_sigcontext(&frame
->uc
.tuc_mcontext
, env
, frame_addr
, set
);
192 for (i
= 0; i
< TARGET_NSIG_WORDS
; ++i
) {
193 __put_user(set
->sig
[i
], &frame
->uc
.tuc_sigmask
.sig
[i
]);
196 if (ka
->sa_restorer
) {
197 r26
= ka
->sa_restorer
;
199 __put_user(INSN_MOV_R30_R16
, &frame
->retcode
[0]);
200 __put_user(INSN_LDI_R0
+ TARGET_NR_rt_sigreturn
,
202 __put_user(INSN_CALLSYS
, &frame
->retcode
[2]);
204 r26
= frame_addr
+ offsetof(struct target_sigframe
, retcode
);
213 env
->ir
[IR_RA
] = r26
;
214 env
->ir
[IR_PV
] = env
->pc
= ka
->_sa_handler
;
215 env
->ir
[IR_A0
] = sig
;
216 env
->ir
[IR_A1
] = frame_addr
+ offsetof(struct target_rt_sigframe
, info
);
217 env
->ir
[IR_A2
] = frame_addr
+ offsetof(struct target_rt_sigframe
, uc
);
218 env
->ir
[IR_SP
] = frame_addr
;
221 long do_sigreturn(CPUAlphaState
*env
)
223 struct target_sigcontext
*sc
;
224 abi_ulong sc_addr
= env
->ir
[IR_A0
];
225 target_sigset_t target_set
;
228 if (!lock_user_struct(VERIFY_READ
, sc
, sc_addr
, 1)) {
232 target_sigemptyset(&target_set
);
233 __get_user(target_set
.sig
[0], &sc
->sc_mask
);
235 target_to_host_sigset_internal(&set
, &target_set
);
238 restore_sigcontext(env
, sc
);
239 unlock_user_struct(sc
, sc_addr
, 0);
240 return -TARGET_QEMU_ESIGRETURN
;
243 force_sig(TARGET_SIGSEGV
);
244 return -TARGET_QEMU_ESIGRETURN
;
247 long do_rt_sigreturn(CPUAlphaState
*env
)
249 abi_ulong frame_addr
= env
->ir
[IR_A0
];
250 struct target_rt_sigframe
*frame
;
253 trace_user_do_rt_sigreturn(env
, frame_addr
);
254 if (!lock_user_struct(VERIFY_READ
, frame
, frame_addr
, 1)) {
257 target_to_host_sigset(&set
, &frame
->uc
.tuc_sigmask
);
260 restore_sigcontext(env
, &frame
->uc
.tuc_mcontext
);
261 if (do_sigaltstack(frame_addr
+ offsetof(struct target_rt_sigframe
,
263 0, env
->ir
[IR_SP
]) == -EFAULT
) {
267 unlock_user_struct(frame
, frame_addr
, 0);
268 return -TARGET_QEMU_ESIGRETURN
;
272 unlock_user_struct(frame
, frame_addr
, 0);
273 force_sig(TARGET_SIGSEGV
);
274 return -TARGET_QEMU_ESIGRETURN
;