1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20#include "qemu/osdep.h"
21#include "qemu-common.h"
22#include "qemu.h"
23#include "cpu_loop-common.h"
24
25#define SPARC64_STACK_BIAS 2047
26
27
28
29
30
31static inline int get_reg_index(CPUSPARCState *env, int cwp, int index)
32{
33 index = (index + cwp * 16) % (16 * env->nwindows);
34
35
36 if (index < 8 && env->cwp == env->nwindows - 1)
37 index += 16 * env->nwindows;
38 return index;
39}
40
41
42static inline void save_window_offset(CPUSPARCState *env, int cwp1)
43{
44 unsigned int i;
45 abi_ulong sp_ptr;
46
47 sp_ptr = env->regbase[get_reg_index(env, cwp1, 6)];
48#ifdef TARGET_SPARC64
49 if (sp_ptr & 3)
50 sp_ptr += SPARC64_STACK_BIAS;
51#endif
52#if defined(DEBUG_WIN)
53 printf("win_overflow: sp_ptr=0x" TARGET_ABI_FMT_lx " save_cwp=%d\n",
54 sp_ptr, cwp1);
55#endif
56 for(i = 0; i < 16; i++) {
57
58 put_user_ual(env->regbase[get_reg_index(env, cwp1, 8 + i)], sp_ptr);
59 sp_ptr += sizeof(abi_ulong);
60 }
61}
62
63static void save_window(CPUSPARCState *env)
64{
65#ifndef TARGET_SPARC64
66 unsigned int new_wim;
67 new_wim = ((env->wim >> 1) | (env->wim << (env->nwindows - 1))) &
68 ((1LL << env->nwindows) - 1);
69 save_window_offset(env, cpu_cwp_dec(env, env->cwp - 2));
70 env->wim = new_wim;
71#else
72 save_window_offset(env, cpu_cwp_dec(env, env->cwp - 2));
73 env->cansave++;
74 env->canrestore--;
75#endif
76}
77
78static void restore_window(CPUSPARCState *env)
79{
80#ifndef TARGET_SPARC64
81 unsigned int new_wim;
82#endif
83 unsigned int i, cwp1;
84 abi_ulong sp_ptr;
85
86#ifndef TARGET_SPARC64
87 new_wim = ((env->wim << 1) | (env->wim >> (env->nwindows - 1))) &
88 ((1LL << env->nwindows) - 1);
89#endif
90
91
92 cwp1 = cpu_cwp_inc(env, env->cwp + 1);
93 sp_ptr = env->regbase[get_reg_index(env, cwp1, 6)];
94#ifdef TARGET_SPARC64
95 if (sp_ptr & 3)
96 sp_ptr += SPARC64_STACK_BIAS;
97#endif
98#if defined(DEBUG_WIN)
99 printf("win_underflow: sp_ptr=0x" TARGET_ABI_FMT_lx " load_cwp=%d\n",
100 sp_ptr, cwp1);
101#endif
102 for(i = 0; i < 16; i++) {
103
104 get_user_ual(env->regbase[get_reg_index(env, cwp1, 8 + i)], sp_ptr);
105 sp_ptr += sizeof(abi_ulong);
106 }
107#ifdef TARGET_SPARC64
108 env->canrestore++;
109 if (env->cleanwin < env->nwindows - 1)
110 env->cleanwin++;
111 env->cansave--;
112#else
113 env->wim = new_wim;
114#endif
115}
116
117static void flush_windows(CPUSPARCState *env)
118{
119 int offset, cwp1;
120
121 offset = 1;
122 for(;;) {
123
124 cwp1 = cpu_cwp_inc(env, env->cwp + offset);
125#ifndef TARGET_SPARC64
126 if (env->wim & (1 << cwp1))
127 break;
128#else
129 if (env->canrestore == 0)
130 break;
131 env->cansave++;
132 env->canrestore--;
133#endif
134 save_window_offset(env, cwp1);
135 offset++;
136 }
137 cwp1 = cpu_cwp_inc(env, env->cwp + 1);
138#ifndef TARGET_SPARC64
139
140 env->wim = 1 << cwp1;
141#endif
142#if defined(DEBUG_WIN)
143 printf("flush_windows: nb=%d\n", offset - 1);
144#endif
145}
146
147void cpu_loop (CPUSPARCState *env)
148{
149 CPUState *cs = env_cpu(env);
150 int trapnr;
151 abi_long ret;
152 target_siginfo_t info;
153
154 while (1) {
155 cpu_exec_start(cs);
156 trapnr = cpu_exec(cs);
157 cpu_exec_end(cs);
158 process_queued_cpu_work(cs);
159
160
161 if (env->cc_op != CC_OP_FLAGS) {
162 cpu_get_psr(env);
163 }
164
165 switch (trapnr) {
166#ifndef TARGET_SPARC64
167 case 0x88:
168 case 0x90:
169#else
170 case 0x110:
171 case 0x16d:
172#endif
173 ret = do_syscall (env, env->gregs[1],
174 env->regwptr[0], env->regwptr[1],
175 env->regwptr[2], env->regwptr[3],
176 env->regwptr[4], env->regwptr[5],
177 0, 0);
178 if (ret == -TARGET_ERESTARTSYS || ret == -TARGET_QEMU_ESIGRETURN) {
179 break;
180 }
181 if ((abi_ulong)ret >= (abi_ulong)(-515)) {
182#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
183 env->xcc |= PSR_CARRY;
184#else
185 env->psr |= PSR_CARRY;
186#endif
187 ret = -ret;
188 } else {
189#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
190 env->xcc &= ~PSR_CARRY;
191#else
192 env->psr &= ~PSR_CARRY;
193#endif
194 }
195 env->regwptr[0] = ret;
196
197 env->pc = env->npc;
198 env->npc = env->npc + 4;
199 break;
200 case 0x83:
201#ifdef TARGET_ABI32
202 case 0x103:
203#endif
204 flush_windows(env);
205
206 env->pc = env->npc;
207 env->npc = env->npc + 4;
208 break;
209#ifndef TARGET_SPARC64
210 case TT_WIN_OVF:
211 save_window(env);
212 break;
213 case TT_WIN_UNF:
214 restore_window(env);
215 break;
216 case TT_TFAULT:
217 case TT_DFAULT:
218 {
219 info.si_signo = TARGET_SIGSEGV;
220 info.si_errno = 0;
221
222 info.si_code = TARGET_SEGV_MAPERR;
223 info._sifields._sigfault._addr = env->mmuregs[4];
224 queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
225 }
226 break;
227#else
228 case TT_SPILL:
229 save_window(env);
230 break;
231 case TT_FILL:
232 restore_window(env);
233 break;
234 case TT_TFAULT:
235 case TT_DFAULT:
236 {
237 info.si_signo = TARGET_SIGSEGV;
238 info.si_errno = 0;
239
240 info.si_code = TARGET_SEGV_MAPERR;
241 if (trapnr == TT_DFAULT)
242 info._sifields._sigfault._addr = env->dmmu.mmuregs[4];
243 else
244 info._sifields._sigfault._addr = cpu_tsptr(env)->tpc;
245 queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
246 }
247 break;
248#ifndef TARGET_ABI32
249 case 0x16e:
250 flush_windows(env);
251 sparc64_get_context(env);
252 break;
253 case 0x16f:
254 flush_windows(env);
255 sparc64_set_context(env);
256 break;
257#endif
258#endif
259 case EXCP_INTERRUPT:
260
261 break;
262 case TT_ILL_INSN:
263 {
264 info.si_signo = TARGET_SIGILL;
265 info.si_errno = 0;
266 info.si_code = TARGET_ILL_ILLOPC;
267 info._sifields._sigfault._addr = env->pc;
268 queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
269 }
270 break;
271 case EXCP_DEBUG:
272 info.si_signo = TARGET_SIGTRAP;
273 info.si_errno = 0;
274 info.si_code = TARGET_TRAP_BRKPT;
275 queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
276 break;
277 case EXCP_ATOMIC:
278 cpu_exec_step_atomic(cs);
279 break;
280 default:
281 fprintf(stderr, "Unhandled trap: 0x%x\n", trapnr);
282 cpu_dump_state(cs, stderr, 0);
283 exit(EXIT_FAILURE);
284 }
285 process_pending_signals (env);
286 }
287}
288
289void target_cpu_copy_regs(CPUArchState *env, struct target_pt_regs *regs)
290{
291 int i;
292 env->pc = regs->pc;
293 env->npc = regs->npc;
294 env->y = regs->y;
295 for(i = 0; i < 8; i++)
296 env->gregs[i] = regs->u_regs[i];
297 for(i = 0; i < 8; i++)
298 env->regwptr[i] = regs->u_regs[i + 8];
299}
300