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 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
;
60 struct target_rt_sigframe
{
61 target_siginfo_t info
;
62 struct target_ucontext uc
;
65 #define INSN_MOV_R30_R16 0x47fe0410
66 #define INSN_LDI_R0 0x201f0000
67 #define INSN_CALLSYS 0x00000083
69 static void setup_sigcontext(struct target_sigcontext
*sc
, CPUAlphaState
*env
,
70 abi_ulong frame_addr
, target_sigset_t
*set
)
74 __put_user(on_sig_stack(frame_addr
), &sc
->sc_onstack
);
75 __put_user(set
->sig
[0], &sc
->sc_mask
);
76 __put_user(env
->pc
, &sc
->sc_pc
);
77 __put_user(8, &sc
->sc_ps
);
79 for (i
= 0; i
< 31; ++i
) {
80 __put_user(env
->ir
[i
], &sc
->sc_regs
[i
]);
82 __put_user(0, &sc
->sc_regs
[31]);
84 for (i
= 0; i
< 31; ++i
) {
85 __put_user(env
->fir
[i
], &sc
->sc_fpregs
[i
]);
87 __put_user(0, &sc
->sc_fpregs
[31]);
88 __put_user(cpu_alpha_load_fpcr(env
), &sc
->sc_fpcr
);
90 __put_user(0, &sc
->sc_traparg_a0
); /* FIXME */
91 __put_user(0, &sc
->sc_traparg_a1
); /* FIXME */
92 __put_user(0, &sc
->sc_traparg_a2
); /* FIXME */
95 static void restore_sigcontext(CPUAlphaState
*env
,
96 struct target_sigcontext
*sc
)
101 __get_user(env
->pc
, &sc
->sc_pc
);
103 for (i
= 0; i
< 31; ++i
) {
104 __get_user(env
->ir
[i
], &sc
->sc_regs
[i
]);
106 for (i
= 0; i
< 31; ++i
) {
107 __get_user(env
->fir
[i
], &sc
->sc_fpregs
[i
]);
110 __get_user(fpcr
, &sc
->sc_fpcr
);
111 cpu_alpha_store_fpcr(env
, fpcr
);
114 static inline abi_ulong
get_sigframe(struct target_sigaction
*sa
,
116 unsigned long framesize
)
120 sp
= target_sigsp(get_sp_from_cpustate(env
), sa
);
122 return (sp
- framesize
) & -32;
125 void setup_frame(int sig
, struct target_sigaction
*ka
,
126 target_sigset_t
*set
, CPUAlphaState
*env
)
128 abi_ulong frame_addr
, r26
;
129 struct target_sigframe
*frame
;
132 frame_addr
= get_sigframe(ka
, env
, sizeof(*frame
));
133 trace_user_setup_frame(env
, frame_addr
);
134 if (!lock_user_struct(VERIFY_WRITE
, frame
, frame_addr
, 0)) {
138 setup_sigcontext(&frame
->sc
, env
, frame_addr
, set
);
140 if (ka
->ka_restorer
) {
141 r26
= ka
->ka_restorer
;
143 r26
= default_sigreturn
;
146 unlock_user_struct(frame
, frame_addr
, 1);
154 env
->ir
[IR_RA
] = r26
;
155 env
->ir
[IR_PV
] = env
->pc
= ka
->_sa_handler
;
156 env
->ir
[IR_A0
] = sig
;
158 env
->ir
[IR_A2
] = frame_addr
+ offsetof(struct target_sigframe
, sc
);
159 env
->ir
[IR_SP
] = frame_addr
;
162 void setup_rt_frame(int sig
, struct target_sigaction
*ka
,
163 target_siginfo_t
*info
,
164 target_sigset_t
*set
, CPUAlphaState
*env
)
166 abi_ulong frame_addr
, r26
;
167 struct target_rt_sigframe
*frame
;
170 frame_addr
= get_sigframe(ka
, env
, sizeof(*frame
));
171 trace_user_setup_rt_frame(env
, frame_addr
);
172 if (!lock_user_struct(VERIFY_WRITE
, frame
, frame_addr
, 0)) {
176 tswap_siginfo(&frame
->info
, info
);
178 __put_user(0, &frame
->uc
.tuc_flags
);
179 __put_user(0, &frame
->uc
.tuc_link
);
180 __put_user(set
->sig
[0], &frame
->uc
.tuc_osf_sigmask
);
182 target_save_altstack(&frame
->uc
.tuc_stack
, env
);
184 setup_sigcontext(&frame
->uc
.tuc_mcontext
, env
, frame_addr
, set
);
185 for (i
= 0; i
< TARGET_NSIG_WORDS
; ++i
) {
186 __put_user(set
->sig
[i
], &frame
->uc
.tuc_sigmask
.sig
[i
]);
189 if (ka
->ka_restorer
) {
190 r26
= ka
->ka_restorer
;
192 r26
= default_rt_sigreturn
;
201 env
->ir
[IR_RA
] = r26
;
202 env
->ir
[IR_PV
] = env
->pc
= ka
->_sa_handler
;
203 env
->ir
[IR_A0
] = sig
;
204 env
->ir
[IR_A1
] = frame_addr
+ offsetof(struct target_rt_sigframe
, info
);
205 env
->ir
[IR_A2
] = frame_addr
+ offsetof(struct target_rt_sigframe
, uc
);
206 env
->ir
[IR_SP
] = frame_addr
;
209 long do_sigreturn(CPUAlphaState
*env
)
211 struct target_sigcontext
*sc
;
212 abi_ulong sc_addr
= env
->ir
[IR_A0
];
213 target_sigset_t target_set
;
216 if (!lock_user_struct(VERIFY_READ
, sc
, sc_addr
, 1)) {
220 target_sigemptyset(&target_set
);
221 __get_user(target_set
.sig
[0], &sc
->sc_mask
);
223 target_to_host_sigset_internal(&set
, &target_set
);
226 restore_sigcontext(env
, sc
);
227 unlock_user_struct(sc
, sc_addr
, 0);
228 return -QEMU_ESIGRETURN
;
231 force_sig(TARGET_SIGSEGV
);
232 return -QEMU_ESIGRETURN
;
235 long do_rt_sigreturn(CPUAlphaState
*env
)
237 abi_ulong frame_addr
= env
->ir
[IR_A0
];
238 struct target_rt_sigframe
*frame
;
241 trace_user_do_rt_sigreturn(env
, frame_addr
);
242 if (!lock_user_struct(VERIFY_READ
, frame
, frame_addr
, 1)) {
245 target_to_host_sigset(&set
, &frame
->uc
.tuc_sigmask
);
248 restore_sigcontext(env
, &frame
->uc
.tuc_mcontext
);
249 target_restore_altstack(&frame
->uc
.tuc_stack
, env
);
251 unlock_user_struct(frame
, frame_addr
, 0);
252 return -QEMU_ESIGRETURN
;
256 unlock_user_struct(frame
, frame_addr
, 0);
257 force_sig(TARGET_SIGSEGV
);
258 return -QEMU_ESIGRETURN
;
261 void setup_sigtramp(abi_ulong sigtramp_page
)
263 uint32_t *tramp
= lock_user(VERIFY_WRITE
, sigtramp_page
, 6 * 4, 0);
264 assert(tramp
!= NULL
);
266 default_sigreturn
= sigtramp_page
;
267 __put_user(INSN_MOV_R30_R16
, &tramp
[0]);
268 __put_user(INSN_LDI_R0
+ TARGET_NR_sigreturn
, &tramp
[1]);
269 __put_user(INSN_CALLSYS
, &tramp
[2]);
271 default_rt_sigreturn
= sigtramp_page
+ 3 * 4;
272 __put_user(INSN_MOV_R30_R16
, &tramp
[3]);
273 __put_user(INSN_LDI_R0
+ TARGET_NR_rt_sigreturn
, &tramp
[4]);
274 __put_user(INSN_CALLSYS
, &tramp
[5]);
276 unlock_user(tramp
, sigtramp_page
, 6 * 4);