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
;
139 frame_addr
= get_sigframe(ka
, env
, sizeof(*frame
));
140 trace_user_setup_rt_frame(env
, frame_addr
);
142 if (!lock_user_struct(VERIFY_WRITE
, frame
, frame_addr
, 0)) {
146 if (ka
->sa_flags
& SA_SIGINFO
) {
147 tswap_siginfo(&frame
->info
, info
);
150 __put_user(0, &frame
->uc
.tuc_flags
);
151 __put_user(0, &frame
->uc
.tuc_link
);
152 target_save_altstack(&frame
->uc
.tuc_stack
, env
);
153 if (!setup_sigcontext(frame
, env
)) {
154 unlock_user_struct(frame
, frame_addr
, 0);
157 for (i
= 0; i
< TARGET_NSIG_WORDS
; ++i
) {
158 __put_user(set
->sig
[i
], &frame
->uc
.tuc_sigmask
.sig
[i
]);
161 if (ka
->sa_flags
& TARGET_SA_RESTORER
) {
162 ra
= ka
->sa_restorer
;
164 ra
= frame_addr
+ offsetof(struct target_rt_sigframe
, retcode
);
165 #ifdef TARGET_WORDS_BIGENDIAN
166 /* Generate instruction: MOVI a2, __NR_rt_sigreturn */
167 __put_user(0x22, &frame
->retcode
[0]);
168 __put_user(0x0a, &frame
->retcode
[1]);
169 __put_user(TARGET_NR_rt_sigreturn
, &frame
->retcode
[2]);
170 /* Generate instruction: SYSCALL */
171 __put_user(0x00, &frame
->retcode
[3]);
172 __put_user(0x05, &frame
->retcode
[4]);
173 __put_user(0x00, &frame
->retcode
[5]);
175 /* Generate instruction: MOVI a2, __NR_rt_sigreturn */
176 __put_user(0x22, &frame
->retcode
[0]);
177 __put_user(0xa0, &frame
->retcode
[1]);
178 __put_user(TARGET_NR_rt_sigreturn
, &frame
->retcode
[2]);
179 /* Generate instruction: SYSCALL */
180 __put_user(0x00, &frame
->retcode
[3]);
181 __put_user(0x50, &frame
->retcode
[4]);
182 __put_user(0x00, &frame
->retcode
[5]);
185 env
->sregs
[PS
] = PS_UM
| (3 << PS_RING_SHIFT
);
186 if (xtensa_option_enabled(env
->config
, XTENSA_OPTION_WINDOWED_REGISTER
)) {
187 env
->sregs
[PS
] |= PS_WOE
| (1 << PS_CALLINC_SHIFT
);
189 memset(env
->regs
, 0, sizeof(env
->regs
));
190 env
->pc
= ka
->_sa_handler
;
191 env
->regs
[1] = frame_addr
;
192 env
->sregs
[WINDOW_BASE
] = 0;
193 env
->sregs
[WINDOW_START
] = 1;
195 env
->regs
[4] = (ra
& 0x3fffffff) | 0x40000000;
197 env
->regs
[7] = frame_addr
+ offsetof(struct target_rt_sigframe
, info
);
198 env
->regs
[8] = frame_addr
+ offsetof(struct target_rt_sigframe
, uc
);
199 unlock_user_struct(frame
, frame_addr
, 1);
207 static void restore_sigcontext(CPUXtensaState
*env
,
208 struct target_rt_sigframe
*frame
)
210 struct target_sigcontext
*sc
= &frame
->uc
.tuc_mcontext
;
214 __get_user(env
->pc
, &sc
->sc_pc
);
215 __get_user(ps
, &sc
->sc_ps
);
216 __get_user(env
->sregs
[LBEG
], &sc
->sc_lbeg
);
217 __get_user(env
->sregs
[LEND
], &sc
->sc_lend
);
218 __get_user(env
->sregs
[LCOUNT
], &sc
->sc_lcount
);
220 env
->sregs
[WINDOW_BASE
] = 0;
221 env
->sregs
[WINDOW_START
] = 1;
222 env
->sregs
[PS
] = deposit32(env
->sregs
[PS
],
225 extract32(ps
, PS_CALLINC_SHIFT
,
227 for (i
= 0; i
< 16; ++i
) {
228 __get_user(env
->regs
[i
], sc
->sc_a
+ i
);
233 long do_rt_sigreturn(CPUXtensaState
*env
)
235 abi_ulong frame_addr
= env
->regs
[1];
236 struct target_rt_sigframe
*frame
;
239 trace_user_do_rt_sigreturn(env
, frame_addr
);
240 if (!lock_user_struct(VERIFY_READ
, frame
, frame_addr
, 1)) {
243 target_to_host_sigset(&set
, &frame
->uc
.tuc_sigmask
);
246 restore_sigcontext(env
, frame
);
248 if (do_sigaltstack(frame_addr
+
249 offsetof(struct target_rt_sigframe
, uc
.tuc_stack
),
250 0, get_sp_from_cpustate(env
)) == -TARGET_EFAULT
) {
253 unlock_user_struct(frame
, frame_addr
, 0);
254 return -TARGET_QEMU_ESIGRETURN
;
257 unlock_user_struct(frame
, frame_addr
, 0);
258 force_sig(TARGET_SIGSEGV
);
259 return -TARGET_QEMU_ESIGRETURN
;