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