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
{
36 struct target_sigframe
42 abi_ulong extramask
[TARGET_NSIG_WORDS
-1];
43 struct target_sigcontext sc
;
46 typedef int target_greg_t
;
47 #define TARGET_NGREG 18
48 typedef target_greg_t target_gregset_t
[TARGET_NGREG
];
50 typedef struct target_fpregset
{
55 struct target_mcontext
{
57 target_gregset_t gregs
;
58 target_fpregset_t fpregs
;
61 #define TARGET_MCONTEXT_VERSION 2
63 struct target_ucontext
{
66 target_stack_t tuc_stack
;
67 struct target_mcontext tuc_mcontext
;
68 abi_long tuc_filler
[80];
69 target_sigset_t tuc_sigmask
;
72 struct target_rt_sigframe
78 struct target_siginfo info
;
79 struct target_ucontext uc
;
82 static void setup_sigcontext(struct target_sigcontext
*sc
, CPUM68KState
*env
,
85 uint32_t sr
= (env
->sr
& 0xff00) | cpu_m68k_get_ccr(env
);
86 __put_user(mask
, &sc
->sc_mask
);
87 __put_user(env
->aregs
[7], &sc
->sc_usp
);
88 __put_user(env
->dregs
[0], &sc
->sc_d0
);
89 __put_user(env
->dregs
[1], &sc
->sc_d1
);
90 __put_user(env
->aregs
[0], &sc
->sc_a0
);
91 __put_user(env
->aregs
[1], &sc
->sc_a1
);
92 __put_user(sr
, &sc
->sc_sr
);
93 __put_user(env
->pc
, &sc
->sc_pc
);
97 restore_sigcontext(CPUM68KState
*env
, struct target_sigcontext
*sc
)
101 __get_user(env
->aregs
[7], &sc
->sc_usp
);
102 __get_user(env
->dregs
[0], &sc
->sc_d0
);
103 __get_user(env
->dregs
[1], &sc
->sc_d1
);
104 __get_user(env
->aregs
[0], &sc
->sc_a0
);
105 __get_user(env
->aregs
[1], &sc
->sc_a1
);
106 __get_user(env
->pc
, &sc
->sc_pc
);
107 __get_user(temp
, &sc
->sc_sr
);
108 cpu_m68k_set_ccr(env
, temp
);
112 * Determine which stack to use..
114 static inline abi_ulong
115 get_sigframe(struct target_sigaction
*ka
, CPUM68KState
*regs
,
120 sp
= target_sigsp(get_sp_from_cpustate(regs
), ka
);
123 return ((sp
- frame_size
) & -8UL);
126 void setup_frame(int sig
, struct target_sigaction
*ka
,
127 target_sigset_t
*set
, CPUM68KState
*env
)
129 struct target_sigframe
*frame
;
130 abi_ulong frame_addr
;
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 __put_user(sig
, &frame
->sig
);
142 sc_addr
= frame_addr
+ offsetof(struct target_sigframe
, sc
);
143 __put_user(sc_addr
, &frame
->psc
);
145 setup_sigcontext(&frame
->sc
, env
, set
->sig
[0]);
147 for(i
= 1; i
< TARGET_NSIG_WORDS
; i
++) {
148 __put_user(set
->sig
[i
], &frame
->extramask
[i
- 1]);
151 /* Set up to return from userspace. */
152 __put_user(default_sigreturn
, &frame
->pretcode
);
154 env
->aregs
[7] = frame_addr
;
155 env
->pc
= ka
->_sa_handler
;
157 unlock_user_struct(frame
, frame_addr
, 1);
164 static inline void target_rt_save_fpu_state(struct target_ucontext
*uc
,
168 target_fpregset_t
*fpregs
= &uc
->tuc_mcontext
.fpregs
;
170 __put_user(env
->fpcr
, &fpregs
->f_fpcntl
[0]);
171 __put_user(env
->fpsr
, &fpregs
->f_fpcntl
[1]);
172 /* fpiar is not emulated */
174 for (i
= 0; i
< 8; i
++) {
175 uint32_t high
= env
->fregs
[i
].d
.high
<< 16;
176 __put_user(high
, &fpregs
->f_fpregs
[i
* 3]);
177 __put_user(env
->fregs
[i
].d
.low
,
178 (uint64_t *)&fpregs
->f_fpregs
[i
* 3 + 1]);
182 static inline int target_rt_setup_ucontext(struct target_ucontext
*uc
,
185 target_greg_t
*gregs
= uc
->tuc_mcontext
.gregs
;
186 uint32_t sr
= (env
->sr
& 0xff00) | cpu_m68k_get_ccr(env
);
188 __put_user(TARGET_MCONTEXT_VERSION
, &uc
->tuc_mcontext
.version
);
189 __put_user(env
->dregs
[0], &gregs
[0]);
190 __put_user(env
->dregs
[1], &gregs
[1]);
191 __put_user(env
->dregs
[2], &gregs
[2]);
192 __put_user(env
->dregs
[3], &gregs
[3]);
193 __put_user(env
->dregs
[4], &gregs
[4]);
194 __put_user(env
->dregs
[5], &gregs
[5]);
195 __put_user(env
->dregs
[6], &gregs
[6]);
196 __put_user(env
->dregs
[7], &gregs
[7]);
197 __put_user(env
->aregs
[0], &gregs
[8]);
198 __put_user(env
->aregs
[1], &gregs
[9]);
199 __put_user(env
->aregs
[2], &gregs
[10]);
200 __put_user(env
->aregs
[3], &gregs
[11]);
201 __put_user(env
->aregs
[4], &gregs
[12]);
202 __put_user(env
->aregs
[5], &gregs
[13]);
203 __put_user(env
->aregs
[6], &gregs
[14]);
204 __put_user(env
->aregs
[7], &gregs
[15]);
205 __put_user(env
->pc
, &gregs
[16]);
206 __put_user(sr
, &gregs
[17]);
208 target_rt_save_fpu_state(uc
, env
);
213 static inline void target_rt_restore_fpu_state(CPUM68KState
*env
,
214 struct target_ucontext
*uc
)
217 target_fpregset_t
*fpregs
= &uc
->tuc_mcontext
.fpregs
;
220 __get_user(fpcr
, &fpregs
->f_fpcntl
[0]);
221 cpu_m68k_set_fpcr(env
, fpcr
);
222 __get_user(env
->fpsr
, &fpregs
->f_fpcntl
[1]);
223 /* fpiar is not emulated */
225 for (i
= 0; i
< 8; i
++) {
227 __get_user(high
, &fpregs
->f_fpregs
[i
* 3]);
228 env
->fregs
[i
].d
.high
= high
>> 16;
229 __get_user(env
->fregs
[i
].d
.low
,
230 (uint64_t *)&fpregs
->f_fpregs
[i
* 3 + 1]);
234 static inline int target_rt_restore_ucontext(CPUM68KState
*env
,
235 struct target_ucontext
*uc
)
238 target_greg_t
*gregs
= uc
->tuc_mcontext
.gregs
;
240 __get_user(temp
, &uc
->tuc_mcontext
.version
);
241 if (temp
!= TARGET_MCONTEXT_VERSION
)
244 /* restore passed registers */
245 __get_user(env
->dregs
[0], &gregs
[0]);
246 __get_user(env
->dregs
[1], &gregs
[1]);
247 __get_user(env
->dregs
[2], &gregs
[2]);
248 __get_user(env
->dregs
[3], &gregs
[3]);
249 __get_user(env
->dregs
[4], &gregs
[4]);
250 __get_user(env
->dregs
[5], &gregs
[5]);
251 __get_user(env
->dregs
[6], &gregs
[6]);
252 __get_user(env
->dregs
[7], &gregs
[7]);
253 __get_user(env
->aregs
[0], &gregs
[8]);
254 __get_user(env
->aregs
[1], &gregs
[9]);
255 __get_user(env
->aregs
[2], &gregs
[10]);
256 __get_user(env
->aregs
[3], &gregs
[11]);
257 __get_user(env
->aregs
[4], &gregs
[12]);
258 __get_user(env
->aregs
[5], &gregs
[13]);
259 __get_user(env
->aregs
[6], &gregs
[14]);
260 __get_user(env
->aregs
[7], &gregs
[15]);
261 __get_user(env
->pc
, &gregs
[16]);
262 __get_user(temp
, &gregs
[17]);
263 cpu_m68k_set_ccr(env
, temp
);
265 target_rt_restore_fpu_state(env
, uc
);
273 void setup_rt_frame(int sig
, struct target_sigaction
*ka
,
274 target_siginfo_t
*info
,
275 target_sigset_t
*set
, CPUM68KState
*env
)
277 struct target_rt_sigframe
*frame
;
278 abi_ulong frame_addr
;
284 frame_addr
= get_sigframe(ka
, env
, sizeof *frame
);
285 trace_user_setup_rt_frame(env
, frame_addr
);
286 if (!lock_user_struct(VERIFY_WRITE
, frame
, frame_addr
, 0)) {
290 __put_user(sig
, &frame
->sig
);
292 info_addr
= frame_addr
+ offsetof(struct target_rt_sigframe
, info
);
293 __put_user(info_addr
, &frame
->pinfo
);
295 uc_addr
= frame_addr
+ offsetof(struct target_rt_sigframe
, uc
);
296 __put_user(uc_addr
, &frame
->puc
);
300 /* Create the ucontext */
302 __put_user(0, &frame
->uc
.tuc_flags
);
303 __put_user(0, &frame
->uc
.tuc_link
);
304 target_save_altstack(&frame
->uc
.tuc_stack
, env
);
305 err
|= target_rt_setup_ucontext(&frame
->uc
, env
);
310 for (i
= 0; i
< TARGET_NSIG_WORDS
; i
++) {
311 __put_user(set
->sig
[i
], &frame
->uc
.tuc_sigmask
.sig
[i
]);
314 /* Set up to return from userspace. */
315 __put_user(default_rt_sigreturn
, &frame
->pretcode
);
317 env
->aregs
[7] = frame_addr
;
318 env
->pc
= ka
->_sa_handler
;
320 unlock_user_struct(frame
, frame_addr
, 1);
324 unlock_user_struct(frame
, frame_addr
, 1);
328 long do_sigreturn(CPUM68KState
*env
)
330 struct target_sigframe
*frame
;
331 abi_ulong frame_addr
= env
->aregs
[7] - 4;
332 target_sigset_t target_set
;
336 trace_user_do_sigreturn(env
, frame_addr
);
337 if (!lock_user_struct(VERIFY_READ
, frame
, frame_addr
, 1))
340 /* set blocked signals */
342 __get_user(target_set
.sig
[0], &frame
->sc
.sc_mask
);
344 for(i
= 1; i
< TARGET_NSIG_WORDS
; i
++) {
345 __get_user(target_set
.sig
[i
], &frame
->extramask
[i
- 1]);
348 target_to_host_sigset_internal(&set
, &target_set
);
351 /* restore registers */
353 restore_sigcontext(env
, &frame
->sc
);
355 unlock_user_struct(frame
, frame_addr
, 0);
356 return -QEMU_ESIGRETURN
;
359 force_sig(TARGET_SIGSEGV
);
360 return -QEMU_ESIGRETURN
;
363 long do_rt_sigreturn(CPUM68KState
*env
)
365 struct target_rt_sigframe
*frame
;
366 abi_ulong frame_addr
= env
->aregs
[7] - 4;
369 trace_user_do_rt_sigreturn(env
, frame_addr
);
370 if (!lock_user_struct(VERIFY_READ
, frame
, frame_addr
, 1))
373 target_to_host_sigset(&set
, &frame
->uc
.tuc_sigmask
);
376 /* restore registers */
378 if (target_rt_restore_ucontext(env
, &frame
->uc
))
381 target_restore_altstack(&frame
->uc
.tuc_stack
, env
);
383 unlock_user_struct(frame
, frame_addr
, 0);
384 return -QEMU_ESIGRETURN
;
387 unlock_user_struct(frame
, frame_addr
, 0);
388 force_sig(TARGET_SIGSEGV
);
389 return -QEMU_ESIGRETURN
;
392 void setup_sigtramp(abi_ulong sigtramp_page
)
394 void *tramp
= lock_user(VERIFY_WRITE
, sigtramp_page
, 4 + 6, 0);
395 assert(tramp
!= NULL
);
397 default_sigreturn
= sigtramp_page
;
399 /* moveq #,d0; trap #0 */
400 __put_user(0x70004e40 + (TARGET_NR_sigreturn
<< 16), (uint32_t *)tramp
);
402 default_rt_sigreturn
= sigtramp_page
+ 4;
404 /* moveq #,d0; notb d0; trap #0 */
405 __put_user(0x70004600 + ((TARGET_NR_rt_sigreturn
^ 0xff) << 16),
406 (uint32_t *)(tramp
+ 4));
407 __put_user(0x4e40, (uint16_t *)(tramp
+ 8));
409 unlock_user(tramp
, sigtramp_page
, 4 + 6);