blob: 1eb7b2dfc3fd41a9b96be367dd31c28027e9901b [file] [log] [blame]
Peter Maydellda30d852011-12-05 19:42:18 +00001/*
2 * Emulation of Linux signals : SPARC64 specific code
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
20#if !defined(TARGET_ABI32)
21#define MC_TSTATE 0
22#define MC_PC 1
23#define MC_NPC 2
24#define MC_Y 3
25#define MC_G1 4
26#define MC_G2 5
27#define MC_G3 6
28#define MC_G4 7
29#define MC_G5 8
30#define MC_G6 9
31#define MC_G7 10
32#define MC_O0 11
33#define MC_O1 12
34#define MC_O2 13
35#define MC_O3 14
36#define MC_O4 15
37#define MC_O5 16
38#define MC_O6 17
39#define MC_O7 18
40#define MC_NGREG 19
41
42typedef abi_ulong target_mc_greg_t;
43typedef target_mc_greg_t target_mc_gregset_t[MC_NGREG];
44
45struct target_mc_fq {
46 abi_ulong *mcfq_addr;
47 uint32_t mcfq_insn;
48};
49
50struct target_mc_fpu {
51 union {
52 uint32_t sregs[32];
53 uint64_t dregs[32];
54 //uint128_t qregs[16];
55 } mcfpu_fregs;
56 abi_ulong mcfpu_fsr;
57 abi_ulong mcfpu_fprs;
58 abi_ulong mcfpu_gsr;
59 struct target_mc_fq *mcfpu_fq;
60 unsigned char mcfpu_qcnt;
61 unsigned char mcfpu_qentsz;
62 unsigned char mcfpu_enab;
63};
64typedef struct target_mc_fpu target_mc_fpu_t;
65
66typedef struct {
67 target_mc_gregset_t mc_gregs;
68 target_mc_greg_t mc_fp;
69 target_mc_greg_t mc_i7;
70 target_mc_fpu_t mc_fpregs;
71} target_mcontext_t;
72
73struct target_ucontext {
74 struct target_ucontext *tuc_link;
75 abi_ulong tuc_flags;
76 target_sigset_t tuc_sigmask;
77 target_mcontext_t tuc_mcontext;
78};
79
80/* A V9 register window */
81struct target_reg_window {
82 abi_ulong locals[8];
83 abi_ulong ins[8];
84};
85
86#define TARGET_STACK_BIAS 2047
87
88/* {set, get}context() needed for 64-bit SparcLinux userland. */
89void sparc64_set_context(CPUSPARCState *env)
90{
91 abi_ulong ucp_addr;
92 struct target_ucontext *ucp;
93 target_mc_gregset_t *grp;
94 abi_ulong pc, npc, tstate;
95 abi_ulong fp, i7, w_addr;
96 int err;
97 unsigned int i;
98
99 ucp_addr = env->regwptr[UREG_I0];
100 if (!lock_user_struct(VERIFY_READ, ucp, ucp_addr, 1))
101 goto do_sigsegv;
102 grp = &ucp->tuc_mcontext.mc_gregs;
103 err = __get_user(pc, &((*grp)[MC_PC]));
104 err |= __get_user(npc, &((*grp)[MC_NPC]));
105 if (err || ((pc | npc) & 3))
106 goto do_sigsegv;
107 if (env->regwptr[UREG_I1]) {
108 target_sigset_t target_set;
109 sigset_t set;
110
111 if (TARGET_NSIG_WORDS == 1) {
112 if (__get_user(target_set.sig[0], &ucp->tuc_sigmask.sig[0]))
113 goto do_sigsegv;
114 } else {
115 abi_ulong *src, *dst;
116 src = ucp->tuc_sigmask.sig;
117 dst = target_set.sig;
118 for (i = 0; i < sizeof(target_sigset_t) / sizeof(abi_ulong);
119 i++, dst++, src++)
120 err |= __get_user(*dst, src);
121 if (err)
122 goto do_sigsegv;
123 }
124 target_to_host_sigset_internal(&set, &target_set);
125 sigprocmask(SIG_SETMASK, &set, NULL);
126 }
127 env->pc = pc;
128 env->npc = npc;
129 err |= __get_user(env->y, &((*grp)[MC_Y]));
130 err |= __get_user(tstate, &((*grp)[MC_TSTATE]));
131 env->asi = (tstate >> 24) & 0xff;
132 cpu_put_ccr(env, tstate >> 32);
133 cpu_put_cwp64(env, tstate & 0x1f);
134 err |= __get_user(env->gregs[1], (&(*grp)[MC_G1]));
135 err |= __get_user(env->gregs[2], (&(*grp)[MC_G2]));
136 err |= __get_user(env->gregs[3], (&(*grp)[MC_G3]));
137 err |= __get_user(env->gregs[4], (&(*grp)[MC_G4]));
138 err |= __get_user(env->gregs[5], (&(*grp)[MC_G5]));
139 err |= __get_user(env->gregs[6], (&(*grp)[MC_G6]));
140 err |= __get_user(env->gregs[7], (&(*grp)[MC_G7]));
141 err |= __get_user(env->regwptr[UREG_I0], (&(*grp)[MC_O0]));
142 err |= __get_user(env->regwptr[UREG_I1], (&(*grp)[MC_O1]));
143 err |= __get_user(env->regwptr[UREG_I2], (&(*grp)[MC_O2]));
144 err |= __get_user(env->regwptr[UREG_I3], (&(*grp)[MC_O3]));
145 err |= __get_user(env->regwptr[UREG_I4], (&(*grp)[MC_O4]));
146 err |= __get_user(env->regwptr[UREG_I5], (&(*grp)[MC_O5]));
147 err |= __get_user(env->regwptr[UREG_I6], (&(*grp)[MC_O6]));
148 err |= __get_user(env->regwptr[UREG_I7], (&(*grp)[MC_O7]));
149
150 err |= __get_user(fp, &(ucp->tuc_mcontext.mc_fp));
151 err |= __get_user(i7, &(ucp->tuc_mcontext.mc_i7));
152
153 w_addr = TARGET_STACK_BIAS+env->regwptr[UREG_I6];
154 if (put_user(fp, w_addr + offsetof(struct target_reg_window, ins[6]),
155 abi_ulong) != 0)
156 goto do_sigsegv;
157 if (put_user(i7, w_addr + offsetof(struct target_reg_window, ins[7]),
158 abi_ulong) != 0)
159 goto do_sigsegv;
160 /* FIXME this does not match how the kernel handles the FPU in
161 * its sparc64_set_context implementation. In particular the FPU
162 * is only restored if fenab is non-zero in:
163 * __get_user(fenab, &(ucp->tuc_mcontext.mc_fpregs.mcfpu_enab));
164 */
165 err |= __get_user(env->fprs, &(ucp->tuc_mcontext.mc_fpregs.mcfpu_fprs));
166 {
167 uint32_t *src = ucp->tuc_mcontext.mc_fpregs.mcfpu_fregs.sregs;
168 for (i = 0; i < 64; i++, src++) {
169 if (i & 1) {
170 err |= __get_user(env->fpr[i/2].l.lower, src);
171 } else {
172 err |= __get_user(env->fpr[i/2].l.upper, src);
173 }
174 }
175 }
176 err |= __get_user(env->fsr,
177 &(ucp->tuc_mcontext.mc_fpregs.mcfpu_fsr));
178 err |= __get_user(env->gsr,
179 &(ucp->tuc_mcontext.mc_fpregs.mcfpu_gsr));
180 if (err)
181 goto do_sigsegv;
182 unlock_user_struct(ucp, ucp_addr, 0);
183 return;
184 do_sigsegv:
185 unlock_user_struct(ucp, ucp_addr, 0);
186 force_sig(TARGET_SIGSEGV);
187}
188
189void sparc64_get_context(CPUSPARCState *env)
190{
191 abi_ulong ucp_addr;
192 struct target_ucontext *ucp;
193 target_mc_gregset_t *grp;
194 target_mcontext_t *mcp;
195 abi_ulong fp, i7, w_addr;
196 int err;
197 unsigned int i;
198 target_sigset_t target_set;
199 sigset_t set;
200
201 ucp_addr = env->regwptr[UREG_I0];
202 if (!lock_user_struct(VERIFY_WRITE, ucp, ucp_addr, 0))
203 goto do_sigsegv;
204
205 mcp = &ucp->tuc_mcontext;
206 grp = &mcp->mc_gregs;
207
208 /* Skip over the trap instruction, first. */
209 env->pc = env->npc;
210 env->npc += 4;
211
212 err = 0;
213
214 sigprocmask(0, NULL, &set);
215 host_to_target_sigset_internal(&target_set, &set);
216 if (TARGET_NSIG_WORDS == 1) {
217 err |= __put_user(target_set.sig[0],
218 (abi_ulong *)&ucp->tuc_sigmask);
219 } else {
220 abi_ulong *src, *dst;
221 src = target_set.sig;
222 dst = ucp->tuc_sigmask.sig;
223 for (i = 0; i < sizeof(target_sigset_t) / sizeof(abi_ulong);
224 i++, dst++, src++)
225 err |= __put_user(*src, dst);
226 if (err)
227 goto do_sigsegv;
228 }
229
230 /* XXX: tstate must be saved properly */
231 // err |= __put_user(env->tstate, &((*grp)[MC_TSTATE]));
232 err |= __put_user(env->pc, &((*grp)[MC_PC]));
233 err |= __put_user(env->npc, &((*grp)[MC_NPC]));
234 err |= __put_user(env->y, &((*grp)[MC_Y]));
235 err |= __put_user(env->gregs[1], &((*grp)[MC_G1]));
236 err |= __put_user(env->gregs[2], &((*grp)[MC_G2]));
237 err |= __put_user(env->gregs[3], &((*grp)[MC_G3]));
238 err |= __put_user(env->gregs[4], &((*grp)[MC_G4]));
239 err |= __put_user(env->gregs[5], &((*grp)[MC_G5]));
240 err |= __put_user(env->gregs[6], &((*grp)[MC_G6]));
241 err |= __put_user(env->gregs[7], &((*grp)[MC_G7]));
242 err |= __put_user(env->regwptr[UREG_I0], &((*grp)[MC_O0]));
243 err |= __put_user(env->regwptr[UREG_I1], &((*grp)[MC_O1]));
244 err |= __put_user(env->regwptr[UREG_I2], &((*grp)[MC_O2]));
245 err |= __put_user(env->regwptr[UREG_I3], &((*grp)[MC_O3]));
246 err |= __put_user(env->regwptr[UREG_I4], &((*grp)[MC_O4]));
247 err |= __put_user(env->regwptr[UREG_I5], &((*grp)[MC_O5]));
248 err |= __put_user(env->regwptr[UREG_I6], &((*grp)[MC_O6]));
249 err |= __put_user(env->regwptr[UREG_I7], &((*grp)[MC_O7]));
250
251 w_addr = TARGET_STACK_BIAS+env->regwptr[UREG_I6];
252 fp = i7 = 0;
253 if (get_user(fp, w_addr + offsetof(struct target_reg_window, ins[6]),
254 abi_ulong) != 0)
255 goto do_sigsegv;
256 if (get_user(i7, w_addr + offsetof(struct target_reg_window, ins[7]),
257 abi_ulong) != 0)
258 goto do_sigsegv;
259 err |= __put_user(fp, &(mcp->mc_fp));
260 err |= __put_user(i7, &(mcp->mc_i7));
261
262 {
263 uint32_t *dst = ucp->tuc_mcontext.mc_fpregs.mcfpu_fregs.sregs;
264 for (i = 0; i < 64; i++, dst++) {
265 if (i & 1) {
266 err |= __put_user(env->fpr[i/2].l.lower, dst);
267 } else {
268 err |= __put_user(env->fpr[i/2].l.upper, dst);
269 }
270 }
271 }
272 err |= __put_user(env->fsr, &(mcp->mc_fpregs.mcfpu_fsr));
273 err |= __put_user(env->gsr, &(mcp->mc_fpregs.mcfpu_gsr));
274 err |= __put_user(env->fprs, &(mcp->mc_fpregs.mcfpu_fprs));
275
276 if (err)
277 goto do_sigsegv;
278 unlock_user_struct(ucp, ucp_addr, 1);
279 return;
280 do_sigsegv:
281 unlock_user_struct(ucp, ucp_addr, 1);
282 force_sig(TARGET_SIGSEGV);
283}
284#endif