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
{
37 struct target_ucontext
{
40 target_stack_t tuc_stack
;
41 struct target_sigcontext tuc_mcontext
;
42 target_sigset_t tuc_sigmask
;
45 struct target_rt_sigframe
{
46 target_siginfo_t info
;
47 struct target_ucontext uc
;
53 static abi_ulong
get_sigframe(struct target_sigaction
*sa
,
55 unsigned long framesize
)
59 sp
= target_sigsp(get_sp_from_cpustate(env
), sa
);
61 return (sp
- framesize
) & -16;
64 static int flush_window_regs(CPUXtensaState
*env
)
66 uint32_t wb
= env
->sregs
[WINDOW_BASE
];
67 uint32_t ws
= xtensa_replicate_windowstart(env
) >> (wb
+ 1);
68 unsigned d
= ctz32(ws
) + 1;
72 for (i
= d
; i
< env
->config
->nareg
/ 4; i
+= d
) {
77 xtensa_rotate_window(env
, d
);
82 } else if (ws
& 0x2) {
84 ret
|= get_user_ual(osp
, env
->regs
[1] - 12);
87 } else if (ws
& 0x4) {
89 ret
|= get_user_ual(osp
, env
->regs
[1] - 12);
93 g_assert_not_reached();
96 for (j
= 0; j
< 4; ++j
) {
97 ret
|= put_user_ual(env
->regs
[j
], ssp
- 16 + j
* 4);
99 for (j
= 4; j
< d
* 4; ++j
) {
100 ret
|= put_user_ual(env
->regs
[j
], osp
- 16 + j
* 4);
103 xtensa_rotate_window(env
, d
);
104 g_assert(env
->sregs
[WINDOW_BASE
] == wb
);
108 static int setup_sigcontext(struct target_rt_sigframe
*frame
,
111 struct target_sigcontext
*sc
= &frame
->uc
.tuc_mcontext
;
114 __put_user(env
->pc
, &sc
->sc_pc
);
115 __put_user(env
->sregs
[PS
], &sc
->sc_ps
);
116 __put_user(env
->sregs
[LBEG
], &sc
->sc_lbeg
);
117 __put_user(env
->sregs
[LEND
], &sc
->sc_lend
);
118 __put_user(env
->sregs
[LCOUNT
], &sc
->sc_lcount
);
119 if (!flush_window_regs(env
)) {
122 for (i
= 0; i
< 16; ++i
) {
123 __put_user(env
->regs
[i
], sc
->sc_a
+ i
);
125 __put_user(0, &sc
->sc_xtregs
);
130 void setup_rt_frame(int sig
, struct target_sigaction
*ka
,
131 target_siginfo_t
*info
,
132 target_sigset_t
*set
, CPUXtensaState
*env
)
134 abi_ulong frame_addr
;
135 struct target_rt_sigframe
*frame
;
141 frame_addr
= get_sigframe(ka
, env
, sizeof(*frame
));
142 trace_user_setup_rt_frame(env
, frame_addr
);
144 if (!lock_user_struct(VERIFY_WRITE
, frame
, frame_addr
, 0)) {
148 if (ka
->sa_flags
& SA_SIGINFO
) {
149 tswap_siginfo(&frame
->info
, info
);
152 __put_user(0, &frame
->uc
.tuc_flags
);
153 __put_user(0, &frame
->uc
.tuc_link
);
154 target_save_altstack(&frame
->uc
.tuc_stack
, env
);
155 if (!setup_sigcontext(frame
, env
)) {
156 unlock_user_struct(frame
, frame_addr
, 0);
159 for (i
= 0; i
< TARGET_NSIG_WORDS
; ++i
) {
160 __put_user(set
->sig
[i
], &frame
->uc
.tuc_sigmask
.sig
[i
]);
163 if (ka
->sa_flags
& TARGET_SA_RESTORER
) {
164 ra
= ka
->sa_restorer
;
166 ra
= frame_addr
+ offsetof(struct target_rt_sigframe
, retcode
);
167 #ifdef TARGET_WORDS_BIGENDIAN
168 /* Generate instruction: MOVI a2, __NR_rt_sigreturn */
169 __put_user(0x22, &frame
->retcode
[0]);
170 __put_user(0x0a, &frame
->retcode
[1]);
171 __put_user(TARGET_NR_rt_sigreturn
, &frame
->retcode
[2]);
172 /* Generate instruction: SYSCALL */
173 __put_user(0x00, &frame
->retcode
[3]);
174 __put_user(0x05, &frame
->retcode
[4]);
175 __put_user(0x00, &frame
->retcode
[5]);
177 /* Generate instruction: MOVI a2, __NR_rt_sigreturn */
178 __put_user(0x22, &frame
->retcode
[0]);
179 __put_user(0xa0, &frame
->retcode
[1]);
180 __put_user(TARGET_NR_rt_sigreturn
, &frame
->retcode
[2]);
181 /* Generate instruction: SYSCALL */
182 __put_user(0x00, &frame
->retcode
[3]);
183 __put_user(0x50, &frame
->retcode
[4]);
184 __put_user(0x00, &frame
->retcode
[5]);
187 memset(env
->regs
, 0, sizeof(env
->regs
));
188 env
->pc
= ka
->_sa_handler
;
189 env
->regs
[1] = frame_addr
;
190 env
->sregs
[WINDOW_BASE
] = 0;
191 env
->sregs
[WINDOW_START
] = 1;
193 abi_call0
= (env
->sregs
[PS
] & PS_WOE
) == 0;
194 env
->sregs
[PS
] = PS_UM
| (3 << PS_RING_SHIFT
);
198 env
->regs
[base
] = ra
;
200 env
->sregs
[PS
] |= PS_WOE
| (1 << PS_CALLINC_SHIFT
);
202 env
->regs
[base
] = (ra
& 0x3fffffff) | 0x40000000;
204 env
->regs
[base
+ 2] = sig
;
205 env
->regs
[base
+ 3] = frame_addr
+ offsetof(struct target_rt_sigframe
,
207 env
->regs
[base
+ 4] = frame_addr
+ offsetof(struct target_rt_sigframe
, uc
);
208 unlock_user_struct(frame
, frame_addr
, 1);
216 static void restore_sigcontext(CPUXtensaState
*env
,
217 struct target_rt_sigframe
*frame
)
219 struct target_sigcontext
*sc
= &frame
->uc
.tuc_mcontext
;
223 __get_user(env
->pc
, &sc
->sc_pc
);
224 __get_user(ps
, &sc
->sc_ps
);
225 __get_user(env
->sregs
[LBEG
], &sc
->sc_lbeg
);
226 __get_user(env
->sregs
[LEND
], &sc
->sc_lend
);
227 __get_user(env
->sregs
[LCOUNT
], &sc
->sc_lcount
);
229 env
->sregs
[WINDOW_BASE
] = 0;
230 env
->sregs
[WINDOW_START
] = 1;
231 env
->sregs
[PS
] = deposit32(env
->sregs
[PS
],
234 extract32(ps
, PS_CALLINC_SHIFT
,
236 for (i
= 0; i
< 16; ++i
) {
237 __get_user(env
->regs
[i
], sc
->sc_a
+ i
);
242 long do_rt_sigreturn(CPUXtensaState
*env
)
244 abi_ulong frame_addr
= env
->regs
[1];
245 struct target_rt_sigframe
*frame
;
248 trace_user_do_rt_sigreturn(env
, frame_addr
);
249 if (!lock_user_struct(VERIFY_READ
, frame
, frame_addr
, 1)) {
252 target_to_host_sigset(&set
, &frame
->uc
.tuc_sigmask
);
255 restore_sigcontext(env
, frame
);
257 if (do_sigaltstack(frame_addr
+
258 offsetof(struct target_rt_sigframe
, uc
.tuc_stack
),
259 0, get_sp_from_cpustate(env
)) == -TARGET_EFAULT
) {
262 unlock_user_struct(frame
, frame_addr
, 0);
263 return -TARGET_QEMU_ESIGRETURN
;
266 unlock_user_struct(frame
, frame_addr
, 0);
267 force_sig(TARGET_SIGSEGV
);
268 return -TARGET_QEMU_ESIGRETURN
;