4 * Copyright (c) 2003-2008 Fabrice Bellard
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.
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.
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/>.
20 #include "qemu/osdep.h"
21 #include "qemu-common.h"
23 #include "cpu_loop-common.h"
25 #define SPARC64_STACK_BIAS 2047
29 /* WARNING: dealing with register windows _is_ complicated. More info
30 can be found at http://www.sics.se/~psm/sparcstack.html */
31 static inline int get_reg_index(CPUSPARCState
*env
, int cwp
, int index
)
33 index
= (index
+ cwp
* 16) % (16 * env
->nwindows
);
34 /* wrap handling : if cwp is on the last window, then we use the
35 registers 'after' the end */
36 if (index
< 8 && env
->cwp
== env
->nwindows
- 1)
37 index
+= 16 * env
->nwindows
;
41 /* save the register window 'cwp1' */
42 static inline void save_window_offset(CPUSPARCState
*env
, int cwp1
)
47 sp_ptr
= env
->regbase
[get_reg_index(env
, cwp1
, 6)];
50 sp_ptr
+= SPARC64_STACK_BIAS
;
52 #if defined(DEBUG_WIN)
53 printf("win_overflow: sp_ptr=0x" TARGET_ABI_FMT_lx
" save_cwp=%d\n",
56 for(i
= 0; i
< 16; i
++) {
57 /* FIXME - what to do if put_user() fails? */
58 put_user_ual(env
->regbase
[get_reg_index(env
, cwp1
, 8 + i
)], sp_ptr
);
59 sp_ptr
+= sizeof(abi_ulong
);
63 static void save_window(CPUSPARCState
*env
)
65 #ifndef TARGET_SPARC64
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));
72 save_window_offset(env
, cpu_cwp_dec(env
, env
->cwp
- 2));
78 static void restore_window(CPUSPARCState
*env
)
80 #ifndef TARGET_SPARC64
86 #ifndef TARGET_SPARC64
87 new_wim
= ((env
->wim
<< 1) | (env
->wim
>> (env
->nwindows
- 1))) &
88 ((1LL << env
->nwindows
) - 1);
91 /* restore the invalid window */
92 cwp1
= cpu_cwp_inc(env
, env
->cwp
+ 1);
93 sp_ptr
= env
->regbase
[get_reg_index(env
, cwp1
, 6)];
96 sp_ptr
+= SPARC64_STACK_BIAS
;
98 #if defined(DEBUG_WIN)
99 printf("win_underflow: sp_ptr=0x" TARGET_ABI_FMT_lx
" load_cwp=%d\n",
102 for(i
= 0; i
< 16; i
++) {
103 /* FIXME - what to do if get_user() fails? */
104 get_user_ual(env
->regbase
[get_reg_index(env
, cwp1
, 8 + i
)], sp_ptr
);
105 sp_ptr
+= sizeof(abi_ulong
);
107 #ifdef TARGET_SPARC64
109 if (env
->cleanwin
< env
->nwindows
- 1)
117 static void flush_windows(CPUSPARCState
*env
)
123 /* if restore would invoke restore_window(), then we can stop */
124 cwp1
= cpu_cwp_inc(env
, env
->cwp
+ offset
);
125 #ifndef TARGET_SPARC64
126 if (env
->wim
& (1 << cwp1
))
129 if (env
->canrestore
== 0)
134 save_window_offset(env
, cwp1
);
137 cwp1
= cpu_cwp_inc(env
, env
->cwp
+ 1);
138 #ifndef TARGET_SPARC64
139 /* set wim so that restore will reload the registers */
140 env
->wim
= 1 << cwp1
;
142 #if defined(DEBUG_WIN)
143 printf("flush_windows: nb=%d\n", offset
- 1);
147 void cpu_loop (CPUSPARCState
*env
)
149 CPUState
*cs
= env_cpu(env
);
152 target_siginfo_t info
;
156 trapnr
= cpu_exec(cs
);
158 process_queued_cpu_work(cs
);
160 /* Compute PSR before exposing state. */
161 if (env
->cc_op
!= CC_OP_FLAGS
) {
166 #ifndef TARGET_SPARC64
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],
178 if (ret
== -TARGET_ERESTARTSYS
|| ret
== -TARGET_QEMU_ESIGRETURN
) {
181 if ((abi_ulong
)ret
>= (abi_ulong
)(-515)) {
182 #if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
183 env
->xcc
|= PSR_CARRY
;
185 env
->psr
|= PSR_CARRY
;
189 #if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
190 env
->xcc
&= ~PSR_CARRY
;
192 env
->psr
&= ~PSR_CARRY
;
195 env
->regwptr
[0] = ret
;
196 /* next instruction */
198 env
->npc
= env
->npc
+ 4;
200 case 0x83: /* flush windows */
205 /* next instruction */
207 env
->npc
= env
->npc
+ 4;
209 #ifndef TARGET_SPARC64
210 case TT_WIN_OVF
: /* window overflow */
213 case TT_WIN_UNF
: /* window underflow */
219 info
.si_signo
= TARGET_SIGSEGV
;
221 /* XXX: check env->error_code */
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
);
228 case TT_SPILL
: /* window overflow */
231 case TT_FILL
: /* window underflow */
237 info
.si_signo
= TARGET_SIGSEGV
;
239 /* XXX: check env->error_code */
240 info
.si_code
= TARGET_SEGV_MAPERR
;
241 if (trapnr
== TT_DFAULT
)
242 info
._sifields
._sigfault
._addr
= env
->dmmu
.mmuregs
[4];
244 info
._sifields
._sigfault
._addr
= cpu_tsptr(env
)->tpc
;
245 queue_signal(env
, info
.si_signo
, QEMU_SI_FAULT
, &info
);
251 sparc64_get_context(env
);
255 sparc64_set_context(env
);
260 /* just indicate that signals should be handled asap */
264 info
.si_signo
= TARGET_SIGILL
;
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
);
272 info
.si_signo
= TARGET_SIGTRAP
;
274 info
.si_code
= TARGET_TRAP_BRKPT
;
275 queue_signal(env
, info
.si_signo
, QEMU_SI_FAULT
, &info
);
278 cpu_exec_step_atomic(cs
);
281 fprintf(stderr
, "Unhandled trap: 0x%x\n", trapnr
);
282 cpu_dump_state(cs
, stderr
, 0);
285 process_pending_signals (env
);
289 void target_cpu_copy_regs(CPUArchState
*env
, struct target_pt_regs
*regs
)
293 env
->npc
= regs
->npc
;
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];