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 "user-internals.h" 23 #include "cpu_loop-common.h" 24 #include "signal-common.h" 25 26 #define SPARC64_STACK_BIAS 2047 27 28 //#define DEBUG_WIN 29 30 /* WARNING: dealing with register windows _is_ complicated. More info 31 can be found at http://www.sics.se/~psm/sparcstack.html */ 32 static inline int get_reg_index(CPUSPARCState *env, int cwp, int index) 33 { 34 index = (index + cwp * 16) % (16 * env->nwindows); 35 /* wrap handling : if cwp is on the last window, then we use the 36 registers 'after' the end */ 37 if (index < 8 && env->cwp == env->nwindows - 1) 38 index += 16 * env->nwindows; 39 return index; 40 } 41 42 /* save the register window 'cwp1' */ 43 static inline void save_window_offset(CPUSPARCState *env, int cwp1) 44 { 45 unsigned int i; 46 abi_ulong sp_ptr; 47 48 sp_ptr = env->regbase[get_reg_index(env, cwp1, 6)]; 49 #ifdef TARGET_SPARC64 50 if (sp_ptr & 3) 51 sp_ptr += SPARC64_STACK_BIAS; 52 #endif 53 #if defined(DEBUG_WIN) 54 printf("win_overflow: sp_ptr=0x" TARGET_ABI_FMT_lx " save_cwp=%d\n", 55 sp_ptr, cwp1); 56 #endif 57 for(i = 0; i < 16; i++) { 58 /* FIXME - what to do if put_user() fails? */ 59 put_user_ual(env->regbase[get_reg_index(env, cwp1, 8 + i)], sp_ptr); 60 sp_ptr += sizeof(abi_ulong); 61 } 62 } 63 64 static void save_window(CPUSPARCState *env) 65 { 66 #ifndef TARGET_SPARC64 67 unsigned int new_wim; 68 new_wim = ((env->wim >> 1) | (env->wim << (env->nwindows - 1))) & 69 ((1LL << env->nwindows) - 1); 70 save_window_offset(env, cpu_cwp_dec(env, env->cwp - 2)); 71 env->wim = new_wim; 72 #else 73 /* 74 * cansave is zero if the spill trap handler is triggered by `save` and 75 * nonzero if triggered by a `flushw` 76 */ 77 save_window_offset(env, cpu_cwp_dec(env, env->cwp - env->cansave - 2)); 78 env->cansave++; 79 env->canrestore--; 80 #endif 81 } 82 83 static void restore_window(CPUSPARCState *env) 84 { 85 #ifndef TARGET_SPARC64 86 unsigned int new_wim; 87 #endif 88 unsigned int i, cwp1; 89 abi_ulong sp_ptr; 90 91 #ifndef TARGET_SPARC64 92 new_wim = ((env->wim << 1) | (env->wim >> (env->nwindows - 1))) & 93 ((1LL << env->nwindows) - 1); 94 #endif 95 96 /* restore the invalid window */ 97 cwp1 = cpu_cwp_inc(env, env->cwp + 1); 98 sp_ptr = env->regbase[get_reg_index(env, cwp1, 6)]; 99 #ifdef TARGET_SPARC64 100 if (sp_ptr & 3) 101 sp_ptr += SPARC64_STACK_BIAS; 102 #endif 103 #if defined(DEBUG_WIN) 104 printf("win_underflow: sp_ptr=0x" TARGET_ABI_FMT_lx " load_cwp=%d\n", 105 sp_ptr, cwp1); 106 #endif 107 for(i = 0; i < 16; i++) { 108 /* FIXME - what to do if get_user() fails? */ 109 get_user_ual(env->regbase[get_reg_index(env, cwp1, 8 + i)], sp_ptr); 110 sp_ptr += sizeof(abi_ulong); 111 } 112 #ifdef TARGET_SPARC64 113 env->canrestore++; 114 if (env->cleanwin < env->nwindows - 1) 115 env->cleanwin++; 116 env->cansave--; 117 #else 118 env->wim = new_wim; 119 #endif 120 } 121 122 static void flush_windows(CPUSPARCState *env) 123 { 124 int offset, cwp1; 125 126 offset = 1; 127 for(;;) { 128 /* if restore would invoke restore_window(), then we can stop */ 129 cwp1 = cpu_cwp_inc(env, env->cwp + offset); 130 #ifndef TARGET_SPARC64 131 if (env->wim & (1 << cwp1)) 132 break; 133 #else 134 if (env->canrestore == 0) 135 break; 136 env->cansave++; 137 env->canrestore--; 138 #endif 139 save_window_offset(env, cwp1); 140 offset++; 141 } 142 cwp1 = cpu_cwp_inc(env, env->cwp + 1); 143 #ifndef TARGET_SPARC64 144 /* set wim so that restore will reload the registers */ 145 env->wim = 1 << cwp1; 146 #endif 147 #if defined(DEBUG_WIN) 148 printf("flush_windows: nb=%d\n", offset - 1); 149 #endif 150 } 151 152 static void next_instruction(CPUSPARCState *env) 153 { 154 env->pc = env->npc; 155 env->npc = env->npc + 4; 156 } 157 158 static uint32_t do_getcc(CPUSPARCState *env) 159 { 160 #ifdef TARGET_SPARC64 161 return cpu_get_ccr(env) & 0xf; 162 #else 163 return extract32(cpu_get_psr(env), 20, 4); 164 #endif 165 } 166 167 static void do_setcc(CPUSPARCState *env, uint32_t icc) 168 { 169 #ifdef TARGET_SPARC64 170 cpu_put_ccr(env, (cpu_get_ccr(env) & 0xf0) | (icc & 0xf)); 171 #else 172 cpu_put_psr(env, deposit32(cpu_get_psr(env), 20, 4, icc)); 173 #endif 174 } 175 176 static uint32_t do_getpsr(CPUSPARCState *env) 177 { 178 #ifdef TARGET_SPARC64 179 const uint64_t TSTATE_CWP = 0x1f; 180 const uint64_t TSTATE_ICC = 0xfull << 32; 181 const uint64_t TSTATE_XCC = 0xfull << 36; 182 const uint32_t PSR_S = 0x00000080u; 183 const uint32_t PSR_V8PLUS = 0xff000000u; 184 uint64_t tstate = sparc64_tstate(env); 185 186 /* See <asm/psrcompat.h>, tstate_to_psr. */ 187 return ((tstate & TSTATE_CWP) | 188 PSR_S | 189 ((tstate & TSTATE_ICC) >> 12) | 190 ((tstate & TSTATE_XCC) >> 20) | 191 PSR_V8PLUS); 192 #else 193 return (cpu_get_psr(env) & (PSR_ICC | PSR_CWP)) | PSR_S; 194 #endif 195 } 196 197 /* Avoid ifdefs below for the abi32 and abi64 paths. */ 198 #ifdef TARGET_ABI32 199 #define TARGET_TT_SYSCALL (TT_TRAP + 0x10) /* t_linux */ 200 #else 201 #define TARGET_TT_SYSCALL (TT_TRAP + 0x6d) /* tl0_linux64 */ 202 #endif 203 204 /* Avoid ifdefs below for the v9 and pre-v9 hw traps. */ 205 #ifdef TARGET_SPARC64 206 #define TARGET_TT_SPILL TT_SPILL 207 #define TARGET_TT_FILL TT_FILL 208 #else 209 #define TARGET_TT_SPILL TT_WIN_OVF 210 #define TARGET_TT_FILL TT_WIN_UNF 211 #endif 212 213 void cpu_loop (CPUSPARCState *env) 214 { 215 CPUState *cs = env_cpu(env); 216 int trapnr; 217 abi_long ret; 218 219 while (1) { 220 cpu_exec_start(cs); 221 trapnr = cpu_exec(cs); 222 cpu_exec_end(cs); 223 process_queued_cpu_work(cs); 224 225 switch (trapnr) { 226 case TARGET_TT_SYSCALL: 227 ret = do_syscall (env, env->gregs[1], 228 env->regwptr[0], env->regwptr[1], 229 env->regwptr[2], env->regwptr[3], 230 env->regwptr[4], env->regwptr[5], 231 0, 0); 232 if (ret == -QEMU_ERESTARTSYS || ret == -QEMU_ESIGRETURN) { 233 break; 234 } 235 if ((abi_ulong)ret >= (abi_ulong)(-515)) { 236 set_syscall_C(env, 1); 237 ret = -ret; 238 } else { 239 set_syscall_C(env, 0); 240 } 241 env->regwptr[0] = ret; 242 /* next instruction */ 243 env->pc = env->npc; 244 env->npc = env->npc + 4; 245 break; 246 247 case TT_TRAP + 0x01: /* breakpoint */ 248 case EXCP_DEBUG: 249 force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->pc); 250 break; 251 252 case TT_TRAP + 0x02: /* div0 */ 253 case TT_DIV_ZERO: 254 force_sig_fault(TARGET_SIGFPE, TARGET_FPE_INTDIV, env->pc); 255 break; 256 257 case TT_TRAP + 0x03: /* flush windows */ 258 flush_windows(env); 259 next_instruction(env); 260 break; 261 262 case TT_TRAP + 0x20: /* getcc */ 263 env->gregs[1] = do_getcc(env); 264 next_instruction(env); 265 break; 266 case TT_TRAP + 0x21: /* setcc */ 267 do_setcc(env, env->gregs[1]); 268 next_instruction(env); 269 break; 270 case TT_TRAP + 0x22: /* getpsr */ 271 env->gregs[1] = do_getpsr(env); 272 next_instruction(env); 273 break; 274 275 #ifdef TARGET_SPARC64 276 case TT_TRAP + 0x6e: 277 flush_windows(env); 278 sparc64_get_context(env); 279 break; 280 case TT_TRAP + 0x6f: 281 flush_windows(env); 282 sparc64_set_context(env); 283 break; 284 #endif 285 286 case TARGET_TT_SPILL: /* window overflow */ 287 save_window(env); 288 break; 289 case TARGET_TT_FILL: /* window underflow */ 290 restore_window(env); 291 break; 292 293 case TT_FP_EXCP: 294 { 295 int code = TARGET_FPE_FLTUNK; 296 target_ulong fsr = cpu_get_fsr(env); 297 298 if ((fsr & FSR_FTT_MASK) == FSR_FTT_IEEE_EXCP) { 299 if (fsr & FSR_NVC) { 300 code = TARGET_FPE_FLTINV; 301 } else if (fsr & FSR_OFC) { 302 code = TARGET_FPE_FLTOVF; 303 } else if (fsr & FSR_UFC) { 304 code = TARGET_FPE_FLTUND; 305 } else if (fsr & FSR_DZC) { 306 code = TARGET_FPE_FLTDIV; 307 } else if (fsr & FSR_NXC) { 308 code = TARGET_FPE_FLTRES; 309 } 310 } 311 force_sig_fault(TARGET_SIGFPE, code, env->pc); 312 } 313 break; 314 315 case EXCP_INTERRUPT: 316 /* just indicate that signals should be handled asap */ 317 break; 318 case TT_ILL_INSN: 319 force_sig_fault(TARGET_SIGILL, TARGET_ILL_ILLOPC, env->pc); 320 break; 321 case TT_PRIV_INSN: 322 force_sig_fault(TARGET_SIGILL, TARGET_ILL_PRVOPC, env->pc); 323 break; 324 case TT_TOVF: 325 force_sig_fault(TARGET_SIGEMT, TARGET_EMT_TAGOVF, env->pc); 326 break; 327 #ifdef TARGET_SPARC64 328 case TT_PRIV_ACT: 329 /* Note do_privact defers to do_privop. */ 330 force_sig_fault(TARGET_SIGILL, TARGET_ILL_PRVOPC, env->pc); 331 break; 332 #else 333 case TT_NCP_INSN: 334 force_sig_fault(TARGET_SIGILL, TARGET_ILL_COPROC, env->pc); 335 break; 336 case TT_UNIMP_FLUSH: 337 next_instruction(env); 338 break; 339 #endif 340 case EXCP_ATOMIC: 341 cpu_exec_step_atomic(cs); 342 break; 343 default: 344 /* 345 * Most software trap numbers vector to BAD_TRAP. 346 * Handle anything not explicitly matched above. 347 */ 348 if (trapnr >= TT_TRAP && trapnr <= TT_TRAP + 0x7f) { 349 force_sig_fault(TARGET_SIGILL, ILL_ILLTRP, env->pc); 350 break; 351 } 352 fprintf(stderr, "Unhandled trap: 0x%x\n", trapnr); 353 cpu_dump_state(cs, stderr, 0); 354 exit(EXIT_FAILURE); 355 } 356 process_pending_signals (env); 357 } 358 } 359 360 void target_cpu_copy_regs(CPUArchState *env, struct target_pt_regs *regs) 361 { 362 int i; 363 env->pc = regs->pc; 364 env->npc = regs->npc; 365 env->y = regs->y; 366 for(i = 0; i < 8; i++) 367 env->gregs[i] = regs->u_regs[i]; 368 for(i = 0; i < 8; i++) 369 env->regwptr[i] = regs->u_regs[i + 8]; 370 } 371