master
c 386 lines 11.5 KB
Raw
1 /*
2 * Emulation of Linux signals
3 *
4 * Copyright (c) 2003 Fabrice Bellard
5 *
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.
10 *
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.
15 *
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/>.
18 */
19 #include "qemu/osdep.h"
20 #include "qemu.h"
21 #include "user-internals.h"
22 #include "signal-common.h"
23 #include "linux-user/trace.h"
24 #include "target/xtensa/cpu.h"
25
26 struct target_sigcontext {
27 abi_ulong sc_pc;
28 abi_ulong sc_ps;
29 abi_ulong sc_lbeg;
30 abi_ulong sc_lend;
31 abi_ulong sc_lcount;
32 abi_ulong sc_sar;
33 abi_ulong sc_acclo;
34 abi_ulong sc_acchi;
35 abi_ulong sc_a[16];
36 abi_ulong sc_xtregs;
37 };
38
39 struct target_ucontext {
40 abi_ulong tuc_flags;
41 abi_ulong tuc_link;
42 target_stack_t tuc_stack;
43 struct target_sigcontext tuc_mcontext;
44 target_sigset_t tuc_sigmask;
45 };
46
47 struct target_xtensa_xtregs_fp {
48 uint32_t f[16];
49 uint32_t fcr;
50 uint32_t fsr;
51 };
52
53 struct target_xtensa_xtregs_dfp {
54 uint64_t f[16];
55 uint32_t fcr;
56 uint32_t fsr;
57 };
58
59 struct target_rt_sigframe {
60 target_siginfo_t info;
61 struct target_ucontext uc;
62 union {
63 struct target_xtensa_xtregs_fp fp;
64 struct target_xtensa_xtregs_dfp dfp;
65 } xtregs;
66 uint8_t retcode[6];
67 abi_ulong window[4];
68 };
69
70 static abi_ulong get_sigframe(struct target_sigaction *sa,
71 CPUXtensaState *env,
72 unsigned long framesize)
73 {
74 abi_ulong sp;
75
76 sp = target_sigsp(get_sp_from_cpustate(env), sa);
77
78 return (sp - framesize) & -16;
79 }
80
81 static int flush_window_regs(CPUXtensaState *env)
82 {
83 uint32_t wb = env->sregs[WINDOW_BASE];
84 uint32_t ws = xtensa_replicate_windowstart(env) >> (wb + 1);
85 unsigned d = ctz32(ws) + 1;
86 unsigned i;
87 int ret = 0;
88
89 for (i = d; i < env->config->nareg / 4; i += d) {
90 uint32_t ssp, osp;
91 unsigned j;
92
93 ws >>= d;
94 xtensa_rotate_window(env, d);
95
96 if (ws & 0x1) {
97 ssp = env->regs[5];
98 d = 1;
99 } else if (ws & 0x2) {
100 ssp = env->regs[9];
101 ret |= get_user_ual(osp, env->regs[1] - 12);
102 osp -= 32;
103 d = 2;
104 } else if (ws & 0x4) {
105 ssp = env->regs[13];
106 ret |= get_user_ual(osp, env->regs[1] - 12);
107 osp -= 48;
108 d = 3;
109 } else {
110 g_assert_not_reached();
111 }
112
113 for (j = 0; j < 4; ++j) {
114 ret |= put_user_ual(env->regs[j], ssp - 16 + j * 4);
115 }
116 for (j = 4; j < d * 4; ++j) {
117 ret |= put_user_ual(env->regs[j], osp - 16 + j * 4);
118 }
119 }
120 xtensa_rotate_window(env, d);
121 g_assert(env->sregs[WINDOW_BASE] == wb);
122 return ret == 0;
123 }
124
125 static int setup_sigcontext(struct target_rt_sigframe *frame,
126 abi_ulong frame_addr,
127 CPUXtensaState *env)
128 {
129 struct target_sigcontext *sc = &frame->uc.tuc_mcontext;
130 int i;
131
132 __put_user(env->pc, &sc->sc_pc);
133 __put_user(env->sregs[PS], &sc->sc_ps);
134 __put_user(env->sregs[LBEG], &sc->sc_lbeg);
135 __put_user(env->sregs[LEND], &sc->sc_lend);
136 __put_user(env->sregs[LCOUNT], &sc->sc_lcount);
137 if (!flush_window_regs(env)) {
138 return 0;
139 }
140 for (i = 0; i < 16; ++i) {
141 __put_user(env->regs[i], sc->sc_a + i);
142 }
143 if (xtensa_option_enabled(env->config, XTENSA_OPTION_DFP_COPROCESSOR)) {
144 for (i = 0; i < 16; ++i) {
145 __put_user(env->fregs[i].f64, &frame->xtregs.dfp.f[i]);
146 }
147 __put_user(env->uregs[FCR], &frame->xtregs.dfp.fcr);
148 __put_user(cpu_get_fsr(env), &frame->xtregs.dfp.fsr);
149 __put_user(frame_addr + offsetof(struct target_rt_sigframe, xtregs),
150 &sc->sc_xtregs);
151 } else if (xtensa_option_enabled(env->config, XTENSA_OPTION_FP_COPROCESSOR)) {
152 for (i = 0; i < 16; ++i) {
153 __put_user(env->fregs[i].f32[FP_F32_LOW], &frame->xtregs.fp.f[i]);
154 }
155 __put_user(env->uregs[FCR], &frame->xtregs.fp.fcr);
156 __put_user(cpu_get_fsr(env), &frame->xtregs.fp.fsr);
157 __put_user(frame_addr + offsetof(struct target_rt_sigframe, xtregs),
158 &sc->sc_xtregs);
159 } else {
160 __put_user(0, &sc->sc_xtregs);
161 }
162 return 1;
163 }
164
165 static void install_sigtramp(uint8_t *tramp)
166 {
167 #if TARGET_BIG_ENDIAN
168 /* Generate instruction: MOVI a2, __NR_rt_sigreturn */
169 __put_user(0x22, &tramp[0]);
170 __put_user(0x0a, &tramp[1]);
171 __put_user(TARGET_NR_rt_sigreturn, &tramp[2]);
172 /* Generate instruction: SYSCALL */
173 __put_user(0x00, &tramp[3]);
174 __put_user(0x05, &tramp[4]);
175 __put_user(0x00, &tramp[5]);
176 #else
177 /* Generate instruction: MOVI a2, __NR_rt_sigreturn */
178 __put_user(0x22, &tramp[0]);
179 __put_user(0xa0, &tramp[1]);
180 __put_user(TARGET_NR_rt_sigreturn, &tramp[2]);
181 /* Generate instruction: SYSCALL */
182 __put_user(0x00, &tramp[3]);
183 __put_user(0x50, &tramp[4]);
184 __put_user(0x00, &tramp[5]);
185 #endif
186 }
187
188 void setup_rt_frame(int sig, struct target_sigaction *ka,
189 target_siginfo_t *info,
190 target_sigset_t *set, CPUXtensaState *env)
191 {
192 abi_ulong frame_addr;
193 struct target_rt_sigframe *frame;
194 int is_fdpic = info_is_fdpic(get_task_state(thread_cpu)->info);
195 abi_ulong handler = 0;
196 abi_ulong handler_fdpic_GOT = 0;
197 uint32_t ra;
198 bool abi_call0;
199 unsigned base;
200 int i;
201
202 frame_addr = get_sigframe(ka, env, sizeof(*frame));
203 trace_user_setup_rt_frame(env, frame_addr);
204
205 if (is_fdpic) {
206 abi_ulong funcdesc_ptr = ka->_sa_handler;
207
208 if (get_user_ual(handler, funcdesc_ptr)
209 || get_user_ual(handler_fdpic_GOT, funcdesc_ptr + 4)) {
210 goto give_sigsegv;
211 }
212 } else {
213 handler = ka->_sa_handler;
214 }
215
216 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
217 goto give_sigsegv;
218 }
219
220 if (ka->sa_flags & SA_SIGINFO) {
221 frame->info = *info;
222 }
223
224 __put_user(0, &frame->uc.tuc_flags);
225 __put_user(0, &frame->uc.tuc_link);
226 target_save_altstack(&frame->uc.tuc_stack, env);
227 if (!setup_sigcontext(frame, frame_addr, env)) {
228 unlock_user_struct(frame, frame_addr, 0);
229 goto give_sigsegv;
230 }
231 for (i = 0; i < TARGET_NSIG_WORDS; ++i) {
232 __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
233 }
234
235 if (ka->sa_flags & TARGET_SA_RESTORER) {
236 if (is_fdpic) {
237 if (get_user_ual(ra, ka->sa_restorer)) {
238 unlock_user_struct(frame, frame_addr, 0);
239 goto give_sigsegv;
240 }
241 } else {
242 ra = ka->sa_restorer;
243 }
244 } else {
245 /* Not used, but retain for ABI compatibility. */
246 install_sigtramp(frame->retcode);
247 ra = default_rt_sigreturn;
248 }
249 memset(env->regs, 0, sizeof(env->regs));
250 env->pc = handler;
251 env->regs[1] = frame_addr;
252 env->sregs[WINDOW_BASE] = 0;
253 env->sregs[WINDOW_START] = 1;
254
255 abi_call0 = (env->sregs[PS] & PS_WOE) == 0;
256 env->sregs[PS] = PS_UM | (3 << PS_RING_SHIFT);
257
258 if (abi_call0) {
259 base = 0;
260 env->regs[base] = ra;
261 } else {
262 env->sregs[PS] |= PS_WOE | (1 << PS_CALLINC_SHIFT);
263 base = 4;
264 env->regs[base] = (ra & 0x3fffffff) | 0x40000000;
265 }
266 env->regs[base + 2] = sig;
267 env->regs[base + 3] = frame_addr + offsetof(struct target_rt_sigframe,
268 info);
269 env->regs[base + 4] = frame_addr + offsetof(struct target_rt_sigframe, uc);
270 if (is_fdpic) {
271 env->regs[base + 11] = handler_fdpic_GOT;
272 }
273 unlock_user_struct(frame, frame_addr, 1);
274 return;
275
276 give_sigsegv:
277 force_sigsegv(sig);
278 }
279
280 static int restore_sigcontext(CPUXtensaState *env,
281 struct target_rt_sigframe *frame)
282 {
283 struct target_sigcontext *sc = &frame->uc.tuc_mcontext;
284 uint32_t ps;
285 int i;
286
287 __get_user(env->pc, &sc->sc_pc);
288 __get_user(ps, &sc->sc_ps);
289 __get_user(env->sregs[LBEG], &sc->sc_lbeg);
290 __get_user(env->sregs[LEND], &sc->sc_lend);
291 __get_user(env->sregs[LCOUNT], &sc->sc_lcount);
292
293 env->sregs[WINDOW_BASE] = 0;
294 env->sregs[WINDOW_START] = 1;
295 env->sregs[PS] = deposit32(env->sregs[PS],
296 PS_CALLINC_SHIFT,
297 PS_CALLINC_LEN,
298 extract32(ps, PS_CALLINC_SHIFT,
299 PS_CALLINC_LEN));
300 for (i = 0; i < 16; ++i) {
301 __get_user(env->regs[i], sc->sc_a + i);
302 }
303 {
304 abi_ulong xtregs_addr;
305
306 __get_user(xtregs_addr, &sc->sc_xtregs);
307 if (xtregs_addr) {
308 if (xtensa_option_enabled(env->config,
309 XTENSA_OPTION_DFP_COPROCESSOR)) {
310 struct target_xtensa_xtregs_dfp *xtregs;
311 uint32_t fcr, fsr;
312
313 xtregs = lock_user(VERIFY_READ, xtregs_addr,
314 sizeof(*xtregs), 1);
315 if (!xtregs) {
316 return 0;
317 }
318 for (i = 0; i < 16; ++i) {
319 __get_user(env->fregs[i].f64, &xtregs->f[i]);
320 }
321 __get_user(fcr, &xtregs->fcr);
322 __get_user(fsr, &xtregs->fsr);
323 unlock_user(xtregs, xtregs_addr, 0);
324 cpu_set_fcr(env, fcr);
325 cpu_set_fsr(env, fsr);
326 } else if (xtensa_option_enabled(env->config,
327 XTENSA_OPTION_FP_COPROCESSOR)) {
328 struct target_xtensa_xtregs_fp *xtregs;
329 uint32_t fcr, fsr;
330
331 xtregs = lock_user(VERIFY_READ, xtregs_addr,
332 sizeof(*xtregs), 1);
333 if (!xtregs) {
334 return 0;
335 }
336 for (i = 0; i < 16; ++i) {
337 __get_user(env->fregs[i].f32[FP_F32_LOW], &xtregs->f[i]);
338 }
339 __get_user(fcr, &xtregs->fcr);
340 __get_user(fsr, &xtregs->fsr);
341 unlock_user(xtregs, xtregs_addr, 0);
342 cpu_set_fcr(env, fcr);
343 cpu_set_fsr(env, fsr);
344 }
345 }
346 }
347 return 1;
348 }
349
350 long do_rt_sigreturn(CPUXtensaState *env)
351 {
352 abi_ulong frame_addr = env->regs[1];
353 struct target_rt_sigframe *frame;
354 sigset_t set;
355
356 trace_user_do_rt_sigreturn(env, frame_addr);
357 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
358 force_sig(TARGET_SIGSEGV);
359 return -QEMU_ESIGRETURN;
360 }
361 target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
362 set_sigmask(&set);
363
364 if (!restore_sigcontext(env, frame)) {
365 goto badframe;
366 }
367 target_restore_altstack(&frame->uc.tuc_stack, env);
368
369 unlock_user_struct(frame, frame_addr, 0);
370 return -QEMU_ESIGRETURN;
371
372 badframe:
373 unlock_user_struct(frame, frame_addr, 0);
374 force_sig(TARGET_SIGSEGV);
375 return -QEMU_ESIGRETURN;
376 }
377
378 void setup_sigtramp(abi_ulong sigtramp_page)
379 {
380 uint8_t *tramp = lock_user(VERIFY_WRITE, sigtramp_page, 6, 0);
381 assert(tramp != NULL);
382
383 default_rt_sigreturn = sigtramp_page;
384 install_sigtramp(tramp);
385 unlock_user(tramp, sigtramp_page, 6);
386 }