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 struct target_sigcontext
{
31 abi_long sc_fpregs
[32];
33 abi_ulong sc_fp_control
;
34 abi_ulong sc_reserved1
;
35 abi_ulong sc_reserved2
;
38 abi_ulong sc_traparg_a0
;
39 abi_ulong sc_traparg_a1
;
40 abi_ulong sc_traparg_a2
;
41 abi_ulong sc_fp_trap_pc
;
42 abi_ulong sc_fp_trigger_sum
;
43 abi_ulong sc_fp_trigger_inst
;
46 struct target_ucontext
{
49 abi_ulong tuc_osf_sigmask
;
50 target_stack_t tuc_stack
;
51 struct target_sigcontext tuc_mcontext
;
52 target_sigset_t tuc_sigmask
;
55 struct target_sigframe
{
56 struct target_sigcontext sc
;
57 unsigned int retcode
[3];
60 struct target_rt_sigframe
{
61 target_siginfo_t info
;
62 struct target_ucontext uc
;
63 unsigned int retcode
[3];
66 #define INSN_MOV_R30_R16 0x47fe0410
67 #define INSN_LDI_R0 0x201f0000
68 #define INSN_CALLSYS 0x00000083
70 static void setup_sigcontext(struct target_sigcontext
*sc
, CPUAlphaState
*env
,
71 abi_ulong frame_addr
, target_sigset_t
*set
)
75 __put_user(on_sig_stack(frame_addr
), &sc
->sc_onstack
);
76 __put_user(set
->sig
[0], &sc
->sc_mask
);
77 __put_user(env
->pc
, &sc
->sc_pc
);
78 __put_user(8, &sc
->sc_ps
);
80 for (i
= 0; i
< 31; ++i
) {
81 __put_user(env
->ir
[i
], &sc
->sc_regs
[i
]);
83 __put_user(0, &sc
->sc_regs
[31]);
85 for (i
= 0; i
< 31; ++i
) {
86 __put_user(env
->fir
[i
], &sc
->sc_fpregs
[i
]);
88 __put_user(0, &sc
->sc_fpregs
[31]);
89 __put_user(cpu_alpha_load_fpcr(env
), &sc
->sc_fpcr
);
91 __put_user(0, &sc
->sc_traparg_a0
); /* FIXME */
92 __put_user(0, &sc
->sc_traparg_a1
); /* FIXME */
93 __put_user(0, &sc
->sc_traparg_a2
); /* FIXME */
96 static void restore_sigcontext(CPUAlphaState
*env
,
97 struct target_sigcontext
*sc
)
102 __get_user(env
->pc
, &sc
->sc_pc
);
104 for (i
= 0; i
< 31; ++i
) {
105 __get_user(env
->ir
[i
], &sc
->sc_regs
[i
]);
107 for (i
= 0; i
< 31; ++i
) {
108 __get_user(env
->fir
[i
], &sc
->sc_fpregs
[i
]);
111 __get_user(fpcr
, &sc
->sc_fpcr
);
112 cpu_alpha_store_fpcr(env
, fpcr
);
115 static inline abi_ulong
get_sigframe(struct target_sigaction
*sa
,
117 unsigned long framesize
)
121 sp
= target_sigsp(get_sp_from_cpustate(env
), sa
);
123 return (sp
- framesize
) & -32;
126 void setup_frame(int sig
, struct target_sigaction
*ka
,
127 target_sigset_t
*set
, CPUAlphaState
*env
)
129 abi_ulong frame_addr
, r26
;
130 struct target_sigframe
*frame
;
133 frame_addr
= get_sigframe(ka
, env
, sizeof(*frame
));
134 trace_user_setup_frame(env
, frame_addr
);
135 if (!lock_user_struct(VERIFY_WRITE
, frame
, frame_addr
, 0)) {
139 setup_sigcontext(&frame
->sc
, env
, frame_addr
, set
);
141 if (ka
->sa_restorer
) {
142 r26
= ka
->sa_restorer
;
144 __put_user(INSN_MOV_R30_R16
, &frame
->retcode
[0]);
145 __put_user(INSN_LDI_R0
+ TARGET_NR_sigreturn
,
147 __put_user(INSN_CALLSYS
, &frame
->retcode
[2]);
149 r26
= frame_addr
+ offsetof(struct target_sigframe
, retcode
);
152 unlock_user_struct(frame
, frame_addr
, 1);
160 env
->ir
[IR_RA
] = r26
;
161 env
->ir
[IR_PV
] = env
->pc
= ka
->_sa_handler
;
162 env
->ir
[IR_A0
] = sig
;
164 env
->ir
[IR_A2
] = frame_addr
+ offsetof(struct target_sigframe
, sc
);
165 env
->ir
[IR_SP
] = frame_addr
;
168 void setup_rt_frame(int sig
, struct target_sigaction
*ka
,
169 target_siginfo_t
*info
,
170 target_sigset_t
*set
, CPUAlphaState
*env
)
172 abi_ulong frame_addr
, r26
;
173 struct target_rt_sigframe
*frame
;
176 frame_addr
= get_sigframe(ka
, env
, sizeof(*frame
));
177 trace_user_setup_rt_frame(env
, frame_addr
);
178 if (!lock_user_struct(VERIFY_WRITE
, frame
, frame_addr
, 0)) {
182 tswap_siginfo(&frame
->info
, info
);
184 __put_user(0, &frame
->uc
.tuc_flags
);
185 __put_user(0, &frame
->uc
.tuc_link
);
186 __put_user(set
->sig
[0], &frame
->uc
.tuc_osf_sigmask
);
188 target_save_altstack(&frame
->uc
.tuc_stack
, env
);
190 setup_sigcontext(&frame
->uc
.tuc_mcontext
, env
, frame_addr
, set
);
191 for (i
= 0; i
< TARGET_NSIG_WORDS
; ++i
) {
192 __put_user(set
->sig
[i
], &frame
->uc
.tuc_sigmask
.sig
[i
]);
195 if (ka
->sa_restorer
) {
196 r26
= ka
->sa_restorer
;
198 __put_user(INSN_MOV_R30_R16
, &frame
->retcode
[0]);
199 __put_user(INSN_LDI_R0
+ TARGET_NR_rt_sigreturn
,
201 __put_user(INSN_CALLSYS
, &frame
->retcode
[2]);
203 r26
= frame_addr
+ offsetof(struct target_sigframe
, retcode
);
212 env
->ir
[IR_RA
] = r26
;
213 env
->ir
[IR_PV
] = env
->pc
= ka
->_sa_handler
;
214 env
->ir
[IR_A0
] = sig
;
215 env
->ir
[IR_A1
] = frame_addr
+ offsetof(struct target_rt_sigframe
, info
);
216 env
->ir
[IR_A2
] = frame_addr
+ offsetof(struct target_rt_sigframe
, uc
);
217 env
->ir
[IR_SP
] = frame_addr
;
220 long do_sigreturn(CPUAlphaState
*env
)
222 struct target_sigcontext
*sc
;
223 abi_ulong sc_addr
= env
->ir
[IR_A0
];
224 target_sigset_t target_set
;
227 if (!lock_user_struct(VERIFY_READ
, sc
, sc_addr
, 1)) {
231 target_sigemptyset(&target_set
);
232 __get_user(target_set
.sig
[0], &sc
->sc_mask
);
234 target_to_host_sigset_internal(&set
, &target_set
);
237 restore_sigcontext(env
, sc
);
238 unlock_user_struct(sc
, sc_addr
, 0);
239 return -TARGET_QEMU_ESIGRETURN
;
242 force_sig(TARGET_SIGSEGV
);
243 return -TARGET_QEMU_ESIGRETURN
;
246 long do_rt_sigreturn(CPUAlphaState
*env
)
248 abi_ulong frame_addr
= env
->ir
[IR_A0
];
249 struct target_rt_sigframe
*frame
;
252 trace_user_do_rt_sigreturn(env
, frame_addr
);
253 if (!lock_user_struct(VERIFY_READ
, frame
, frame_addr
, 1)) {
256 target_to_host_sigset(&set
, &frame
->uc
.tuc_sigmask
);
259 restore_sigcontext(env
, &frame
->uc
.tuc_mcontext
);
260 if (do_sigaltstack(frame_addr
+ offsetof(struct target_rt_sigframe
,
262 0, env
->ir
[IR_SP
]) == -EFAULT
) {
266 unlock_user_struct(frame
, frame_addr
, 0);
267 return -TARGET_QEMU_ESIGRETURN
;
271 unlock_user_struct(frame
, frame_addr
, 0);
272 force_sig(TARGET_SIGSEGV
);
273 return -TARGET_QEMU_ESIGRETURN
;