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
{
38 struct target_ucontext
{
41 target_stack_t tuc_stack
;
42 struct target_sigcontext tuc_mcontext
;
43 target_sigset_t tuc_sigmask
;
46 struct target_rt_sigframe
{
47 target_siginfo_t info
;
48 struct target_ucontext uc
;
54 static abi_ulong
get_sigframe(struct target_sigaction
*sa
,
56 unsigned long framesize
)
60 sp
= target_sigsp(get_sp_from_cpustate(env
), sa
);
62 return (sp
- framesize
) & -16;
65 static int flush_window_regs(CPUXtensaState
*env
)
67 uint32_t wb
= env
->sregs
[WINDOW_BASE
];
68 uint32_t ws
= xtensa_replicate_windowstart(env
) >> (wb
+ 1);
69 unsigned d
= ctz32(ws
) + 1;
73 for (i
= d
; i
< env
->config
->nareg
/ 4; i
+= d
) {
78 xtensa_rotate_window(env
, d
);
83 } else if (ws
& 0x2) {
85 ret
|= get_user_ual(osp
, env
->regs
[1] - 12);
88 } else if (ws
& 0x4) {
90 ret
|= get_user_ual(osp
, env
->regs
[1] - 12);
94 g_assert_not_reached();
97 for (j
= 0; j
< 4; ++j
) {
98 ret
|= put_user_ual(env
->regs
[j
], ssp
- 16 + j
* 4);
100 for (j
= 4; j
< d
* 4; ++j
) {
101 ret
|= put_user_ual(env
->regs
[j
], osp
- 16 + j
* 4);
104 xtensa_rotate_window(env
, d
);
105 g_assert(env
->sregs
[WINDOW_BASE
] == wb
);
109 static int setup_sigcontext(struct target_rt_sigframe
*frame
,
112 struct target_sigcontext
*sc
= &frame
->uc
.tuc_mcontext
;
115 __put_user(env
->pc
, &sc
->sc_pc
);
116 __put_user(env
->sregs
[PS
], &sc
->sc_ps
);
117 __put_user(env
->sregs
[LBEG
], &sc
->sc_lbeg
);
118 __put_user(env
->sregs
[LEND
], &sc
->sc_lend
);
119 __put_user(env
->sregs
[LCOUNT
], &sc
->sc_lcount
);
120 if (!flush_window_regs(env
)) {
123 for (i
= 0; i
< 16; ++i
) {
124 __put_user(env
->regs
[i
], sc
->sc_a
+ i
);
126 __put_user(0, &sc
->sc_xtregs
);
131 static void install_sigtramp(uint8_t *tramp
)
133 #if TARGET_BIG_ENDIAN
134 /* Generate instruction: MOVI a2, __NR_rt_sigreturn */
135 __put_user(0x22, &tramp
[0]);
136 __put_user(0x0a, &tramp
[1]);
137 __put_user(TARGET_NR_rt_sigreturn
, &tramp
[2]);
138 /* Generate instruction: SYSCALL */
139 __put_user(0x00, &tramp
[3]);
140 __put_user(0x05, &tramp
[4]);
141 __put_user(0x00, &tramp
[5]);
143 /* Generate instruction: MOVI a2, __NR_rt_sigreturn */
144 __put_user(0x22, &tramp
[0]);
145 __put_user(0xa0, &tramp
[1]);
146 __put_user(TARGET_NR_rt_sigreturn
, &tramp
[2]);
147 /* Generate instruction: SYSCALL */
148 __put_user(0x00, &tramp
[3]);
149 __put_user(0x50, &tramp
[4]);
150 __put_user(0x00, &tramp
[5]);
154 void setup_rt_frame(int sig
, struct target_sigaction
*ka
,
155 target_siginfo_t
*info
,
156 target_sigset_t
*set
, CPUXtensaState
*env
)
158 abi_ulong frame_addr
;
159 struct target_rt_sigframe
*frame
;
165 frame_addr
= get_sigframe(ka
, env
, sizeof(*frame
));
166 trace_user_setup_rt_frame(env
, frame_addr
);
168 if (!lock_user_struct(VERIFY_WRITE
, frame
, frame_addr
, 0)) {
172 if (ka
->sa_flags
& SA_SIGINFO
) {
173 tswap_siginfo(&frame
->info
, info
);
176 __put_user(0, &frame
->uc
.tuc_flags
);
177 __put_user(0, &frame
->uc
.tuc_link
);
178 target_save_altstack(&frame
->uc
.tuc_stack
, env
);
179 if (!setup_sigcontext(frame
, env
)) {
180 unlock_user_struct(frame
, frame_addr
, 0);
183 for (i
= 0; i
< TARGET_NSIG_WORDS
; ++i
) {
184 __put_user(set
->sig
[i
], &frame
->uc
.tuc_sigmask
.sig
[i
]);
187 if (ka
->sa_flags
& TARGET_SA_RESTORER
) {
188 ra
= ka
->sa_restorer
;
190 /* Not used, but retain for ABI compatibility. */
191 install_sigtramp(frame
->retcode
);
192 ra
= default_rt_sigreturn
;
194 memset(env
->regs
, 0, sizeof(env
->regs
));
195 env
->pc
= ka
->_sa_handler
;
196 env
->regs
[1] = frame_addr
;
197 env
->sregs
[WINDOW_BASE
] = 0;
198 env
->sregs
[WINDOW_START
] = 1;
200 abi_call0
= (env
->sregs
[PS
] & PS_WOE
) == 0;
201 env
->sregs
[PS
] = PS_UM
| (3 << PS_RING_SHIFT
);
205 env
->regs
[base
] = ra
;
207 env
->sregs
[PS
] |= PS_WOE
| (1 << PS_CALLINC_SHIFT
);
209 env
->regs
[base
] = (ra
& 0x3fffffff) | 0x40000000;
211 env
->regs
[base
+ 2] = sig
;
212 env
->regs
[base
+ 3] = frame_addr
+ offsetof(struct target_rt_sigframe
,
214 env
->regs
[base
+ 4] = frame_addr
+ offsetof(struct target_rt_sigframe
, uc
);
215 unlock_user_struct(frame
, frame_addr
, 1);
223 static void restore_sigcontext(CPUXtensaState
*env
,
224 struct target_rt_sigframe
*frame
)
226 struct target_sigcontext
*sc
= &frame
->uc
.tuc_mcontext
;
230 __get_user(env
->pc
, &sc
->sc_pc
);
231 __get_user(ps
, &sc
->sc_ps
);
232 __get_user(env
->sregs
[LBEG
], &sc
->sc_lbeg
);
233 __get_user(env
->sregs
[LEND
], &sc
->sc_lend
);
234 __get_user(env
->sregs
[LCOUNT
], &sc
->sc_lcount
);
236 env
->sregs
[WINDOW_BASE
] = 0;
237 env
->sregs
[WINDOW_START
] = 1;
238 env
->sregs
[PS
] = deposit32(env
->sregs
[PS
],
241 extract32(ps
, PS_CALLINC_SHIFT
,
243 for (i
= 0; i
< 16; ++i
) {
244 __get_user(env
->regs
[i
], sc
->sc_a
+ i
);
249 long do_rt_sigreturn(CPUXtensaState
*env
)
251 abi_ulong frame_addr
= env
->regs
[1];
252 struct target_rt_sigframe
*frame
;
255 trace_user_do_rt_sigreturn(env
, frame_addr
);
256 if (!lock_user_struct(VERIFY_READ
, frame
, frame_addr
, 1)) {
259 target_to_host_sigset(&set
, &frame
->uc
.tuc_sigmask
);
262 restore_sigcontext(env
, frame
);
263 target_restore_altstack(&frame
->uc
.tuc_stack
, env
);
265 unlock_user_struct(frame
, frame_addr
, 0);
266 return -QEMU_ESIGRETURN
;
269 unlock_user_struct(frame
, frame_addr
, 0);
270 force_sig(TARGET_SIGSEGV
);
271 return -QEMU_ESIGRETURN
;
274 void setup_sigtramp(abi_ulong sigtramp_page
)
276 uint8_t *tramp
= lock_user(VERIFY_WRITE
, sigtramp_page
, 6, 0);
277 assert(tramp
!= NULL
);
279 default_rt_sigreturn
= sigtramp_page
;
280 install_sigtramp(tramp
);
281 unlock_user(tramp
, sigtramp_page
, 6);