]>
Commit | Line | Data |
---|---|---|
befb7447 LV |
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 | */ | |
9f172adb LV |
19 | #include "qemu/osdep.h" |
20 | #include "qemu.h" | |
3b249d26 | 21 | #include "user-internals.h" |
9f172adb LV |
22 | #include "signal-common.h" |
23 | #include "linux-user/trace.h" | |
24 | ||
f8ea624e RH |
25 | /* A Sparc register window */ |
26 | struct target_reg_window { | |
9f172adb LV |
27 | abi_ulong locals[8]; |
28 | abi_ulong ins[8]; | |
f8ea624e RH |
29 | }; |
30 | ||
31 | /* A Sparc stack frame. */ | |
32 | struct target_stackf { | |
33 | /* | |
34 | * Since qemu does not reference fp or callers_pc directly, | |
35 | * it's simpler to treat fp and callers_pc as elements of ins[], | |
36 | * and then bundle locals[] and ins[] into reg_window. | |
37 | */ | |
38 | struct target_reg_window win; | |
39 | /* | |
40 | * Similarly, bundle structptr and xxargs into xargs[]. | |
41 | * This portion of the struct is part of the function call abi, | |
42 | * and belongs to the callee for spilling argument registers. | |
43 | */ | |
44 | abi_ulong xargs[8]; | |
9f172adb LV |
45 | }; |
46 | ||
71cda6e9 | 47 | struct target_siginfo_fpu { |
11670e84 RH |
48 | #ifdef TARGET_SPARC64 |
49 | uint64_t si_double_regs[32]; | |
50 | uint64_t si_fsr; | |
51 | uint64_t si_gsr; | |
52 | uint64_t si_fprs; | |
53 | #else | |
71cda6e9 RH |
54 | /* It is more convenient for qemu to move doubles, not singles. */ |
55 | uint64_t si_double_regs[16]; | |
56 | uint32_t si_fsr; | |
57 | uint32_t si_fpqdepth; | |
9f172adb | 58 | struct { |
71cda6e9 RH |
59 | uint32_t insn_addr; |
60 | uint32_t insn; | |
9f172adb | 61 | } si_fpqueue [16]; |
11670e84 | 62 | #endif |
71cda6e9 | 63 | }; |
9f172adb | 64 | |
bb3347f8 | 65 | #ifdef TARGET_ARCH_HAS_SETUP_FRAME |
9f172adb | 66 | struct target_signal_frame { |
f8ea624e | 67 | struct target_stackf ss; |
a1181d53 | 68 | struct target_pt_regs regs; |
71cda6e9 RH |
69 | uint32_t si_mask; |
70 | abi_ulong fpu_save; | |
71 | uint32_t insns[2] QEMU_ALIGNED(8); | |
72 | abi_ulong extramask[TARGET_NSIG_WORDS - 1]; | |
73 | abi_ulong extra_size; /* Should be 0 */ | |
819f6df1 | 74 | abi_ulong rwin_save; |
9f172adb | 75 | }; |
bb3347f8 | 76 | #endif |
9f172adb | 77 | |
e76f2f84 RH |
78 | struct target_rt_signal_frame { |
79 | struct target_stackf ss; | |
80 | target_siginfo_t info; | |
81 | struct target_pt_regs regs; | |
bb3347f8 RH |
82 | #if defined(TARGET_SPARC64) && !defined(TARGET_ABI32) |
83 | abi_ulong fpu_save; | |
84 | target_stack_t stack; | |
85 | target_sigset_t mask; | |
86 | #else | |
e76f2f84 RH |
87 | target_sigset_t mask; |
88 | abi_ulong fpu_save; | |
89 | uint32_t insns[2]; | |
90 | target_stack_t stack; | |
91 | abi_ulong extra_size; /* Should be 0 */ | |
bb3347f8 | 92 | #endif |
e76f2f84 RH |
93 | abi_ulong rwin_save; |
94 | }; | |
95 | ||
a0774ec4 RH |
96 | static abi_ulong get_sigframe(struct target_sigaction *sa, |
97 | CPUSPARCState *env, | |
98 | size_t framesize) | |
9f172adb | 99 | { |
465e237b | 100 | abi_ulong sp = get_sp_from_cpustate(env); |
9f172adb | 101 | |
465e237b LV |
102 | /* |
103 | * If we are on the alternate signal stack and would overflow it, don't. | |
104 | * Return an always-bogus address instead so we will die with SIGSEGV. | |
a0774ec4 | 105 | */ |
465e237b | 106 | if (on_sig_stack(sp) && !likely(on_sig_stack(sp - framesize))) { |
a0774ec4 | 107 | return -1; |
465e237b | 108 | } |
9f172adb LV |
109 | |
110 | /* This is the X/Open sanctioned signal stack switching. */ | |
465e237b LV |
111 | sp = target_sigsp(sp, sa) - framesize; |
112 | ||
a0774ec4 RH |
113 | /* |
114 | * Always align the stack frame. This handles two cases. First, | |
465e237b LV |
115 | * sigaltstack need not be mindful of platform specific stack |
116 | * alignment. Second, if we took this signal because the stack | |
117 | * is not aligned properly, we'd like to take the signal cleanly | |
118 | * and report that. | |
119 | */ | |
120 | sp &= ~15UL; | |
121 | ||
122 | return sp; | |
9f172adb LV |
123 | } |
124 | ||
a1181d53 | 125 | static void save_pt_regs(struct target_pt_regs *regs, CPUSPARCState *env) |
9f172adb | 126 | { |
a1181d53 RH |
127 | int i; |
128 | ||
129 | #if defined(TARGET_SPARC64) && !defined(TARGET_ABI32) | |
130 | __put_user(sparc64_tstate(env), ®s->tstate); | |
131 | /* TODO: magic should contain PT_REG_MAGIC + %tt. */ | |
132 | __put_user(0, ®s->magic); | |
133 | #else | |
134 | __put_user(cpu_get_psr(env), ®s->psr); | |
135 | #endif | |
136 | ||
137 | __put_user(env->pc, ®s->pc); | |
138 | __put_user(env->npc, ®s->npc); | |
139 | __put_user(env->y, ®s->y); | |
140 | ||
141 | for (i = 0; i < 8; i++) { | |
142 | __put_user(env->gregs[i], ®s->u_regs[i]); | |
9f172adb | 143 | } |
a1181d53 RH |
144 | for (i = 0; i < 8; i++) { |
145 | __put_user(env->regwptr[WREG_O0 + i], ®s->u_regs[i + 8]); | |
146 | } | |
147 | } | |
148 | ||
149 | static void restore_pt_regs(struct target_pt_regs *regs, CPUSPARCState *env) | |
150 | { | |
151 | int i; | |
152 | ||
153 | #if defined(TARGET_SPARC64) && !defined(TARGET_ABI32) | |
154 | /* User can only change condition codes and %asi in %tstate. */ | |
155 | uint64_t tstate; | |
156 | __get_user(tstate, ®s->tstate); | |
157 | cpu_put_ccr(env, tstate >> 32); | |
158 | env->asi = extract64(tstate, 24, 8); | |
159 | #else | |
160 | /* | |
161 | * User can only change condition codes and FPU enabling in %psr. | |
162 | * But don't bother with FPU enabling, since a real kernel would | |
163 | * just re-enable the FPU upon the next fpu trap. | |
164 | */ | |
165 | uint32_t psr; | |
166 | __get_user(psr, ®s->psr); | |
167 | env->psr = (psr & PSR_ICC) | (env->psr & ~PSR_ICC); | |
168 | #endif | |
169 | ||
170 | /* Note that pc and npc are handled in the caller. */ | |
171 | ||
172 | __get_user(env->y, ®s->y); | |
173 | ||
174 | for (i = 0; i < 8; i++) { | |
175 | __get_user(env->gregs[i], ®s->u_regs[i]); | |
176 | } | |
177 | for (i = 0; i < 8; i++) { | |
178 | __get_user(env->regwptr[WREG_O0 + i], ®s->u_regs[i + 8]); | |
9f172adb | 179 | } |
9f172adb LV |
180 | } |
181 | ||
44a5f861 RH |
182 | static void save_reg_win(struct target_reg_window *win, CPUSPARCState *env) |
183 | { | |
184 | int i; | |
185 | ||
186 | for (i = 0; i < 8; i++) { | |
187 | __put_user(env->regwptr[i + WREG_L0], &win->locals[i]); | |
188 | } | |
189 | for (i = 0; i < 8; i++) { | |
190 | __put_user(env->regwptr[i + WREG_I0], &win->ins[i]); | |
191 | } | |
192 | } | |
193 | ||
71cda6e9 RH |
194 | static void save_fpu(struct target_siginfo_fpu *fpu, CPUSPARCState *env) |
195 | { | |
196 | int i; | |
197 | ||
11670e84 RH |
198 | #ifdef TARGET_SPARC64 |
199 | for (i = 0; i < 32; ++i) { | |
200 | __put_user(env->fpr[i].ll, &fpu->si_double_regs[i]); | |
201 | } | |
202 | __put_user(env->fsr, &fpu->si_fsr); | |
203 | __put_user(env->gsr, &fpu->si_gsr); | |
204 | __put_user(env->fprs, &fpu->si_fprs); | |
205 | #else | |
71cda6e9 RH |
206 | for (i = 0; i < 16; ++i) { |
207 | __put_user(env->fpr[i].ll, &fpu->si_double_regs[i]); | |
208 | } | |
209 | __put_user(env->fsr, &fpu->si_fsr); | |
210 | __put_user(0, &fpu->si_fpqdepth); | |
11670e84 | 211 | #endif |
71cda6e9 RH |
212 | } |
213 | ||
214 | static void restore_fpu(struct target_siginfo_fpu *fpu, CPUSPARCState *env) | |
215 | { | |
216 | int i; | |
217 | ||
11670e84 RH |
218 | #ifdef TARGET_SPARC64 |
219 | uint64_t fprs; | |
220 | __get_user(fprs, &fpu->si_fprs); | |
221 | ||
222 | /* In case the user mucks about with FPRS, restore as directed. */ | |
223 | if (fprs & FPRS_DL) { | |
224 | for (i = 0; i < 16; ++i) { | |
225 | __get_user(env->fpr[i].ll, &fpu->si_double_regs[i]); | |
226 | } | |
227 | } | |
228 | if (fprs & FPRS_DU) { | |
229 | for (i = 16; i < 32; ++i) { | |
230 | __get_user(env->fpr[i].ll, &fpu->si_double_regs[i]); | |
231 | } | |
232 | } | |
233 | __get_user(env->fsr, &fpu->si_fsr); | |
234 | __get_user(env->gsr, &fpu->si_gsr); | |
235 | env->fprs |= fprs; | |
236 | #else | |
71cda6e9 RH |
237 | for (i = 0; i < 16; ++i) { |
238 | __get_user(env->fpr[i].ll, &fpu->si_double_regs[i]); | |
239 | } | |
240 | __get_user(env->fsr, &fpu->si_fsr); | |
11670e84 | 241 | #endif |
71cda6e9 | 242 | } |
9f172adb | 243 | |
bb3347f8 | 244 | #ifdef TARGET_ARCH_HAS_SETUP_FRAME |
9f172adb LV |
245 | void setup_frame(int sig, struct target_sigaction *ka, |
246 | target_sigset_t *set, CPUSPARCState *env) | |
247 | { | |
248 | abi_ulong sf_addr; | |
249 | struct target_signal_frame *sf; | |
71cda6e9 RH |
250 | size_t sf_size = sizeof(*sf) + sizeof(struct target_siginfo_fpu); |
251 | int i; | |
9f172adb | 252 | |
71cda6e9 | 253 | sf_addr = get_sigframe(ka, env, sf_size); |
9f172adb LV |
254 | trace_user_setup_frame(env, sf_addr); |
255 | ||
71cda6e9 | 256 | sf = lock_user(VERIFY_WRITE, sf_addr, sf_size, 0); |
9f172adb | 257 | if (!sf) { |
757d2601 RH |
258 | force_sigsegv(sig); |
259 | return; | |
9f172adb | 260 | } |
71cda6e9 | 261 | |
9f172adb | 262 | /* 2. Save the current process state */ |
a1181d53 | 263 | save_pt_regs(&sf->regs, env); |
9f172adb LV |
264 | __put_user(0, &sf->extra_size); |
265 | ||
71cda6e9 RH |
266 | save_fpu((struct target_siginfo_fpu *)(sf + 1), env); |
267 | __put_user(sf_addr + sizeof(*sf), &sf->fpu_save); | |
9f172adb | 268 | |
819f6df1 RH |
269 | __put_user(0, &sf->rwin_save); /* TODO: save_rwin_state */ |
270 | ||
a1181d53 | 271 | __put_user(set->sig[0], &sf->si_mask); |
9f172adb LV |
272 | for (i = 0; i < TARGET_NSIG_WORDS - 1; i++) { |
273 | __put_user(set->sig[i + 1], &sf->extramask[i]); | |
274 | } | |
275 | ||
44a5f861 | 276 | save_reg_win(&sf->ss.win, env); |
9f172adb LV |
277 | |
278 | /* 3. signal handler back-trampoline and parameters */ | |
8d9c72a2 | 279 | env->regwptr[WREG_SP] = sf_addr; |
80180eb2 RH |
280 | env->regwptr[WREG_O0] = sig; |
281 | env->regwptr[WREG_O1] = sf_addr + | |
a1181d53 | 282 | offsetof(struct target_signal_frame, regs); |
80180eb2 | 283 | env->regwptr[WREG_O2] = sf_addr + |
a1181d53 | 284 | offsetof(struct target_signal_frame, regs); |
9f172adb LV |
285 | |
286 | /* 4. signal handler */ | |
287 | env->pc = ka->_sa_handler; | |
757d2601 RH |
288 | env->npc = env->pc + 4; |
289 | ||
9f172adb LV |
290 | /* 5. return to kernel instructions */ |
291 | if (ka->ka_restorer) { | |
80180eb2 | 292 | env->regwptr[WREG_O7] = ka->ka_restorer; |
9f172adb | 293 | } else { |
80180eb2 | 294 | env->regwptr[WREG_O7] = sf_addr + |
9f172adb LV |
295 | offsetof(struct target_signal_frame, insns) - 2 * 4; |
296 | ||
297 | /* mov __NR_sigreturn, %g1 */ | |
757d2601 | 298 | __put_user(0x821020d8u, &sf->insns[0]); |
9f172adb | 299 | /* t 0x10 */ |
757d2601 | 300 | __put_user(0x91d02010u, &sf->insns[1]); |
9f172adb | 301 | } |
71cda6e9 | 302 | unlock_user(sf, sf_addr, sf_size); |
9f172adb | 303 | } |
bb3347f8 | 304 | #endif /* TARGET_ARCH_HAS_SETUP_FRAME */ |
9f172adb LV |
305 | |
306 | void setup_rt_frame(int sig, struct target_sigaction *ka, | |
307 | target_siginfo_t *info, | |
308 | target_sigset_t *set, CPUSPARCState *env) | |
309 | { | |
e76f2f84 RH |
310 | abi_ulong sf_addr; |
311 | struct target_rt_signal_frame *sf; | |
312 | size_t sf_size = sizeof(*sf) + sizeof(struct target_siginfo_fpu); | |
313 | ||
314 | sf_addr = get_sigframe(ka, env, sf_size); | |
315 | trace_user_setup_rt_frame(env, sf_addr); | |
316 | ||
317 | sf = lock_user(VERIFY_WRITE, sf_addr, sf_size, 0); | |
318 | if (!sf) { | |
319 | force_sigsegv(sig); | |
320 | return; | |
321 | } | |
322 | ||
323 | /* 2. Save the current process state */ | |
324 | save_reg_win(&sf->ss.win, env); | |
325 | save_pt_regs(&sf->regs, env); | |
326 | ||
327 | save_fpu((struct target_siginfo_fpu *)(sf + 1), env); | |
328 | __put_user(sf_addr + sizeof(*sf), &sf->fpu_save); | |
329 | ||
330 | __put_user(0, &sf->rwin_save); /* TODO: save_rwin_state */ | |
331 | ||
332 | tswap_siginfo(&sf->info, info); | |
333 | tswap_sigset(&sf->mask, set); | |
334 | target_save_altstack(&sf->stack, env); | |
335 | ||
bb3347f8 | 336 | #ifdef TARGET_ABI32 |
e76f2f84 | 337 | __put_user(0, &sf->extra_size); |
bb3347f8 | 338 | #endif |
e76f2f84 RH |
339 | |
340 | /* 3. signal handler back-trampoline and parameters */ | |
bb3347f8 | 341 | env->regwptr[WREG_SP] = sf_addr - TARGET_STACK_BIAS; |
e76f2f84 RH |
342 | env->regwptr[WREG_O0] = sig; |
343 | env->regwptr[WREG_O1] = | |
344 | sf_addr + offsetof(struct target_rt_signal_frame, info); | |
bb3347f8 | 345 | #ifdef TARGET_ABI32 |
e76f2f84 RH |
346 | env->regwptr[WREG_O2] = |
347 | sf_addr + offsetof(struct target_rt_signal_frame, regs); | |
bb3347f8 RH |
348 | #else |
349 | env->regwptr[WREG_O2] = env->regwptr[WREG_O1]; | |
350 | #endif | |
e76f2f84 RH |
351 | |
352 | /* 4. signal handler */ | |
353 | env->pc = ka->_sa_handler; | |
354 | env->npc = env->pc + 4; | |
355 | ||
356 | /* 5. return to kernel instructions */ | |
bb3347f8 | 357 | #ifdef TARGET_ABI32 |
e76f2f84 RH |
358 | if (ka->ka_restorer) { |
359 | env->regwptr[WREG_O7] = ka->ka_restorer; | |
360 | } else { | |
361 | env->regwptr[WREG_O7] = | |
362 | sf_addr + offsetof(struct target_rt_signal_frame, insns) - 2 * 4; | |
363 | ||
364 | /* mov __NR_rt_sigreturn, %g1 */ | |
365 | __put_user(0x82102065u, &sf->insns[0]); | |
366 | /* t 0x10 */ | |
367 | __put_user(0x91d02010u, &sf->insns[1]); | |
368 | } | |
bb3347f8 RH |
369 | #else |
370 | env->regwptr[WREG_O7] = ka->ka_restorer; | |
371 | #endif | |
372 | ||
e76f2f84 | 373 | unlock_user(sf, sf_addr, sf_size); |
9f172adb LV |
374 | } |
375 | ||
376 | long do_sigreturn(CPUSPARCState *env) | |
377 | { | |
bb3347f8 | 378 | #ifdef TARGET_ARCH_HAS_SETUP_FRAME |
9f172adb | 379 | abi_ulong sf_addr; |
1176e57a | 380 | struct target_signal_frame *sf = NULL; |
71cda6e9 | 381 | abi_ulong pc, npc, ptr; |
9f172adb LV |
382 | target_sigset_t set; |
383 | sigset_t host_set; | |
bba390cb | 384 | int i; |
9f172adb | 385 | |
8d9c72a2 | 386 | sf_addr = env->regwptr[WREG_SP]; |
9f172adb | 387 | trace_user_do_sigreturn(env, sf_addr); |
9f172adb LV |
388 | |
389 | /* 1. Make sure we are not getting garbage from the user */ | |
1176e57a RH |
390 | if ((sf_addr & 15) || !lock_user_struct(VERIFY_READ, sf, sf_addr, 1)) { |
391 | goto segv_and_exit; | |
392 | } | |
9f172adb | 393 | |
1176e57a RH |
394 | /* Make sure stack pointer is aligned. */ |
395 | __get_user(ptr, &sf->regs.u_regs[14]); | |
396 | if (ptr & 7) { | |
9f172adb | 397 | goto segv_and_exit; |
1176e57a | 398 | } |
9f172adb | 399 | |
1176e57a RH |
400 | /* Make sure instruction pointers are aligned. */ |
401 | __get_user(pc, &sf->regs.pc); | |
a1181d53 | 402 | __get_user(npc, &sf->regs.npc); |
9f172adb LV |
403 | if ((pc | npc) & 3) { |
404 | goto segv_and_exit; | |
405 | } | |
406 | ||
407 | /* 2. Restore the state */ | |
a1181d53 | 408 | restore_pt_regs(&sf->regs, env); |
9f172adb LV |
409 | env->pc = pc; |
410 | env->npc = npc; | |
9f172adb | 411 | |
71cda6e9 RH |
412 | __get_user(ptr, &sf->fpu_save); |
413 | if (ptr) { | |
414 | struct target_siginfo_fpu *fpu; | |
415 | if ((ptr & 3) || !lock_user_struct(VERIFY_READ, fpu, ptr, 1)) { | |
416 | goto segv_and_exit; | |
417 | } | |
418 | restore_fpu(fpu, env); | |
419 | unlock_user_struct(fpu, ptr, 0); | |
420 | } | |
9f172adb | 421 | |
819f6df1 RH |
422 | __get_user(ptr, &sf->rwin_save); |
423 | if (ptr) { | |
424 | goto segv_and_exit; /* TODO: restore_rwin */ | |
425 | } | |
426 | ||
a1181d53 RH |
427 | __get_user(set.sig[0], &sf->si_mask); |
428 | for (i = 1; i < TARGET_NSIG_WORDS; i++) { | |
9f172adb LV |
429 | __get_user(set.sig[i], &sf->extramask[i - 1]); |
430 | } | |
431 | ||
432 | target_to_host_sigset_internal(&host_set, &set); | |
433 | set_sigmask(&host_set); | |
434 | ||
9f172adb LV |
435 | unlock_user_struct(sf, sf_addr, 0); |
436 | return -TARGET_QEMU_ESIGRETURN; | |
437 | ||
1176e57a | 438 | segv_and_exit: |
9f172adb LV |
439 | unlock_user_struct(sf, sf_addr, 0); |
440 | force_sig(TARGET_SIGSEGV); | |
441 | return -TARGET_QEMU_ESIGRETURN; | |
bb3347f8 RH |
442 | #else |
443 | return -TARGET_ENOSYS; | |
444 | #endif | |
9f172adb LV |
445 | } |
446 | ||
447 | long do_rt_sigreturn(CPUSPARCState *env) | |
448 | { | |
e76f2f84 RH |
449 | abi_ulong sf_addr, tpc, tnpc, ptr; |
450 | struct target_rt_signal_frame *sf = NULL; | |
451 | sigset_t set; | |
452 | ||
453 | sf_addr = get_sp_from_cpustate(env); | |
454 | trace_user_do_rt_sigreturn(env, sf_addr); | |
455 | ||
456 | /* 1. Make sure we are not getting garbage from the user */ | |
457 | if ((sf_addr & 15) || !lock_user_struct(VERIFY_READ, sf, sf_addr, 1)) { | |
458 | goto segv_and_exit; | |
459 | } | |
460 | ||
461 | /* Validate SP alignment. */ | |
462 | __get_user(ptr, &sf->regs.u_regs[8 + WREG_SP]); | |
463 | if ((ptr + TARGET_STACK_BIAS) & 7) { | |
464 | goto segv_and_exit; | |
465 | } | |
466 | ||
467 | /* Validate PC and NPC alignment. */ | |
468 | __get_user(tpc, &sf->regs.pc); | |
469 | __get_user(tnpc, &sf->regs.npc); | |
470 | if ((tpc | tnpc) & 3) { | |
471 | goto segv_and_exit; | |
472 | } | |
473 | ||
474 | /* 2. Restore the state */ | |
475 | restore_pt_regs(&sf->regs, env); | |
476 | ||
477 | __get_user(ptr, &sf->fpu_save); | |
478 | if (ptr) { | |
479 | struct target_siginfo_fpu *fpu; | |
480 | if ((ptr & 7) || !lock_user_struct(VERIFY_READ, fpu, ptr, 1)) { | |
481 | goto segv_and_exit; | |
482 | } | |
483 | restore_fpu(fpu, env); | |
484 | unlock_user_struct(fpu, ptr, 0); | |
485 | } | |
486 | ||
487 | __get_user(ptr, &sf->rwin_save); | |
488 | if (ptr) { | |
489 | goto segv_and_exit; /* TODO: restore_rwin_state */ | |
490 | } | |
491 | ||
492 | target_restore_altstack(&sf->stack, env); | |
493 | target_to_host_sigset(&set, &sf->mask); | |
494 | set_sigmask(&set); | |
495 | ||
496 | env->pc = tpc; | |
497 | env->npc = tnpc; | |
498 | ||
499 | unlock_user_struct(sf, sf_addr, 0); | |
500 | return -TARGET_QEMU_ESIGRETURN; | |
501 | ||
502 | segv_and_exit: | |
503 | unlock_user_struct(sf, sf_addr, 0); | |
504 | force_sig(TARGET_SIGSEGV); | |
505 | return -TARGET_QEMU_ESIGRETURN; | |
9f172adb LV |
506 | } |
507 | ||
508 | #if defined(TARGET_SPARC64) && !defined(TARGET_ABI32) | |
509 | #define SPARC_MC_TSTATE 0 | |
510 | #define SPARC_MC_PC 1 | |
511 | #define SPARC_MC_NPC 2 | |
512 | #define SPARC_MC_Y 3 | |
513 | #define SPARC_MC_G1 4 | |
514 | #define SPARC_MC_G2 5 | |
515 | #define SPARC_MC_G3 6 | |
516 | #define SPARC_MC_G4 7 | |
517 | #define SPARC_MC_G5 8 | |
518 | #define SPARC_MC_G6 9 | |
519 | #define SPARC_MC_G7 10 | |
520 | #define SPARC_MC_O0 11 | |
521 | #define SPARC_MC_O1 12 | |
522 | #define SPARC_MC_O2 13 | |
523 | #define SPARC_MC_O3 14 | |
524 | #define SPARC_MC_O4 15 | |
525 | #define SPARC_MC_O5 16 | |
526 | #define SPARC_MC_O6 17 | |
527 | #define SPARC_MC_O7 18 | |
528 | #define SPARC_MC_NGREG 19 | |
529 | ||
530 | typedef abi_ulong target_mc_greg_t; | |
531 | typedef target_mc_greg_t target_mc_gregset_t[SPARC_MC_NGREG]; | |
532 | ||
533 | struct target_mc_fq { | |
b8ae597f | 534 | abi_ulong mcfq_addr; |
9f172adb LV |
535 | uint32_t mcfq_insn; |
536 | }; | |
537 | ||
b8ae597f PM |
538 | /* |
539 | * Note the manual 16-alignment; the kernel gets this because it | |
540 | * includes a "long double qregs[16]" in the mcpu_fregs union, | |
541 | * which we can't do. | |
542 | */ | |
9f172adb LV |
543 | struct target_mc_fpu { |
544 | union { | |
545 | uint32_t sregs[32]; | |
546 | uint64_t dregs[32]; | |
547 | //uint128_t qregs[16]; | |
548 | } mcfpu_fregs; | |
549 | abi_ulong mcfpu_fsr; | |
550 | abi_ulong mcfpu_fprs; | |
551 | abi_ulong mcfpu_gsr; | |
b8ae597f | 552 | abi_ulong mcfpu_fq; |
9f172adb LV |
553 | unsigned char mcfpu_qcnt; |
554 | unsigned char mcfpu_qentsz; | |
555 | unsigned char mcfpu_enab; | |
b8ae597f | 556 | } __attribute__((aligned(16))); |
9f172adb LV |
557 | typedef struct target_mc_fpu target_mc_fpu_t; |
558 | ||
559 | typedef struct { | |
560 | target_mc_gregset_t mc_gregs; | |
561 | target_mc_greg_t mc_fp; | |
562 | target_mc_greg_t mc_i7; | |
563 | target_mc_fpu_t mc_fpregs; | |
564 | } target_mcontext_t; | |
565 | ||
566 | struct target_ucontext { | |
b8ae597f | 567 | abi_ulong tuc_link; |
9f172adb LV |
568 | abi_ulong tuc_flags; |
569 | target_sigset_t tuc_sigmask; | |
570 | target_mcontext_t tuc_mcontext; | |
571 | }; | |
572 | ||
9f172adb LV |
573 | /* {set, get}context() needed for 64-bit SparcLinux userland. */ |
574 | void sparc64_set_context(CPUSPARCState *env) | |
575 | { | |
576 | abi_ulong ucp_addr; | |
577 | struct target_ucontext *ucp; | |
578 | target_mc_gregset_t *grp; | |
246ff442 | 579 | target_mc_fpu_t *fpup; |
9f172adb | 580 | abi_ulong pc, npc, tstate; |
9f172adb | 581 | unsigned int i; |
246ff442 | 582 | unsigned char fenab; |
9f172adb | 583 | |
80180eb2 | 584 | ucp_addr = env->regwptr[WREG_O0]; |
9f172adb LV |
585 | if (!lock_user_struct(VERIFY_READ, ucp, ucp_addr, 1)) { |
586 | goto do_sigsegv; | |
587 | } | |
588 | grp = &ucp->tuc_mcontext.mc_gregs; | |
589 | __get_user(pc, &((*grp)[SPARC_MC_PC])); | |
590 | __get_user(npc, &((*grp)[SPARC_MC_NPC])); | |
591 | if ((pc | npc) & 3) { | |
592 | goto do_sigsegv; | |
593 | } | |
80180eb2 | 594 | if (env->regwptr[WREG_O1]) { |
9f172adb LV |
595 | target_sigset_t target_set; |
596 | sigset_t set; | |
597 | ||
598 | if (TARGET_NSIG_WORDS == 1) { | |
599 | __get_user(target_set.sig[0], &ucp->tuc_sigmask.sig[0]); | |
600 | } else { | |
601 | abi_ulong *src, *dst; | |
602 | src = ucp->tuc_sigmask.sig; | |
603 | dst = target_set.sig; | |
604 | for (i = 0; i < TARGET_NSIG_WORDS; i++, dst++, src++) { | |
605 | __get_user(*dst, src); | |
606 | } | |
607 | } | |
608 | target_to_host_sigset_internal(&set, &target_set); | |
609 | set_sigmask(&set); | |
610 | } | |
611 | env->pc = pc; | |
612 | env->npc = npc; | |
613 | __get_user(env->y, &((*grp)[SPARC_MC_Y])); | |
614 | __get_user(tstate, &((*grp)[SPARC_MC_TSTATE])); | |
7a5805a0 | 615 | /* Honour TSTATE_ASI, TSTATE_ICC and TSTATE_XCC only */ |
9f172adb | 616 | env->asi = (tstate >> 24) & 0xff; |
7a5805a0 | 617 | cpu_put_ccr(env, (tstate >> 32) & 0xff); |
9f172adb LV |
618 | __get_user(env->gregs[1], (&(*grp)[SPARC_MC_G1])); |
619 | __get_user(env->gregs[2], (&(*grp)[SPARC_MC_G2])); | |
620 | __get_user(env->gregs[3], (&(*grp)[SPARC_MC_G3])); | |
621 | __get_user(env->gregs[4], (&(*grp)[SPARC_MC_G4])); | |
622 | __get_user(env->gregs[5], (&(*grp)[SPARC_MC_G5])); | |
623 | __get_user(env->gregs[6], (&(*grp)[SPARC_MC_G6])); | |
0ad20314 | 624 | /* Skip g7 as that's the thread register in userspace */ |
266b4158 PM |
625 | |
626 | /* | |
627 | * Note that unlike the kernel, we didn't need to mess with the | |
628 | * guest register window state to save it into a pt_regs to run | |
629 | * the kernel. So for us the guest's O regs are still in WREG_O* | |
630 | * (unlike the kernel which has put them in UREG_I* in a pt_regs) | |
631 | * and the fp and i7 are still in WREG_I6 and WREG_I7 and don't | |
632 | * need to be written back to userspace memory. | |
633 | */ | |
80180eb2 RH |
634 | __get_user(env->regwptr[WREG_O0], (&(*grp)[SPARC_MC_O0])); |
635 | __get_user(env->regwptr[WREG_O1], (&(*grp)[SPARC_MC_O1])); | |
636 | __get_user(env->regwptr[WREG_O2], (&(*grp)[SPARC_MC_O2])); | |
637 | __get_user(env->regwptr[WREG_O3], (&(*grp)[SPARC_MC_O3])); | |
638 | __get_user(env->regwptr[WREG_O4], (&(*grp)[SPARC_MC_O4])); | |
639 | __get_user(env->regwptr[WREG_O5], (&(*grp)[SPARC_MC_O5])); | |
640 | __get_user(env->regwptr[WREG_O6], (&(*grp)[SPARC_MC_O6])); | |
641 | __get_user(env->regwptr[WREG_O7], (&(*grp)[SPARC_MC_O7])); | |
9f172adb | 642 | |
266b4158 PM |
643 | __get_user(env->regwptr[WREG_FP], &(ucp->tuc_mcontext.mc_fp)); |
644 | __get_user(env->regwptr[WREG_I7], &(ucp->tuc_mcontext.mc_i7)); | |
9f172adb | 645 | |
246ff442 PM |
646 | fpup = &ucp->tuc_mcontext.mc_fpregs; |
647 | ||
648 | __get_user(fenab, &(fpup->mcfpu_enab)); | |
649 | if (fenab) { | |
650 | abi_ulong fprs; | |
651 | ||
652 | /* | |
653 | * We use the FPRS from the guest only in deciding whether | |
654 | * to restore the upper, lower, or both banks of the FPU regs. | |
655 | * The kernel here writes the FPU register data into the | |
656 | * process's current_thread_info state and unconditionally | |
657 | * clears FPRS and TSTATE_PEF: this disables the FPU so that the | |
658 | * next FPU-disabled trap will copy the data out of | |
659 | * current_thread_info and into the real FPU registers. | |
660 | * QEMU doesn't need to handle lazy-FPU-state-restoring like that, | |
661 | * so we always load the data directly into the FPU registers | |
662 | * and leave FPRS and TSTATE_PEF alone (so the FPU stays enabled). | |
663 | * Note that because we (and the kernel) always write zeroes for | |
664 | * the fenab and fprs in sparc64_get_context() none of this code | |
665 | * will execute unless the guest manually constructed or changed | |
666 | * the context structure. | |
667 | */ | |
668 | __get_user(fprs, &(fpup->mcfpu_fprs)); | |
669 | if (fprs & FPRS_DL) { | |
670 | for (i = 0; i < 16; i++) { | |
671 | __get_user(env->fpr[i].ll, &(fpup->mcfpu_fregs.dregs[i])); | |
672 | } | |
673 | } | |
674 | if (fprs & FPRS_DU) { | |
675 | for (i = 16; i < 32; i++) { | |
676 | __get_user(env->fpr[i].ll, &(fpup->mcfpu_fregs.dregs[i])); | |
9f172adb LV |
677 | } |
678 | } | |
246ff442 PM |
679 | __get_user(env->fsr, &(fpup->mcfpu_fsr)); |
680 | __get_user(env->gsr, &(fpup->mcfpu_gsr)); | |
9f172adb | 681 | } |
9f172adb LV |
682 | unlock_user_struct(ucp, ucp_addr, 0); |
683 | return; | |
684 | do_sigsegv: | |
685 | unlock_user_struct(ucp, ucp_addr, 0); | |
686 | force_sig(TARGET_SIGSEGV); | |
687 | } | |
688 | ||
689 | void sparc64_get_context(CPUSPARCState *env) | |
690 | { | |
691 | abi_ulong ucp_addr; | |
692 | struct target_ucontext *ucp; | |
693 | target_mc_gregset_t *grp; | |
694 | target_mcontext_t *mcp; | |
9f172adb LV |
695 | int err; |
696 | unsigned int i; | |
697 | target_sigset_t target_set; | |
698 | sigset_t set; | |
699 | ||
80180eb2 | 700 | ucp_addr = env->regwptr[WREG_O0]; |
9f172adb LV |
701 | if (!lock_user_struct(VERIFY_WRITE, ucp, ucp_addr, 0)) { |
702 | goto do_sigsegv; | |
703 | } | |
246ff442 PM |
704 | |
705 | memset(ucp, 0, sizeof(*ucp)); | |
706 | ||
9f172adb LV |
707 | mcp = &ucp->tuc_mcontext; |
708 | grp = &mcp->mc_gregs; | |
709 | ||
710 | /* Skip over the trap instruction, first. */ | |
711 | env->pc = env->npc; | |
712 | env->npc += 4; | |
713 | ||
714 | /* If we're only reading the signal mask then do_sigprocmask() | |
715 | * is guaranteed not to fail, which is important because we don't | |
716 | * have any way to signal a failure or restart this operation since | |
717 | * this is not a normal syscall. | |
718 | */ | |
719 | err = do_sigprocmask(0, NULL, &set); | |
720 | assert(err == 0); | |
721 | host_to_target_sigset_internal(&target_set, &set); | |
722 | if (TARGET_NSIG_WORDS == 1) { | |
723 | __put_user(target_set.sig[0], | |
724 | (abi_ulong *)&ucp->tuc_sigmask); | |
725 | } else { | |
726 | abi_ulong *src, *dst; | |
727 | src = target_set.sig; | |
728 | dst = ucp->tuc_sigmask.sig; | |
729 | for (i = 0; i < TARGET_NSIG_WORDS; i++, dst++, src++) { | |
730 | __put_user(*src, dst); | |
731 | } | |
9f172adb LV |
732 | } |
733 | ||
7a5805a0 | 734 | __put_user(sparc64_tstate(env), &((*grp)[SPARC_MC_TSTATE])); |
9f172adb LV |
735 | __put_user(env->pc, &((*grp)[SPARC_MC_PC])); |
736 | __put_user(env->npc, &((*grp)[SPARC_MC_NPC])); | |
737 | __put_user(env->y, &((*grp)[SPARC_MC_Y])); | |
738 | __put_user(env->gregs[1], &((*grp)[SPARC_MC_G1])); | |
739 | __put_user(env->gregs[2], &((*grp)[SPARC_MC_G2])); | |
740 | __put_user(env->gregs[3], &((*grp)[SPARC_MC_G3])); | |
741 | __put_user(env->gregs[4], &((*grp)[SPARC_MC_G4])); | |
742 | __put_user(env->gregs[5], &((*grp)[SPARC_MC_G5])); | |
743 | __put_user(env->gregs[6], &((*grp)[SPARC_MC_G6])); | |
744 | __put_user(env->gregs[7], &((*grp)[SPARC_MC_G7])); | |
266b4158 PM |
745 | |
746 | /* | |
747 | * Note that unlike the kernel, we didn't need to mess with the | |
748 | * guest register window state to save it into a pt_regs to run | |
749 | * the kernel. So for us the guest's O regs are still in WREG_O* | |
750 | * (unlike the kernel which has put them in UREG_I* in a pt_regs) | |
751 | * and the fp and i7 are still in WREG_I6 and WREG_I7 and don't | |
752 | * need to be fished out of userspace memory. | |
753 | */ | |
80180eb2 RH |
754 | __put_user(env->regwptr[WREG_O0], &((*grp)[SPARC_MC_O0])); |
755 | __put_user(env->regwptr[WREG_O1], &((*grp)[SPARC_MC_O1])); | |
756 | __put_user(env->regwptr[WREG_O2], &((*grp)[SPARC_MC_O2])); | |
757 | __put_user(env->regwptr[WREG_O3], &((*grp)[SPARC_MC_O3])); | |
758 | __put_user(env->regwptr[WREG_O4], &((*grp)[SPARC_MC_O4])); | |
759 | __put_user(env->regwptr[WREG_O5], &((*grp)[SPARC_MC_O5])); | |
760 | __put_user(env->regwptr[WREG_O6], &((*grp)[SPARC_MC_O6])); | |
761 | __put_user(env->regwptr[WREG_O7], &((*grp)[SPARC_MC_O7])); | |
762 | ||
266b4158 PM |
763 | __put_user(env->regwptr[WREG_FP], &(mcp->mc_fp)); |
764 | __put_user(env->regwptr[WREG_I7], &(mcp->mc_i7)); | |
9f172adb | 765 | |
246ff442 PM |
766 | /* |
767 | * We don't write out the FPU state. This matches the kernel's | |
768 | * implementation (which has the code for doing this but | |
769 | * hidden behind an "if (fenab)" where fenab is always 0). | |
770 | */ | |
9f172adb | 771 | |
9f172adb LV |
772 | unlock_user_struct(ucp, ucp_addr, 1); |
773 | return; | |
774 | do_sigsegv: | |
775 | unlock_user_struct(ucp, ucp_addr, 1); | |
776 | force_sig(TARGET_SIGSEGV); | |
777 | } | |
778 | #endif |