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
{
35 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
79 struct target_siginfo info
;
80 struct target_ucontext uc
;
83 static void setup_sigcontext(struct target_sigcontext
*sc
, CPUM68KState
*env
,
86 uint32_t sr
= (env
->sr
& 0xff00) | cpu_m68k_get_ccr(env
);
87 __put_user(mask
, &sc
->sc_mask
);
88 __put_user(env
->aregs
[7], &sc
->sc_usp
);
89 __put_user(env
->dregs
[0], &sc
->sc_d0
);
90 __put_user(env
->dregs
[1], &sc
->sc_d1
);
91 __put_user(env
->aregs
[0], &sc
->sc_a0
);
92 __put_user(env
->aregs
[1], &sc
->sc_a1
);
93 __put_user(sr
, &sc
->sc_sr
);
94 __put_user(env
->pc
, &sc
->sc_pc
);
98 restore_sigcontext(CPUM68KState
*env
, struct target_sigcontext
*sc
)
102 __get_user(env
->aregs
[7], &sc
->sc_usp
);
103 __get_user(env
->dregs
[0], &sc
->sc_d0
);
104 __get_user(env
->dregs
[1], &sc
->sc_d1
);
105 __get_user(env
->aregs
[0], &sc
->sc_a0
);
106 __get_user(env
->aregs
[1], &sc
->sc_a1
);
107 __get_user(env
->pc
, &sc
->sc_pc
);
108 __get_user(temp
, &sc
->sc_sr
);
109 cpu_m68k_set_ccr(env
, temp
);
113 * Determine which stack to use..
115 static inline abi_ulong
116 get_sigframe(struct target_sigaction
*ka
, CPUM68KState
*regs
,
121 sp
= target_sigsp(get_sp_from_cpustate(regs
), ka
);
124 return ((sp
- frame_size
) & -8UL);
127 void setup_frame(int sig
, struct target_sigaction
*ka
,
128 target_sigset_t
*set
, CPUM68KState
*env
)
130 struct target_sigframe
*frame
;
131 abi_ulong frame_addr
;
132 abi_ulong retcode_addr
;
136 frame_addr
= get_sigframe(ka
, env
, sizeof *frame
);
137 trace_user_setup_frame(env
, frame_addr
);
138 if (!lock_user_struct(VERIFY_WRITE
, frame
, frame_addr
, 0)) {
142 __put_user(sig
, &frame
->sig
);
144 sc_addr
= frame_addr
+ offsetof(struct target_sigframe
, sc
);
145 __put_user(sc_addr
, &frame
->psc
);
147 setup_sigcontext(&frame
->sc
, env
, set
->sig
[0]);
149 for(i
= 1; i
< TARGET_NSIG_WORDS
; i
++) {
150 __put_user(set
->sig
[i
], &frame
->extramask
[i
- 1]);
153 /* Set up to return from userspace. */
155 retcode_addr
= frame_addr
+ offsetof(struct target_sigframe
, retcode
);
156 __put_user(retcode_addr
, &frame
->pretcode
);
158 /* moveq #,d0; trap #0 */
160 __put_user(0x70004e40 + (TARGET_NR_sigreturn
<< 16),
161 (uint32_t *)(frame
->retcode
));
163 /* Set up to return from userspace */
165 env
->aregs
[7] = frame_addr
;
166 env
->pc
= ka
->_sa_handler
;
168 unlock_user_struct(frame
, frame_addr
, 1);
175 static inline void target_rt_save_fpu_state(struct target_ucontext
*uc
,
179 target_fpregset_t
*fpregs
= &uc
->tuc_mcontext
.fpregs
;
181 __put_user(env
->fpcr
, &fpregs
->f_fpcntl
[0]);
182 __put_user(env
->fpsr
, &fpregs
->f_fpcntl
[1]);
183 /* fpiar is not emulated */
185 for (i
= 0; i
< 8; i
++) {
186 uint32_t high
= env
->fregs
[i
].d
.high
<< 16;
187 __put_user(high
, &fpregs
->f_fpregs
[i
* 3]);
188 __put_user(env
->fregs
[i
].d
.low
,
189 (uint64_t *)&fpregs
->f_fpregs
[i
* 3 + 1]);
193 static inline int target_rt_setup_ucontext(struct target_ucontext
*uc
,
196 target_greg_t
*gregs
= uc
->tuc_mcontext
.gregs
;
197 uint32_t sr
= (env
->sr
& 0xff00) | cpu_m68k_get_ccr(env
);
199 __put_user(TARGET_MCONTEXT_VERSION
, &uc
->tuc_mcontext
.version
);
200 __put_user(env
->dregs
[0], &gregs
[0]);
201 __put_user(env
->dregs
[1], &gregs
[1]);
202 __put_user(env
->dregs
[2], &gregs
[2]);
203 __put_user(env
->dregs
[3], &gregs
[3]);
204 __put_user(env
->dregs
[4], &gregs
[4]);
205 __put_user(env
->dregs
[5], &gregs
[5]);
206 __put_user(env
->dregs
[6], &gregs
[6]);
207 __put_user(env
->dregs
[7], &gregs
[7]);
208 __put_user(env
->aregs
[0], &gregs
[8]);
209 __put_user(env
->aregs
[1], &gregs
[9]);
210 __put_user(env
->aregs
[2], &gregs
[10]);
211 __put_user(env
->aregs
[3], &gregs
[11]);
212 __put_user(env
->aregs
[4], &gregs
[12]);
213 __put_user(env
->aregs
[5], &gregs
[13]);
214 __put_user(env
->aregs
[6], &gregs
[14]);
215 __put_user(env
->aregs
[7], &gregs
[15]);
216 __put_user(env
->pc
, &gregs
[16]);
217 __put_user(sr
, &gregs
[17]);
219 target_rt_save_fpu_state(uc
, env
);
224 static inline void target_rt_restore_fpu_state(CPUM68KState
*env
,
225 struct target_ucontext
*uc
)
228 target_fpregset_t
*fpregs
= &uc
->tuc_mcontext
.fpregs
;
231 __get_user(fpcr
, &fpregs
->f_fpcntl
[0]);
232 cpu_m68k_set_fpcr(env
, fpcr
);
233 __get_user(env
->fpsr
, &fpregs
->f_fpcntl
[1]);
234 /* fpiar is not emulated */
236 for (i
= 0; i
< 8; i
++) {
238 __get_user(high
, &fpregs
->f_fpregs
[i
* 3]);
239 env
->fregs
[i
].d
.high
= high
>> 16;
240 __get_user(env
->fregs
[i
].d
.low
,
241 (uint64_t *)&fpregs
->f_fpregs
[i
* 3 + 1]);
245 static inline int target_rt_restore_ucontext(CPUM68KState
*env
,
246 struct target_ucontext
*uc
)
249 target_greg_t
*gregs
= uc
->tuc_mcontext
.gregs
;
251 __get_user(temp
, &uc
->tuc_mcontext
.version
);
252 if (temp
!= TARGET_MCONTEXT_VERSION
)
255 /* restore passed registers */
256 __get_user(env
->dregs
[0], &gregs
[0]);
257 __get_user(env
->dregs
[1], &gregs
[1]);
258 __get_user(env
->dregs
[2], &gregs
[2]);
259 __get_user(env
->dregs
[3], &gregs
[3]);
260 __get_user(env
->dregs
[4], &gregs
[4]);
261 __get_user(env
->dregs
[5], &gregs
[5]);
262 __get_user(env
->dregs
[6], &gregs
[6]);
263 __get_user(env
->dregs
[7], &gregs
[7]);
264 __get_user(env
->aregs
[0], &gregs
[8]);
265 __get_user(env
->aregs
[1], &gregs
[9]);
266 __get_user(env
->aregs
[2], &gregs
[10]);
267 __get_user(env
->aregs
[3], &gregs
[11]);
268 __get_user(env
->aregs
[4], &gregs
[12]);
269 __get_user(env
->aregs
[5], &gregs
[13]);
270 __get_user(env
->aregs
[6], &gregs
[14]);
271 __get_user(env
->aregs
[7], &gregs
[15]);
272 __get_user(env
->pc
, &gregs
[16]);
273 __get_user(temp
, &gregs
[17]);
274 cpu_m68k_set_ccr(env
, temp
);
276 target_rt_restore_fpu_state(env
, uc
);
284 void setup_rt_frame(int sig
, struct target_sigaction
*ka
,
285 target_siginfo_t
*info
,
286 target_sigset_t
*set
, CPUM68KState
*env
)
288 struct target_rt_sigframe
*frame
;
289 abi_ulong frame_addr
;
290 abi_ulong retcode_addr
;
296 frame_addr
= get_sigframe(ka
, env
, sizeof *frame
);
297 trace_user_setup_rt_frame(env
, frame_addr
);
298 if (!lock_user_struct(VERIFY_WRITE
, frame
, frame_addr
, 0)) {
302 __put_user(sig
, &frame
->sig
);
304 info_addr
= frame_addr
+ offsetof(struct target_rt_sigframe
, info
);
305 __put_user(info_addr
, &frame
->pinfo
);
307 uc_addr
= frame_addr
+ offsetof(struct target_rt_sigframe
, uc
);
308 __put_user(uc_addr
, &frame
->puc
);
310 tswap_siginfo(&frame
->info
, info
);
312 /* Create the ucontext */
314 __put_user(0, &frame
->uc
.tuc_flags
);
315 __put_user(0, &frame
->uc
.tuc_link
);
316 target_save_altstack(&frame
->uc
.tuc_stack
, env
);
317 err
|= target_rt_setup_ucontext(&frame
->uc
, env
);
322 for(i
= 0; i
< TARGET_NSIG_WORDS
; i
++) {
323 __put_user(set
->sig
[i
], &frame
->uc
.tuc_sigmask
.sig
[i
]);
326 /* Set up to return from userspace. */
328 retcode_addr
= frame_addr
+ offsetof(struct target_sigframe
, retcode
);
329 __put_user(retcode_addr
, &frame
->pretcode
);
331 /* moveq #,d0; notb d0; trap #0 */
333 __put_user(0x70004600 + ((TARGET_NR_rt_sigreturn
^ 0xff) << 16),
334 (uint32_t *)(frame
->retcode
+ 0));
335 __put_user(0x4e40, (uint16_t *)(frame
->retcode
+ 4));
340 /* Set up to return from userspace */
342 env
->aregs
[7] = frame_addr
;
343 env
->pc
= ka
->_sa_handler
;
345 unlock_user_struct(frame
, frame_addr
, 1);
349 unlock_user_struct(frame
, frame_addr
, 1);
353 long do_sigreturn(CPUM68KState
*env
)
355 struct target_sigframe
*frame
;
356 abi_ulong frame_addr
= env
->aregs
[7] - 4;
357 target_sigset_t target_set
;
361 trace_user_do_sigreturn(env
, frame_addr
);
362 if (!lock_user_struct(VERIFY_READ
, frame
, frame_addr
, 1))
365 /* set blocked signals */
367 __get_user(target_set
.sig
[0], &frame
->sc
.sc_mask
);
369 for(i
= 1; i
< TARGET_NSIG_WORDS
; i
++) {
370 __get_user(target_set
.sig
[i
], &frame
->extramask
[i
- 1]);
373 target_to_host_sigset_internal(&set
, &target_set
);
376 /* restore registers */
378 restore_sigcontext(env
, &frame
->sc
);
380 unlock_user_struct(frame
, frame_addr
, 0);
381 return -TARGET_QEMU_ESIGRETURN
;
384 force_sig(TARGET_SIGSEGV
);
385 return -TARGET_QEMU_ESIGRETURN
;
388 long do_rt_sigreturn(CPUM68KState
*env
)
390 struct target_rt_sigframe
*frame
;
391 abi_ulong frame_addr
= env
->aregs
[7] - 4;
394 trace_user_do_rt_sigreturn(env
, frame_addr
);
395 if (!lock_user_struct(VERIFY_READ
, frame
, frame_addr
, 1))
398 target_to_host_sigset(&set
, &frame
->uc
.tuc_sigmask
);
401 /* restore registers */
403 if (target_rt_restore_ucontext(env
, &frame
->uc
))
406 if (do_sigaltstack(frame_addr
+
407 offsetof(struct target_rt_sigframe
, uc
.tuc_stack
),
408 0, get_sp_from_cpustate(env
)) == -EFAULT
)
411 unlock_user_struct(frame
, frame_addr
, 0);
412 return -TARGET_QEMU_ESIGRETURN
;
415 unlock_user_struct(frame
, frame_addr
, 0);
416 force_sig(TARGET_SIGSEGV
);
417 return -TARGET_QEMU_ESIGRETURN
;