xref: /openbmc/qemu/linux-user/sparc/signal.c (revision b6d32a06fc0984e537091cba08f2e1ed9f775d74)
1befb7447SLaurent Vivier /*
2befb7447SLaurent Vivier  *  Emulation of Linux signals
3befb7447SLaurent Vivier  *
4befb7447SLaurent Vivier  *  Copyright (c) 2003 Fabrice Bellard
5befb7447SLaurent Vivier  *
6befb7447SLaurent Vivier  *  This program is free software; you can redistribute it and/or modify
7befb7447SLaurent Vivier  *  it under the terms of the GNU General Public License as published by
8befb7447SLaurent Vivier  *  the Free Software Foundation; either version 2 of the License, or
9befb7447SLaurent Vivier  *  (at your option) any later version.
10befb7447SLaurent Vivier  *
11befb7447SLaurent Vivier  *  This program is distributed in the hope that it will be useful,
12befb7447SLaurent Vivier  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13befb7447SLaurent Vivier  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14befb7447SLaurent Vivier  *  GNU General Public License for more details.
15befb7447SLaurent Vivier  *
16befb7447SLaurent Vivier  *  You should have received a copy of the GNU General Public License
17befb7447SLaurent Vivier  *  along with this program; if not, see <http://www.gnu.org/licenses/>.
18befb7447SLaurent Vivier  */
199f172adbSLaurent Vivier #include "qemu/osdep.h"
209f172adbSLaurent Vivier #include "qemu.h"
213b249d26SPeter Maydell #include "user-internals.h"
229f172adbSLaurent Vivier #include "signal-common.h"
239f172adbSLaurent Vivier #include "linux-user/trace.h"
249f172adbSLaurent Vivier 
25f8ea624eSRichard Henderson /* A Sparc register window */
26f8ea624eSRichard Henderson struct target_reg_window {
279f172adbSLaurent Vivier     abi_ulong locals[8];
289f172adbSLaurent Vivier     abi_ulong ins[8];
29f8ea624eSRichard Henderson };
30f8ea624eSRichard Henderson 
31f8ea624eSRichard Henderson /* A Sparc stack frame. */
32f8ea624eSRichard Henderson struct target_stackf {
33f8ea624eSRichard Henderson     /*
34f8ea624eSRichard Henderson      * Since qemu does not reference fp or callers_pc directly,
35f8ea624eSRichard Henderson      * it's simpler to treat fp and callers_pc as elements of ins[],
36f8ea624eSRichard Henderson      * and then bundle locals[] and ins[] into reg_window.
379f172adbSLaurent Vivier      */
38f8ea624eSRichard Henderson     struct target_reg_window win;
39f8ea624eSRichard Henderson     /*
40f8ea624eSRichard Henderson      * Similarly, bundle structptr and xxargs into xargs[].
41f8ea624eSRichard Henderson      * This portion of the struct is part of the function call abi,
42f8ea624eSRichard Henderson      * and belongs to the callee for spilling argument registers.
43f8ea624eSRichard Henderson      */
44f8ea624eSRichard Henderson     abi_ulong xargs[8];
459f172adbSLaurent Vivier };
469f172adbSLaurent Vivier 
4771cda6e9SRichard Henderson struct target_siginfo_fpu {
4811670e84SRichard Henderson #ifdef TARGET_SPARC64
4911670e84SRichard Henderson     uint64_t si_double_regs[32];
5011670e84SRichard Henderson     uint64_t si_fsr;
5111670e84SRichard Henderson     uint64_t si_gsr;
5211670e84SRichard Henderson     uint64_t si_fprs;
5311670e84SRichard Henderson #else
5471cda6e9SRichard Henderson     /* It is more convenient for qemu to move doubles, not singles. */
5571cda6e9SRichard Henderson     uint64_t si_double_regs[16];
5671cda6e9SRichard Henderson     uint32_t si_fsr;
5771cda6e9SRichard Henderson     uint32_t si_fpqdepth;
589f172adbSLaurent Vivier     struct {
5971cda6e9SRichard Henderson         uint32_t insn_addr;
6071cda6e9SRichard Henderson         uint32_t insn;
619f172adbSLaurent Vivier     } si_fpqueue [16];
6211670e84SRichard Henderson #endif
6371cda6e9SRichard Henderson };
649f172adbSLaurent Vivier 
65bb3347f8SRichard Henderson #ifdef TARGET_ARCH_HAS_SETUP_FRAME
669f172adbSLaurent Vivier struct target_signal_frame {
67f8ea624eSRichard Henderson     struct target_stackf ss;
68a1181d53SRichard Henderson     struct target_pt_regs regs;
69a1181d53SRichard Henderson     uint32_t si_mask;
709f172adbSLaurent Vivier     abi_ulong fpu_save;
71b220cbcfSRichard Henderson     uint32_t insns[2] QEMU_ALIGNED(8);
729f172adbSLaurent Vivier     abi_ulong extramask[TARGET_NSIG_WORDS - 1];
739f172adbSLaurent Vivier     abi_ulong extra_size; /* Should be 0 */
74819f6df1SRichard Henderson     abi_ulong rwin_save;
759f172adbSLaurent Vivier };
76bb3347f8SRichard Henderson #endif
779f172adbSLaurent Vivier 
78e76f2f84SRichard Henderson struct target_rt_signal_frame {
79e76f2f84SRichard Henderson     struct target_stackf ss;
80e76f2f84SRichard Henderson     target_siginfo_t info;
81e76f2f84SRichard Henderson     struct target_pt_regs regs;
82bb3347f8SRichard Henderson #if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
83bb3347f8SRichard Henderson     abi_ulong fpu_save;
84bb3347f8SRichard Henderson     target_stack_t stack;
85bb3347f8SRichard Henderson     target_sigset_t mask;
86bb3347f8SRichard Henderson #else
87e76f2f84SRichard Henderson     target_sigset_t mask;
88e76f2f84SRichard Henderson     abi_ulong fpu_save;
89e76f2f84SRichard Henderson     uint32_t insns[2];
90e76f2f84SRichard Henderson     target_stack_t stack;
91e76f2f84SRichard Henderson     abi_ulong extra_size; /* Should be 0 */
92bb3347f8SRichard Henderson #endif
93e76f2f84SRichard Henderson     abi_ulong rwin_save;
94e76f2f84SRichard Henderson };
95e76f2f84SRichard Henderson 
get_sigframe(struct target_sigaction * sa,CPUSPARCState * env,size_t framesize)96a0774ec4SRichard Henderson static abi_ulong get_sigframe(struct target_sigaction *sa,
979f172adbSLaurent Vivier                               CPUSPARCState *env,
98a0774ec4SRichard Henderson                               size_t framesize)
999f172adbSLaurent Vivier {
100465e237bSLaurent Vivier     abi_ulong sp = get_sp_from_cpustate(env);
1019f172adbSLaurent Vivier 
102465e237bSLaurent Vivier     /*
103465e237bSLaurent Vivier      * If we are on the alternate signal stack and would overflow it, don't.
104465e237bSLaurent Vivier      * Return an always-bogus address instead so we will die with SIGSEGV.
105465e237bSLaurent Vivier      */
106465e237bSLaurent Vivier     if (on_sig_stack(sp) && !likely(on_sig_stack(sp - framesize))) {
107465e237bSLaurent Vivier         return -1;
108465e237bSLaurent Vivier     }
1099f172adbSLaurent Vivier 
1109f172adbSLaurent Vivier     /* This is the X/Open sanctioned signal stack switching.  */
111465e237bSLaurent Vivier     sp = target_sigsp(sp, sa) - framesize;
112465e237bSLaurent Vivier 
113a0774ec4SRichard Henderson     /*
114a0774ec4SRichard Henderson      * Always align the stack frame.  This handles two cases.  First,
115465e237bSLaurent Vivier      * sigaltstack need not be mindful of platform specific stack
116465e237bSLaurent Vivier      * alignment.  Second, if we took this signal because the stack
117465e237bSLaurent Vivier      * is not aligned properly, we'd like to take the signal cleanly
118465e237bSLaurent Vivier      * and report that.
119465e237bSLaurent Vivier      */
120465e237bSLaurent Vivier     sp &= ~15UL;
121465e237bSLaurent Vivier 
122465e237bSLaurent Vivier     return sp;
1239f172adbSLaurent Vivier }
1249f172adbSLaurent Vivier 
save_pt_regs(struct target_pt_regs * regs,CPUSPARCState * env)125a1181d53SRichard Henderson static void save_pt_regs(struct target_pt_regs *regs, CPUSPARCState *env)
1269f172adbSLaurent Vivier {
127a1181d53SRichard Henderson     int i;
1289f172adbSLaurent Vivier 
129a1181d53SRichard Henderson #if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
130a1181d53SRichard Henderson     __put_user(sparc64_tstate(env), &regs->tstate);
131a1181d53SRichard Henderson     /* TODO: magic should contain PT_REG_MAGIC + %tt. */
132a1181d53SRichard Henderson     __put_user(0, &regs->magic);
133a1181d53SRichard Henderson #else
134a1181d53SRichard Henderson     __put_user(cpu_get_psr(env), &regs->psr);
135a1181d53SRichard Henderson #endif
136a1181d53SRichard Henderson 
137a1181d53SRichard Henderson     __put_user(env->pc, &regs->pc);
138a1181d53SRichard Henderson     __put_user(env->npc, &regs->npc);
139a1181d53SRichard Henderson     __put_user(env->y, &regs->y);
140a1181d53SRichard Henderson 
1419f172adbSLaurent Vivier     for (i = 0; i < 8; i++) {
142a1181d53SRichard Henderson         __put_user(env->gregs[i], &regs->u_regs[i]);
1439f172adbSLaurent Vivier     }
1449f172adbSLaurent Vivier     for (i = 0; i < 8; i++) {
145a1181d53SRichard Henderson         __put_user(env->regwptr[WREG_O0 + i], &regs->u_regs[i + 8]);
1469f172adbSLaurent Vivier     }
147a1181d53SRichard Henderson }
148a1181d53SRichard Henderson 
restore_pt_regs(struct target_pt_regs * regs,CPUSPARCState * env)149a1181d53SRichard Henderson static void restore_pt_regs(struct target_pt_regs *regs, CPUSPARCState *env)
150a1181d53SRichard Henderson {
151a1181d53SRichard Henderson     int i;
152a1181d53SRichard Henderson 
153a1181d53SRichard Henderson #if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
154a1181d53SRichard Henderson     /* User can only change condition codes and %asi in %tstate. */
155a1181d53SRichard Henderson     uint64_t tstate;
156a1181d53SRichard Henderson     __get_user(tstate, &regs->tstate);
157a1181d53SRichard Henderson     cpu_put_ccr(env, tstate >> 32);
158a1181d53SRichard Henderson     env->asi = extract64(tstate, 24, 8);
159a1181d53SRichard Henderson #else
160a1181d53SRichard Henderson     /*
161a1181d53SRichard Henderson      * User can only change condition codes and FPU enabling in %psr.
162a1181d53SRichard Henderson      * But don't bother with FPU enabling, since a real kernel would
163a1181d53SRichard Henderson      * just re-enable the FPU upon the next fpu trap.
164a1181d53SRichard Henderson      */
165a1181d53SRichard Henderson     uint32_t psr;
166a1181d53SRichard Henderson     __get_user(psr, &regs->psr);
167b1fa27fcSRichard Henderson     cpu_put_psr_icc(env, psr);
168a1181d53SRichard Henderson #endif
169a1181d53SRichard Henderson 
170a1181d53SRichard Henderson     /* Note that pc and npc are handled in the caller. */
171a1181d53SRichard Henderson 
172a1181d53SRichard Henderson     __get_user(env->y, &regs->y);
173a1181d53SRichard Henderson 
174a1181d53SRichard Henderson     for (i = 0; i < 8; i++) {
175a1181d53SRichard Henderson         __get_user(env->gregs[i], &regs->u_regs[i]);
176a1181d53SRichard Henderson     }
177a1181d53SRichard Henderson     for (i = 0; i < 8; i++) {
178a1181d53SRichard Henderson         __get_user(env->regwptr[WREG_O0 + i], &regs->u_regs[i + 8]);
179a1181d53SRichard Henderson     }
1809f172adbSLaurent Vivier }
1819f172adbSLaurent Vivier 
save_reg_win(struct target_reg_window * win,CPUSPARCState * env)18244a5f861SRichard Henderson static void save_reg_win(struct target_reg_window *win, CPUSPARCState *env)
18344a5f861SRichard Henderson {
18444a5f861SRichard Henderson     int i;
18544a5f861SRichard Henderson 
18644a5f861SRichard Henderson     for (i = 0; i < 8; i++) {
18744a5f861SRichard Henderson         __put_user(env->regwptr[i + WREG_L0], &win->locals[i]);
18844a5f861SRichard Henderson     }
18944a5f861SRichard Henderson     for (i = 0; i < 8; i++) {
19044a5f861SRichard Henderson         __put_user(env->regwptr[i + WREG_I0], &win->ins[i]);
19144a5f861SRichard Henderson     }
19244a5f861SRichard Henderson }
19344a5f861SRichard Henderson 
save_fpu(struct target_siginfo_fpu * fpu,CPUSPARCState * env)19471cda6e9SRichard Henderson static void save_fpu(struct target_siginfo_fpu *fpu, CPUSPARCState *env)
19571cda6e9SRichard Henderson {
19671cda6e9SRichard Henderson     int i;
19771cda6e9SRichard Henderson 
19811670e84SRichard Henderson #ifdef TARGET_SPARC64
19911670e84SRichard Henderson     for (i = 0; i < 32; ++i) {
20011670e84SRichard Henderson         __put_user(env->fpr[i].ll, &fpu->si_double_regs[i]);
20111670e84SRichard Henderson     }
2021ccd6e13SRichard Henderson     __put_user(cpu_get_fsr(env), &fpu->si_fsr);
20311670e84SRichard Henderson     __put_user(env->gsr, &fpu->si_gsr);
20411670e84SRichard Henderson     __put_user(env->fprs, &fpu->si_fprs);
20511670e84SRichard Henderson #else
20671cda6e9SRichard Henderson     for (i = 0; i < 16; ++i) {
20771cda6e9SRichard Henderson         __put_user(env->fpr[i].ll, &fpu->si_double_regs[i]);
20871cda6e9SRichard Henderson     }
2091ccd6e13SRichard Henderson     __put_user(cpu_get_fsr(env), &fpu->si_fsr);
21071cda6e9SRichard Henderson     __put_user(0, &fpu->si_fpqdepth);
21111670e84SRichard Henderson #endif
21271cda6e9SRichard Henderson }
21371cda6e9SRichard Henderson 
restore_fpu(struct target_siginfo_fpu * fpu,CPUSPARCState * env)21471cda6e9SRichard Henderson static void restore_fpu(struct target_siginfo_fpu *fpu, CPUSPARCState *env)
21571cda6e9SRichard Henderson {
2161ccd6e13SRichard Henderson     target_ulong fsr;
21771cda6e9SRichard Henderson     int i;
21871cda6e9SRichard Henderson 
21911670e84SRichard Henderson #ifdef TARGET_SPARC64
22011670e84SRichard Henderson     uint64_t fprs;
22111670e84SRichard Henderson     __get_user(fprs, &fpu->si_fprs);
22211670e84SRichard Henderson 
22311670e84SRichard Henderson     /* In case the user mucks about with FPRS, restore as directed. */
22411670e84SRichard Henderson     if (fprs & FPRS_DL) {
22511670e84SRichard Henderson         for (i = 0; i < 16; ++i) {
22611670e84SRichard Henderson             __get_user(env->fpr[i].ll, &fpu->si_double_regs[i]);
22711670e84SRichard Henderson         }
22811670e84SRichard Henderson     }
22911670e84SRichard Henderson     if (fprs & FPRS_DU) {
23011670e84SRichard Henderson         for (i = 16; i < 32; ++i) {
23111670e84SRichard Henderson             __get_user(env->fpr[i].ll, &fpu->si_double_regs[i]);
23211670e84SRichard Henderson         }
23311670e84SRichard Henderson     }
23411670e84SRichard Henderson     __get_user(env->gsr, &fpu->si_gsr);
23511670e84SRichard Henderson     env->fprs |= fprs;
23611670e84SRichard Henderson #else
23771cda6e9SRichard Henderson     for (i = 0; i < 16; ++i) {
23871cda6e9SRichard Henderson         __get_user(env->fpr[i].ll, &fpu->si_double_regs[i]);
23971cda6e9SRichard Henderson     }
24011670e84SRichard Henderson #endif
2411ccd6e13SRichard Henderson 
2421ccd6e13SRichard Henderson     __get_user(fsr, &fpu->si_fsr);
2431ccd6e13SRichard Henderson     cpu_put_fsr(env, fsr);
24471cda6e9SRichard Henderson }
2459f172adbSLaurent Vivier 
246bb3347f8SRichard Henderson #ifdef TARGET_ARCH_HAS_SETUP_FRAME
install_sigtramp(uint32_t * tramp,int syscall)2473f7685eaSRichard Henderson static void install_sigtramp(uint32_t *tramp, int syscall)
2483f7685eaSRichard Henderson {
2493f7685eaSRichard Henderson     __put_user(0x82102000u + syscall, &tramp[0]); /* mov syscall, %g1 */
2503f7685eaSRichard Henderson     __put_user(0x91d02010u, &tramp[1]);           /* t 0x10 */
2513f7685eaSRichard Henderson }
2523f7685eaSRichard Henderson 
setup_frame(int sig,struct target_sigaction * ka,target_sigset_t * set,CPUSPARCState * env)2539f172adbSLaurent Vivier void setup_frame(int sig, struct target_sigaction *ka,
2549f172adbSLaurent Vivier                  target_sigset_t *set, CPUSPARCState *env)
2559f172adbSLaurent Vivier {
2569f172adbSLaurent Vivier     abi_ulong sf_addr;
2579f172adbSLaurent Vivier     struct target_signal_frame *sf;
25871cda6e9SRichard Henderson     size_t sf_size = sizeof(*sf) + sizeof(struct target_siginfo_fpu);
25971cda6e9SRichard Henderson     int i;
2609f172adbSLaurent Vivier 
26171cda6e9SRichard Henderson     sf_addr = get_sigframe(ka, env, sf_size);
2629f172adbSLaurent Vivier     trace_user_setup_frame(env, sf_addr);
2639f172adbSLaurent Vivier 
26471cda6e9SRichard Henderson     sf = lock_user(VERIFY_WRITE, sf_addr, sf_size, 0);
2659f172adbSLaurent Vivier     if (!sf) {
266757d2601SRichard Henderson         force_sigsegv(sig);
267757d2601SRichard Henderson         return;
2689f172adbSLaurent Vivier     }
26971cda6e9SRichard Henderson 
2709f172adbSLaurent Vivier     /* 2. Save the current process state */
271a1181d53SRichard Henderson     save_pt_regs(&sf->regs, env);
2729f172adbSLaurent Vivier     __put_user(0, &sf->extra_size);
2739f172adbSLaurent Vivier 
27471cda6e9SRichard Henderson     save_fpu((struct target_siginfo_fpu *)(sf + 1), env);
27571cda6e9SRichard Henderson     __put_user(sf_addr + sizeof(*sf), &sf->fpu_save);
2769f172adbSLaurent Vivier 
277819f6df1SRichard Henderson     __put_user(0, &sf->rwin_save);  /* TODO: save_rwin_state */
278819f6df1SRichard Henderson 
279a1181d53SRichard Henderson     __put_user(set->sig[0], &sf->si_mask);
2809f172adbSLaurent Vivier     for (i = 0; i < TARGET_NSIG_WORDS - 1; i++) {
2819f172adbSLaurent Vivier         __put_user(set->sig[i + 1], &sf->extramask[i]);
2829f172adbSLaurent Vivier     }
2839f172adbSLaurent Vivier 
28444a5f861SRichard Henderson     save_reg_win(&sf->ss.win, env);
2859f172adbSLaurent Vivier 
2869f172adbSLaurent Vivier     /* 3. signal handler back-trampoline and parameters */
2878d9c72a2SRichard Henderson     env->regwptr[WREG_SP] = sf_addr;
28880180eb2SRichard Henderson     env->regwptr[WREG_O0] = sig;
28980180eb2SRichard Henderson     env->regwptr[WREG_O1] = sf_addr +
290a1181d53SRichard Henderson             offsetof(struct target_signal_frame, regs);
29180180eb2SRichard Henderson     env->regwptr[WREG_O2] = sf_addr +
292a1181d53SRichard Henderson             offsetof(struct target_signal_frame, regs);
2939f172adbSLaurent Vivier 
2949f172adbSLaurent Vivier     /* 4. signal handler */
2959f172adbSLaurent Vivier     env->pc = ka->_sa_handler;
296757d2601SRichard Henderson     env->npc = env->pc + 4;
297757d2601SRichard Henderson 
2989f172adbSLaurent Vivier     /* 5. return to kernel instructions */
2999f172adbSLaurent Vivier     if (ka->ka_restorer) {
30080180eb2SRichard Henderson         env->regwptr[WREG_O7] = ka->ka_restorer;
3019f172adbSLaurent Vivier     } else {
3023f7685eaSRichard Henderson         /* Not used, but retain for ABI compatibility. */
3033f7685eaSRichard Henderson         install_sigtramp(sf->insns, TARGET_NR_sigreturn);
3043f7685eaSRichard Henderson         env->regwptr[WREG_O7] = default_sigreturn;
3059f172adbSLaurent Vivier     }
30671cda6e9SRichard Henderson     unlock_user(sf, sf_addr, sf_size);
3079f172adbSLaurent Vivier }
308bb3347f8SRichard Henderson #endif /* TARGET_ARCH_HAS_SETUP_FRAME */
3099f172adbSLaurent Vivier 
setup_rt_frame(int sig,struct target_sigaction * ka,target_siginfo_t * info,target_sigset_t * set,CPUSPARCState * env)3109f172adbSLaurent Vivier void setup_rt_frame(int sig, struct target_sigaction *ka,
3119f172adbSLaurent Vivier                     target_siginfo_t *info,
3129f172adbSLaurent Vivier                     target_sigset_t *set, CPUSPARCState *env)
3139f172adbSLaurent Vivier {
314e76f2f84SRichard Henderson     abi_ulong sf_addr;
315e76f2f84SRichard Henderson     struct target_rt_signal_frame *sf;
316e76f2f84SRichard Henderson     size_t sf_size = sizeof(*sf) + sizeof(struct target_siginfo_fpu);
317e76f2f84SRichard Henderson 
318e76f2f84SRichard Henderson     sf_addr = get_sigframe(ka, env, sf_size);
319e76f2f84SRichard Henderson     trace_user_setup_rt_frame(env, sf_addr);
320e76f2f84SRichard Henderson 
321e76f2f84SRichard Henderson     sf = lock_user(VERIFY_WRITE, sf_addr, sf_size, 0);
322e76f2f84SRichard Henderson     if (!sf) {
323e76f2f84SRichard Henderson         force_sigsegv(sig);
324e76f2f84SRichard Henderson         return;
325e76f2f84SRichard Henderson     }
326e76f2f84SRichard Henderson 
327e76f2f84SRichard Henderson     /* 2. Save the current process state */
328e76f2f84SRichard Henderson     save_reg_win(&sf->ss.win, env);
329e76f2f84SRichard Henderson     save_pt_regs(&sf->regs, env);
330e76f2f84SRichard Henderson 
331e76f2f84SRichard Henderson     save_fpu((struct target_siginfo_fpu *)(sf + 1), env);
332e76f2f84SRichard Henderson     __put_user(sf_addr + sizeof(*sf), &sf->fpu_save);
333e76f2f84SRichard Henderson 
334e76f2f84SRichard Henderson     __put_user(0, &sf->rwin_save);  /* TODO: save_rwin_state */
335e76f2f84SRichard Henderson 
336*4d6d8a05SGustavo Romero     sf->info = *info;
337e76f2f84SRichard Henderson     tswap_sigset(&sf->mask, set);
338e76f2f84SRichard Henderson     target_save_altstack(&sf->stack, env);
339e76f2f84SRichard Henderson 
340bb3347f8SRichard Henderson #ifdef TARGET_ABI32
341e76f2f84SRichard Henderson     __put_user(0, &sf->extra_size);
342bb3347f8SRichard Henderson #endif
343e76f2f84SRichard Henderson 
344e76f2f84SRichard Henderson     /* 3. signal handler back-trampoline and parameters */
345bb3347f8SRichard Henderson     env->regwptr[WREG_SP] = sf_addr - TARGET_STACK_BIAS;
346e76f2f84SRichard Henderson     env->regwptr[WREG_O0] = sig;
347e76f2f84SRichard Henderson     env->regwptr[WREG_O1] =
348e76f2f84SRichard Henderson         sf_addr + offsetof(struct target_rt_signal_frame, info);
349bb3347f8SRichard Henderson #ifdef TARGET_ABI32
350e76f2f84SRichard Henderson     env->regwptr[WREG_O2] =
351e76f2f84SRichard Henderson         sf_addr + offsetof(struct target_rt_signal_frame, regs);
352bb3347f8SRichard Henderson #else
353bb3347f8SRichard Henderson     env->regwptr[WREG_O2] = env->regwptr[WREG_O1];
354bb3347f8SRichard Henderson #endif
355e76f2f84SRichard Henderson 
356e76f2f84SRichard Henderson     /* 4. signal handler */
357e76f2f84SRichard Henderson     env->pc = ka->_sa_handler;
358e76f2f84SRichard Henderson     env->npc = env->pc + 4;
359e76f2f84SRichard Henderson 
360e76f2f84SRichard Henderson     /* 5. return to kernel instructions */
361bb3347f8SRichard Henderson #ifdef TARGET_ABI32
362e76f2f84SRichard Henderson     if (ka->ka_restorer) {
363e76f2f84SRichard Henderson         env->regwptr[WREG_O7] = ka->ka_restorer;
364e76f2f84SRichard Henderson     } else {
3653f7685eaSRichard Henderson         /* Not used, but retain for ABI compatibility. */
3663f7685eaSRichard Henderson         install_sigtramp(sf->insns, TARGET_NR_rt_sigreturn);
3673f7685eaSRichard Henderson         env->regwptr[WREG_O7] = default_rt_sigreturn;
368e76f2f84SRichard Henderson     }
369bb3347f8SRichard Henderson #else
370bb3347f8SRichard Henderson     env->regwptr[WREG_O7] = ka->ka_restorer;
371bb3347f8SRichard Henderson #endif
372bb3347f8SRichard Henderson 
373e76f2f84SRichard Henderson     unlock_user(sf, sf_addr, sf_size);
3749f172adbSLaurent Vivier }
3759f172adbSLaurent Vivier 
do_sigreturn(CPUSPARCState * env)3769f172adbSLaurent Vivier long do_sigreturn(CPUSPARCState *env)
3779f172adbSLaurent Vivier {
378bb3347f8SRichard Henderson #ifdef TARGET_ARCH_HAS_SETUP_FRAME
3799f172adbSLaurent Vivier     abi_ulong sf_addr;
3801176e57aSRichard Henderson     struct target_signal_frame *sf = NULL;
38171cda6e9SRichard Henderson     abi_ulong pc, npc, ptr;
3829f172adbSLaurent Vivier     target_sigset_t set;
3839f172adbSLaurent Vivier     sigset_t host_set;
384bba390cbSPeter Maydell     int i;
3859f172adbSLaurent Vivier 
3868d9c72a2SRichard Henderson     sf_addr = env->regwptr[WREG_SP];
3879f172adbSLaurent Vivier     trace_user_do_sigreturn(env, sf_addr);
3881176e57aSRichard Henderson 
3891176e57aSRichard Henderson     /* 1. Make sure we are not getting garbage from the user */
3901176e57aSRichard Henderson     if ((sf_addr & 15) || !lock_user_struct(VERIFY_READ, sf, sf_addr, 1)) {
3919f172adbSLaurent Vivier         goto segv_and_exit;
3929f172adbSLaurent Vivier     }
3939f172adbSLaurent Vivier 
3941176e57aSRichard Henderson     /* Make sure stack pointer is aligned.  */
3951176e57aSRichard Henderson     __get_user(ptr, &sf->regs.u_regs[14]);
3961176e57aSRichard Henderson     if (ptr & 7) {
3979f172adbSLaurent Vivier         goto segv_and_exit;
3981176e57aSRichard Henderson     }
3999f172adbSLaurent Vivier 
4001176e57aSRichard Henderson     /* Make sure instruction pointers are aligned.  */
401a1181d53SRichard Henderson     __get_user(pc, &sf->regs.pc);
402a1181d53SRichard Henderson     __get_user(npc, &sf->regs.npc);
4039f172adbSLaurent Vivier     if ((pc | npc) & 3) {
4049f172adbSLaurent Vivier         goto segv_and_exit;
4059f172adbSLaurent Vivier     }
4069f172adbSLaurent Vivier 
4079f172adbSLaurent Vivier     /* 2. Restore the state */
408a1181d53SRichard Henderson     restore_pt_regs(&sf->regs, env);
4099f172adbSLaurent Vivier     env->pc = pc;
4109f172adbSLaurent Vivier     env->npc = npc;
4119f172adbSLaurent Vivier 
41271cda6e9SRichard Henderson     __get_user(ptr, &sf->fpu_save);
41371cda6e9SRichard Henderson     if (ptr) {
41471cda6e9SRichard Henderson         struct target_siginfo_fpu *fpu;
41571cda6e9SRichard Henderson         if ((ptr & 3) || !lock_user_struct(VERIFY_READ, fpu, ptr, 1)) {
41671cda6e9SRichard Henderson             goto segv_and_exit;
41771cda6e9SRichard Henderson         }
41871cda6e9SRichard Henderson         restore_fpu(fpu, env);
41971cda6e9SRichard Henderson         unlock_user_struct(fpu, ptr, 0);
42071cda6e9SRichard Henderson     }
4219f172adbSLaurent Vivier 
422819f6df1SRichard Henderson     __get_user(ptr, &sf->rwin_save);
423819f6df1SRichard Henderson     if (ptr) {
424819f6df1SRichard Henderson         goto segv_and_exit;  /* TODO: restore_rwin */
425819f6df1SRichard Henderson     }
426819f6df1SRichard Henderson 
427a1181d53SRichard Henderson     __get_user(set.sig[0], &sf->si_mask);
4289f172adbSLaurent Vivier     for (i = 1; i < TARGET_NSIG_WORDS; i++) {
4299f172adbSLaurent Vivier         __get_user(set.sig[i], &sf->extramask[i - 1]);
4309f172adbSLaurent Vivier     }
4319f172adbSLaurent Vivier 
4329f172adbSLaurent Vivier     target_to_host_sigset_internal(&host_set, &set);
4339f172adbSLaurent Vivier     set_sigmask(&host_set);
4349f172adbSLaurent Vivier 
4359f172adbSLaurent Vivier     unlock_user_struct(sf, sf_addr, 0);
43657a0c938SRichard Henderson     return -QEMU_ESIGRETURN;
4379f172adbSLaurent Vivier 
4389f172adbSLaurent Vivier  segv_and_exit:
4399f172adbSLaurent Vivier     unlock_user_struct(sf, sf_addr, 0);
4409f172adbSLaurent Vivier     force_sig(TARGET_SIGSEGV);
44157a0c938SRichard Henderson     return -QEMU_ESIGRETURN;
442bb3347f8SRichard Henderson #else
443bb3347f8SRichard Henderson     return -TARGET_ENOSYS;
444bb3347f8SRichard Henderson #endif
4459f172adbSLaurent Vivier }
4469f172adbSLaurent Vivier 
do_rt_sigreturn(CPUSPARCState * env)4479f172adbSLaurent Vivier long do_rt_sigreturn(CPUSPARCState *env)
4489f172adbSLaurent Vivier {
449e76f2f84SRichard Henderson     abi_ulong sf_addr, tpc, tnpc, ptr;
450e76f2f84SRichard Henderson     struct target_rt_signal_frame *sf = NULL;
451e76f2f84SRichard Henderson     sigset_t set;
452e76f2f84SRichard Henderson 
453e76f2f84SRichard Henderson     sf_addr = get_sp_from_cpustate(env);
454e76f2f84SRichard Henderson     trace_user_do_rt_sigreturn(env, sf_addr);
455e76f2f84SRichard Henderson 
456e76f2f84SRichard Henderson     /* 1. Make sure we are not getting garbage from the user */
457e76f2f84SRichard Henderson     if ((sf_addr & 15) || !lock_user_struct(VERIFY_READ, sf, sf_addr, 1)) {
458e76f2f84SRichard Henderson         goto segv_and_exit;
459e76f2f84SRichard Henderson     }
460e76f2f84SRichard Henderson 
461e76f2f84SRichard Henderson     /* Validate SP alignment.  */
462e76f2f84SRichard Henderson     __get_user(ptr, &sf->regs.u_regs[8 + WREG_SP]);
463e76f2f84SRichard Henderson     if ((ptr + TARGET_STACK_BIAS) & 7) {
464e76f2f84SRichard Henderson         goto segv_and_exit;
465e76f2f84SRichard Henderson     }
466e76f2f84SRichard Henderson 
467e76f2f84SRichard Henderson     /* Validate PC and NPC alignment.  */
468e76f2f84SRichard Henderson     __get_user(tpc, &sf->regs.pc);
469e76f2f84SRichard Henderson     __get_user(tnpc, &sf->regs.npc);
470e76f2f84SRichard Henderson     if ((tpc | tnpc) & 3) {
471e76f2f84SRichard Henderson         goto segv_and_exit;
472e76f2f84SRichard Henderson     }
473e76f2f84SRichard Henderson 
474e76f2f84SRichard Henderson     /* 2. Restore the state */
475e76f2f84SRichard Henderson     restore_pt_regs(&sf->regs, env);
476e76f2f84SRichard Henderson 
477e76f2f84SRichard Henderson     __get_user(ptr, &sf->fpu_save);
478e76f2f84SRichard Henderson     if (ptr) {
479e76f2f84SRichard Henderson         struct target_siginfo_fpu *fpu;
480e76f2f84SRichard Henderson         if ((ptr & 7) || !lock_user_struct(VERIFY_READ, fpu, ptr, 1)) {
481e76f2f84SRichard Henderson             goto segv_and_exit;
482e76f2f84SRichard Henderson         }
483e76f2f84SRichard Henderson         restore_fpu(fpu, env);
484e76f2f84SRichard Henderson         unlock_user_struct(fpu, ptr, 0);
485e76f2f84SRichard Henderson     }
486e76f2f84SRichard Henderson 
487e76f2f84SRichard Henderson     __get_user(ptr, &sf->rwin_save);
488e76f2f84SRichard Henderson     if (ptr) {
489e76f2f84SRichard Henderson         goto segv_and_exit;  /* TODO: restore_rwin_state */
490e76f2f84SRichard Henderson     }
491e76f2f84SRichard Henderson 
492e76f2f84SRichard Henderson     target_restore_altstack(&sf->stack, env);
493e76f2f84SRichard Henderson     target_to_host_sigset(&set, &sf->mask);
494e76f2f84SRichard Henderson     set_sigmask(&set);
495e76f2f84SRichard Henderson 
496e76f2f84SRichard Henderson     env->pc = tpc;
497e76f2f84SRichard Henderson     env->npc = tnpc;
498e76f2f84SRichard Henderson 
499e76f2f84SRichard Henderson     unlock_user_struct(sf, sf_addr, 0);
50057a0c938SRichard Henderson     return -QEMU_ESIGRETURN;
501e76f2f84SRichard Henderson 
502e76f2f84SRichard Henderson  segv_and_exit:
503e76f2f84SRichard Henderson     unlock_user_struct(sf, sf_addr, 0);
504e76f2f84SRichard Henderson     force_sig(TARGET_SIGSEGV);
50557a0c938SRichard Henderson     return -QEMU_ESIGRETURN;
5069f172adbSLaurent Vivier }
5079f172adbSLaurent Vivier 
508d6b03637SRichard Henderson #ifdef TARGET_ABI32
setup_sigtramp(abi_ulong sigtramp_page)509d6b03637SRichard Henderson void setup_sigtramp(abi_ulong sigtramp_page)
510d6b03637SRichard Henderson {
511d6b03637SRichard Henderson     uint32_t *tramp = lock_user(VERIFY_WRITE, sigtramp_page, 2 * 8, 0);
512d6b03637SRichard Henderson     assert(tramp != NULL);
513d6b03637SRichard Henderson 
514d6b03637SRichard Henderson     default_sigreturn = sigtramp_page;
515d6b03637SRichard Henderson     install_sigtramp(tramp, TARGET_NR_sigreturn);
516d6b03637SRichard Henderson 
517d6b03637SRichard Henderson     default_rt_sigreturn = sigtramp_page + 8;
518d6b03637SRichard Henderson     install_sigtramp(tramp + 2, TARGET_NR_rt_sigreturn);
519d6b03637SRichard Henderson 
520d6b03637SRichard Henderson     unlock_user(tramp, sigtramp_page, 2 * 8);
521d6b03637SRichard Henderson }
522d6b03637SRichard Henderson #endif
523d6b03637SRichard Henderson 
524d6b03637SRichard Henderson #ifdef TARGET_SPARC64
5259f172adbSLaurent Vivier #define SPARC_MC_TSTATE 0
5269f172adbSLaurent Vivier #define SPARC_MC_PC 1
5279f172adbSLaurent Vivier #define SPARC_MC_NPC 2
5289f172adbSLaurent Vivier #define SPARC_MC_Y 3
5299f172adbSLaurent Vivier #define SPARC_MC_G1 4
5309f172adbSLaurent Vivier #define SPARC_MC_G2 5
5319f172adbSLaurent Vivier #define SPARC_MC_G3 6
5329f172adbSLaurent Vivier #define SPARC_MC_G4 7
5339f172adbSLaurent Vivier #define SPARC_MC_G5 8
5349f172adbSLaurent Vivier #define SPARC_MC_G6 9
5359f172adbSLaurent Vivier #define SPARC_MC_G7 10
5369f172adbSLaurent Vivier #define SPARC_MC_O0 11
5379f172adbSLaurent Vivier #define SPARC_MC_O1 12
5389f172adbSLaurent Vivier #define SPARC_MC_O2 13
5399f172adbSLaurent Vivier #define SPARC_MC_O3 14
5409f172adbSLaurent Vivier #define SPARC_MC_O4 15
5419f172adbSLaurent Vivier #define SPARC_MC_O5 16
5429f172adbSLaurent Vivier #define SPARC_MC_O6 17
5439f172adbSLaurent Vivier #define SPARC_MC_O7 18
5449f172adbSLaurent Vivier #define SPARC_MC_NGREG 19
5459f172adbSLaurent Vivier 
5469f172adbSLaurent Vivier typedef abi_ulong target_mc_greg_t;
5479f172adbSLaurent Vivier typedef target_mc_greg_t target_mc_gregset_t[SPARC_MC_NGREG];
5489f172adbSLaurent Vivier 
549b8ae597fSPeter Maydell /*
550b8ae597fSPeter Maydell  * Note the manual 16-alignment; the kernel gets this because it
551b8ae597fSPeter Maydell  * includes a "long double qregs[16]" in the mcpu_fregs union,
552b8ae597fSPeter Maydell  * which we can't do.
553b8ae597fSPeter Maydell  */
5549f172adbSLaurent Vivier struct target_mc_fpu {
5559f172adbSLaurent Vivier     union {
5569f172adbSLaurent Vivier         uint32_t sregs[32];
5579f172adbSLaurent Vivier         uint64_t dregs[32];
5589f172adbSLaurent Vivier         //uint128_t qregs[16];
5599f172adbSLaurent Vivier     } mcfpu_fregs;
5609f172adbSLaurent Vivier     abi_ulong mcfpu_fsr;
5619f172adbSLaurent Vivier     abi_ulong mcfpu_fprs;
5629f172adbSLaurent Vivier     abi_ulong mcfpu_gsr;
563b8ae597fSPeter Maydell     abi_ulong mcfpu_fq;
5649f172adbSLaurent Vivier     unsigned char mcfpu_qcnt;
5659f172adbSLaurent Vivier     unsigned char mcfpu_qentsz;
5669f172adbSLaurent Vivier     unsigned char mcfpu_enab;
567b8ae597fSPeter Maydell } __attribute__((aligned(16)));
5689f172adbSLaurent Vivier typedef struct target_mc_fpu target_mc_fpu_t;
5699f172adbSLaurent Vivier 
5709f172adbSLaurent Vivier typedef struct {
5719f172adbSLaurent Vivier     target_mc_gregset_t mc_gregs;
5729f172adbSLaurent Vivier     target_mc_greg_t mc_fp;
5739f172adbSLaurent Vivier     target_mc_greg_t mc_i7;
5749f172adbSLaurent Vivier     target_mc_fpu_t mc_fpregs;
5759f172adbSLaurent Vivier } target_mcontext_t;
5769f172adbSLaurent Vivier 
5779f172adbSLaurent Vivier struct target_ucontext {
578b8ae597fSPeter Maydell     abi_ulong tuc_link;
5799f172adbSLaurent Vivier     abi_ulong tuc_flags;
5809f172adbSLaurent Vivier     target_sigset_t tuc_sigmask;
5819f172adbSLaurent Vivier     target_mcontext_t tuc_mcontext;
5829f172adbSLaurent Vivier };
5839f172adbSLaurent Vivier 
5849f172adbSLaurent Vivier /* {set, get}context() needed for 64-bit SparcLinux userland. */
sparc64_set_context(CPUSPARCState * env)5859f172adbSLaurent Vivier void sparc64_set_context(CPUSPARCState *env)
5869f172adbSLaurent Vivier {
5879f172adbSLaurent Vivier     abi_ulong ucp_addr;
5889f172adbSLaurent Vivier     struct target_ucontext *ucp;
5899f172adbSLaurent Vivier     target_mc_gregset_t *grp;
590246ff442SPeter Maydell     target_mc_fpu_t *fpup;
591d6b03637SRichard Henderson     target_ulong pc, npc, tstate;
5929f172adbSLaurent Vivier     unsigned int i;
593246ff442SPeter Maydell     unsigned char fenab;
5949f172adbSLaurent Vivier 
59580180eb2SRichard Henderson     ucp_addr = env->regwptr[WREG_O0];
5969f172adbSLaurent Vivier     if (!lock_user_struct(VERIFY_READ, ucp, ucp_addr, 1)) {
5979f172adbSLaurent Vivier         goto do_sigsegv;
5989f172adbSLaurent Vivier     }
5999f172adbSLaurent Vivier     grp  = &ucp->tuc_mcontext.mc_gregs;
6009f172adbSLaurent Vivier     __get_user(pc, &((*grp)[SPARC_MC_PC]));
6019f172adbSLaurent Vivier     __get_user(npc, &((*grp)[SPARC_MC_NPC]));
6029f172adbSLaurent Vivier     if ((pc | npc) & 3) {
6039f172adbSLaurent Vivier         goto do_sigsegv;
6049f172adbSLaurent Vivier     }
60580180eb2SRichard Henderson     if (env->regwptr[WREG_O1]) {
6069f172adbSLaurent Vivier         target_sigset_t target_set;
6079f172adbSLaurent Vivier         sigset_t set;
6089f172adbSLaurent Vivier 
6099f172adbSLaurent Vivier         if (TARGET_NSIG_WORDS == 1) {
6109f172adbSLaurent Vivier             __get_user(target_set.sig[0], &ucp->tuc_sigmask.sig[0]);
6119f172adbSLaurent Vivier         } else {
6129f172adbSLaurent Vivier             abi_ulong *src, *dst;
6139f172adbSLaurent Vivier             src = ucp->tuc_sigmask.sig;
6149f172adbSLaurent Vivier             dst = target_set.sig;
6159f172adbSLaurent Vivier             for (i = 0; i < TARGET_NSIG_WORDS; i++, dst++, src++) {
6169f172adbSLaurent Vivier                 __get_user(*dst, src);
6179f172adbSLaurent Vivier             }
6189f172adbSLaurent Vivier         }
6199f172adbSLaurent Vivier         target_to_host_sigset_internal(&set, &target_set);
6209f172adbSLaurent Vivier         set_sigmask(&set);
6219f172adbSLaurent Vivier     }
6229f172adbSLaurent Vivier     env->pc = pc;
6239f172adbSLaurent Vivier     env->npc = npc;
6249f172adbSLaurent Vivier     __get_user(env->y, &((*grp)[SPARC_MC_Y]));
6259f172adbSLaurent Vivier     __get_user(tstate, &((*grp)[SPARC_MC_TSTATE]));
6267a5805a0SPeter Maydell     /* Honour TSTATE_ASI, TSTATE_ICC and TSTATE_XCC only */
6279f172adbSLaurent Vivier     env->asi = (tstate >> 24) & 0xff;
6287a5805a0SPeter Maydell     cpu_put_ccr(env, (tstate >> 32) & 0xff);
6299f172adbSLaurent Vivier     __get_user(env->gregs[1], (&(*grp)[SPARC_MC_G1]));
6309f172adbSLaurent Vivier     __get_user(env->gregs[2], (&(*grp)[SPARC_MC_G2]));
6319f172adbSLaurent Vivier     __get_user(env->gregs[3], (&(*grp)[SPARC_MC_G3]));
6329f172adbSLaurent Vivier     __get_user(env->gregs[4], (&(*grp)[SPARC_MC_G4]));
6339f172adbSLaurent Vivier     __get_user(env->gregs[5], (&(*grp)[SPARC_MC_G5]));
6349f172adbSLaurent Vivier     __get_user(env->gregs[6], (&(*grp)[SPARC_MC_G6]));
6350ad20314SPeter Maydell     /* Skip g7 as that's the thread register in userspace */
636266b4158SPeter Maydell 
637266b4158SPeter Maydell     /*
638266b4158SPeter Maydell      * Note that unlike the kernel, we didn't need to mess with the
639266b4158SPeter Maydell      * guest register window state to save it into a pt_regs to run
640266b4158SPeter Maydell      * the kernel. So for us the guest's O regs are still in WREG_O*
641266b4158SPeter Maydell      * (unlike the kernel which has put them in UREG_I* in a pt_regs)
642266b4158SPeter Maydell      * and the fp and i7 are still in WREG_I6 and WREG_I7 and don't
643266b4158SPeter Maydell      * need to be written back to userspace memory.
644266b4158SPeter Maydell      */
64580180eb2SRichard Henderson     __get_user(env->regwptr[WREG_O0], (&(*grp)[SPARC_MC_O0]));
64680180eb2SRichard Henderson     __get_user(env->regwptr[WREG_O1], (&(*grp)[SPARC_MC_O1]));
64780180eb2SRichard Henderson     __get_user(env->regwptr[WREG_O2], (&(*grp)[SPARC_MC_O2]));
64880180eb2SRichard Henderson     __get_user(env->regwptr[WREG_O3], (&(*grp)[SPARC_MC_O3]));
64980180eb2SRichard Henderson     __get_user(env->regwptr[WREG_O4], (&(*grp)[SPARC_MC_O4]));
65080180eb2SRichard Henderson     __get_user(env->regwptr[WREG_O5], (&(*grp)[SPARC_MC_O5]));
65180180eb2SRichard Henderson     __get_user(env->regwptr[WREG_O6], (&(*grp)[SPARC_MC_O6]));
65280180eb2SRichard Henderson     __get_user(env->regwptr[WREG_O7], (&(*grp)[SPARC_MC_O7]));
6539f172adbSLaurent Vivier 
654266b4158SPeter Maydell     __get_user(env->regwptr[WREG_FP], &(ucp->tuc_mcontext.mc_fp));
655266b4158SPeter Maydell     __get_user(env->regwptr[WREG_I7], &(ucp->tuc_mcontext.mc_i7));
6569f172adbSLaurent Vivier 
657246ff442SPeter Maydell     fpup = &ucp->tuc_mcontext.mc_fpregs;
658246ff442SPeter Maydell 
659246ff442SPeter Maydell     __get_user(fenab, &(fpup->mcfpu_enab));
660246ff442SPeter Maydell     if (fenab) {
661246ff442SPeter Maydell         abi_ulong fprs;
6621ccd6e13SRichard Henderson         abi_ulong fsr;
663246ff442SPeter Maydell 
664246ff442SPeter Maydell         /*
665246ff442SPeter Maydell          * We use the FPRS from the guest only in deciding whether
666246ff442SPeter Maydell          * to restore the upper, lower, or both banks of the FPU regs.
667246ff442SPeter Maydell          * The kernel here writes the FPU register data into the
668246ff442SPeter Maydell          * process's current_thread_info state and unconditionally
669246ff442SPeter Maydell          * clears FPRS and TSTATE_PEF: this disables the FPU so that the
670246ff442SPeter Maydell          * next FPU-disabled trap will copy the data out of
671246ff442SPeter Maydell          * current_thread_info and into the real FPU registers.
672246ff442SPeter Maydell          * QEMU doesn't need to handle lazy-FPU-state-restoring like that,
673246ff442SPeter Maydell          * so we always load the data directly into the FPU registers
674246ff442SPeter Maydell          * and leave FPRS and TSTATE_PEF alone (so the FPU stays enabled).
675246ff442SPeter Maydell          * Note that because we (and the kernel) always write zeroes for
676246ff442SPeter Maydell          * the fenab and fprs in sparc64_get_context() none of this code
677246ff442SPeter Maydell          * will execute unless the guest manually constructed or changed
678246ff442SPeter Maydell          * the context structure.
6799f172adbSLaurent Vivier          */
680246ff442SPeter Maydell         __get_user(fprs, &(fpup->mcfpu_fprs));
681246ff442SPeter Maydell         if (fprs & FPRS_DL) {
682246ff442SPeter Maydell             for (i = 0; i < 16; i++) {
683246ff442SPeter Maydell                 __get_user(env->fpr[i].ll, &(fpup->mcfpu_fregs.dregs[i]));
6849f172adbSLaurent Vivier             }
6859f172adbSLaurent Vivier         }
686246ff442SPeter Maydell         if (fprs & FPRS_DU) {
687246ff442SPeter Maydell             for (i = 16; i < 32; i++) {
688246ff442SPeter Maydell                 __get_user(env->fpr[i].ll, &(fpup->mcfpu_fregs.dregs[i]));
6899f172adbSLaurent Vivier             }
690246ff442SPeter Maydell         }
6911ccd6e13SRichard Henderson         __get_user(fsr, &(fpup->mcfpu_fsr));
6921ccd6e13SRichard Henderson         cpu_put_fsr(env, fsr);
693246ff442SPeter Maydell         __get_user(env->gsr, &(fpup->mcfpu_gsr));
694246ff442SPeter Maydell     }
6959f172adbSLaurent Vivier     unlock_user_struct(ucp, ucp_addr, 0);
6969f172adbSLaurent Vivier     return;
6979f172adbSLaurent Vivier do_sigsegv:
6989f172adbSLaurent Vivier     unlock_user_struct(ucp, ucp_addr, 0);
6999f172adbSLaurent Vivier     force_sig(TARGET_SIGSEGV);
7009f172adbSLaurent Vivier }
7019f172adbSLaurent Vivier 
sparc64_get_context(CPUSPARCState * env)7029f172adbSLaurent Vivier void sparc64_get_context(CPUSPARCState *env)
7039f172adbSLaurent Vivier {
7049f172adbSLaurent Vivier     abi_ulong ucp_addr;
7059f172adbSLaurent Vivier     struct target_ucontext *ucp;
7069f172adbSLaurent Vivier     target_mc_gregset_t *grp;
7079f172adbSLaurent Vivier     target_mcontext_t *mcp;
7089f172adbSLaurent Vivier     int err;
7099f172adbSLaurent Vivier     unsigned int i;
7109f172adbSLaurent Vivier     target_sigset_t target_set;
7119f172adbSLaurent Vivier     sigset_t set;
7129f172adbSLaurent Vivier 
71380180eb2SRichard Henderson     ucp_addr = env->regwptr[WREG_O0];
7149f172adbSLaurent Vivier     if (!lock_user_struct(VERIFY_WRITE, ucp, ucp_addr, 0)) {
7159f172adbSLaurent Vivier         goto do_sigsegv;
7169f172adbSLaurent Vivier     }
7179f172adbSLaurent Vivier 
718246ff442SPeter Maydell     memset(ucp, 0, sizeof(*ucp));
719246ff442SPeter Maydell 
7209f172adbSLaurent Vivier     mcp = &ucp->tuc_mcontext;
7219f172adbSLaurent Vivier     grp = &mcp->mc_gregs;
7229f172adbSLaurent Vivier 
7239f172adbSLaurent Vivier     /* Skip over the trap instruction, first. */
7249f172adbSLaurent Vivier     env->pc = env->npc;
7259f172adbSLaurent Vivier     env->npc += 4;
7269f172adbSLaurent Vivier 
7279f172adbSLaurent Vivier     /* If we're only reading the signal mask then do_sigprocmask()
7289f172adbSLaurent Vivier      * is guaranteed not to fail, which is important because we don't
7299f172adbSLaurent Vivier      * have any way to signal a failure or restart this operation since
7309f172adbSLaurent Vivier      * this is not a normal syscall.
7319f172adbSLaurent Vivier      */
7329f172adbSLaurent Vivier     err = do_sigprocmask(0, NULL, &set);
7339f172adbSLaurent Vivier     assert(err == 0);
7349f172adbSLaurent Vivier     host_to_target_sigset_internal(&target_set, &set);
7359f172adbSLaurent Vivier     if (TARGET_NSIG_WORDS == 1) {
7369f172adbSLaurent Vivier         __put_user(target_set.sig[0],
7379f172adbSLaurent Vivier                    (abi_ulong *)&ucp->tuc_sigmask);
7389f172adbSLaurent Vivier     } else {
7399f172adbSLaurent Vivier         abi_ulong *src, *dst;
7409f172adbSLaurent Vivier         src = target_set.sig;
7419f172adbSLaurent Vivier         dst = ucp->tuc_sigmask.sig;
7429f172adbSLaurent Vivier         for (i = 0; i < TARGET_NSIG_WORDS; i++, dst++, src++) {
7439f172adbSLaurent Vivier             __put_user(*src, dst);
7449f172adbSLaurent Vivier         }
7459f172adbSLaurent Vivier     }
7469f172adbSLaurent Vivier 
7477a5805a0SPeter Maydell     __put_user(sparc64_tstate(env), &((*grp)[SPARC_MC_TSTATE]));
7489f172adbSLaurent Vivier     __put_user(env->pc, &((*grp)[SPARC_MC_PC]));
7499f172adbSLaurent Vivier     __put_user(env->npc, &((*grp)[SPARC_MC_NPC]));
7509f172adbSLaurent Vivier     __put_user(env->y, &((*grp)[SPARC_MC_Y]));
7519f172adbSLaurent Vivier     __put_user(env->gregs[1], &((*grp)[SPARC_MC_G1]));
7529f172adbSLaurent Vivier     __put_user(env->gregs[2], &((*grp)[SPARC_MC_G2]));
7539f172adbSLaurent Vivier     __put_user(env->gregs[3], &((*grp)[SPARC_MC_G3]));
7549f172adbSLaurent Vivier     __put_user(env->gregs[4], &((*grp)[SPARC_MC_G4]));
7559f172adbSLaurent Vivier     __put_user(env->gregs[5], &((*grp)[SPARC_MC_G5]));
7569f172adbSLaurent Vivier     __put_user(env->gregs[6], &((*grp)[SPARC_MC_G6]));
7579f172adbSLaurent Vivier     __put_user(env->gregs[7], &((*grp)[SPARC_MC_G7]));
758266b4158SPeter Maydell 
759266b4158SPeter Maydell     /*
760266b4158SPeter Maydell      * Note that unlike the kernel, we didn't need to mess with the
761266b4158SPeter Maydell      * guest register window state to save it into a pt_regs to run
762266b4158SPeter Maydell      * the kernel. So for us the guest's O regs are still in WREG_O*
763266b4158SPeter Maydell      * (unlike the kernel which has put them in UREG_I* in a pt_regs)
764266b4158SPeter Maydell      * and the fp and i7 are still in WREG_I6 and WREG_I7 and don't
765266b4158SPeter Maydell      * need to be fished out of userspace memory.
766266b4158SPeter Maydell      */
76780180eb2SRichard Henderson     __put_user(env->regwptr[WREG_O0], &((*grp)[SPARC_MC_O0]));
76880180eb2SRichard Henderson     __put_user(env->regwptr[WREG_O1], &((*grp)[SPARC_MC_O1]));
76980180eb2SRichard Henderson     __put_user(env->regwptr[WREG_O2], &((*grp)[SPARC_MC_O2]));
77080180eb2SRichard Henderson     __put_user(env->regwptr[WREG_O3], &((*grp)[SPARC_MC_O3]));
77180180eb2SRichard Henderson     __put_user(env->regwptr[WREG_O4], &((*grp)[SPARC_MC_O4]));
77280180eb2SRichard Henderson     __put_user(env->regwptr[WREG_O5], &((*grp)[SPARC_MC_O5]));
77380180eb2SRichard Henderson     __put_user(env->regwptr[WREG_O6], &((*grp)[SPARC_MC_O6]));
77480180eb2SRichard Henderson     __put_user(env->regwptr[WREG_O7], &((*grp)[SPARC_MC_O7]));
7759f172adbSLaurent Vivier 
776266b4158SPeter Maydell     __put_user(env->regwptr[WREG_FP], &(mcp->mc_fp));
777266b4158SPeter Maydell     __put_user(env->regwptr[WREG_I7], &(mcp->mc_i7));
7789f172adbSLaurent Vivier 
779246ff442SPeter Maydell     /*
780246ff442SPeter Maydell      * We don't write out the FPU state. This matches the kernel's
781246ff442SPeter Maydell      * implementation (which has the code for doing this but
782246ff442SPeter Maydell      * hidden behind an "if (fenab)" where fenab is always 0).
783246ff442SPeter Maydell      */
7849f172adbSLaurent Vivier 
7859f172adbSLaurent Vivier     unlock_user_struct(ucp, ucp_addr, 1);
7869f172adbSLaurent Vivier     return;
7879f172adbSLaurent Vivier do_sigsegv:
7889f172adbSLaurent Vivier     unlock_user_struct(ucp, ucp_addr, 1);
7899f172adbSLaurent Vivier     force_sig(TARGET_SIGSEGV);
7909f172adbSLaurent Vivier }
791d6b03637SRichard Henderson #endif /* TARGET_SPARC64 */
792