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-common.h" 22 #include "qemu.h" 23 #include "cpu_loop-common.h" 24 25 #define SPARC64_STACK_BIAS 2047 26 27 //#define DEBUG_WIN 28 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) 32 { 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; 38 return index; 39 } 40 41 /* save the register window 'cwp1' */ 42 static 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 /* 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); 60 } 61 } 62 63 static 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 78 static 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 /* restore the invalid window */ 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 /* 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); 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 117 static void flush_windows(CPUSPARCState *env) 118 { 119 int offset, cwp1; 120 121 offset = 1; 122 for(;;) { 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)) 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 /* set wim so that restore will reload the registers */ 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 147 void 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 /* Compute PSR before exposing state. */ 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 /* next instruction */ 197 env->pc = env->npc; 198 env->npc = env->npc + 4; 199 break; 200 case 0x83: /* flush windows */ 201 #ifdef TARGET_ABI32 202 case 0x103: 203 #endif 204 flush_windows(env); 205 /* next instruction */ 206 env->pc = env->npc; 207 env->npc = env->npc + 4; 208 break; 209 #ifndef TARGET_SPARC64 210 case TT_WIN_OVF: /* window overflow */ 211 save_window(env); 212 break; 213 case TT_WIN_UNF: /* window underflow */ 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 /* 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); 225 } 226 break; 227 #else 228 case TT_SPILL: /* window overflow */ 229 save_window(env); 230 break; 231 case TT_FILL: /* window underflow */ 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 /* 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]; 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 /* just indicate that signals should be handled asap */ 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 289 void 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