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 #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 void cpu_loop (CPUSPARCState *env) 153 { 154 CPUState *cs = env_cpu(env); 155 int trapnr; 156 abi_long ret; 157 target_siginfo_t info; 158 159 while (1) { 160 cpu_exec_start(cs); 161 trapnr = cpu_exec(cs); 162 cpu_exec_end(cs); 163 process_queued_cpu_work(cs); 164 165 /* Compute PSR before exposing state. */ 166 if (env->cc_op != CC_OP_FLAGS) { 167 cpu_get_psr(env); 168 } 169 170 switch (trapnr) { 171 #ifndef TARGET_SPARC64 172 case 0x88: 173 case 0x90: 174 #else 175 case 0x110: 176 case 0x16d: 177 #endif 178 ret = do_syscall (env, env->gregs[1], 179 env->regwptr[0], env->regwptr[1], 180 env->regwptr[2], env->regwptr[3], 181 env->regwptr[4], env->regwptr[5], 182 0, 0); 183 if (ret == -TARGET_ERESTARTSYS || ret == -TARGET_QEMU_ESIGRETURN) { 184 break; 185 } 186 if ((abi_ulong)ret >= (abi_ulong)(-515)) { 187 #if defined(TARGET_SPARC64) && !defined(TARGET_ABI32) 188 env->xcc |= PSR_CARRY; 189 #else 190 env->psr |= PSR_CARRY; 191 #endif 192 ret = -ret; 193 } else { 194 #if defined(TARGET_SPARC64) && !defined(TARGET_ABI32) 195 env->xcc &= ~PSR_CARRY; 196 #else 197 env->psr &= ~PSR_CARRY; 198 #endif 199 } 200 env->regwptr[0] = ret; 201 /* next instruction */ 202 env->pc = env->npc; 203 env->npc = env->npc + 4; 204 break; 205 case 0x83: /* flush windows */ 206 #ifdef TARGET_ABI32 207 case 0x103: 208 #endif 209 flush_windows(env); 210 /* next instruction */ 211 env->pc = env->npc; 212 env->npc = env->npc + 4; 213 break; 214 #ifndef TARGET_SPARC64 215 case TT_WIN_OVF: /* window overflow */ 216 save_window(env); 217 break; 218 case TT_WIN_UNF: /* window underflow */ 219 restore_window(env); 220 break; 221 case TT_TFAULT: 222 case TT_DFAULT: 223 { 224 info.si_signo = TARGET_SIGSEGV; 225 info.si_errno = 0; 226 /* XXX: check env->error_code */ 227 info.si_code = TARGET_SEGV_MAPERR; 228 info._sifields._sigfault._addr = env->mmuregs[4]; 229 queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); 230 } 231 break; 232 #else 233 case TT_SPILL: /* window overflow */ 234 save_window(env); 235 break; 236 case TT_FILL: /* window underflow */ 237 restore_window(env); 238 break; 239 case TT_TFAULT: 240 case TT_DFAULT: 241 { 242 info.si_signo = TARGET_SIGSEGV; 243 info.si_errno = 0; 244 /* XXX: check env->error_code */ 245 info.si_code = TARGET_SEGV_MAPERR; 246 if (trapnr == TT_DFAULT) 247 info._sifields._sigfault._addr = env->dmmu.mmuregs[4]; 248 else 249 info._sifields._sigfault._addr = cpu_tsptr(env)->tpc; 250 queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); 251 } 252 break; 253 #ifndef TARGET_ABI32 254 case 0x16e: 255 flush_windows(env); 256 sparc64_get_context(env); 257 break; 258 case 0x16f: 259 flush_windows(env); 260 sparc64_set_context(env); 261 break; 262 #endif 263 #endif 264 case EXCP_INTERRUPT: 265 /* just indicate that signals should be handled asap */ 266 break; 267 case TT_ILL_INSN: 268 { 269 info.si_signo = TARGET_SIGILL; 270 info.si_errno = 0; 271 info.si_code = TARGET_ILL_ILLOPC; 272 info._sifields._sigfault._addr = env->pc; 273 queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); 274 } 275 break; 276 case EXCP_DEBUG: 277 info.si_signo = TARGET_SIGTRAP; 278 info.si_errno = 0; 279 info.si_code = TARGET_TRAP_BRKPT; 280 queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); 281 break; 282 case EXCP_ATOMIC: 283 cpu_exec_step_atomic(cs); 284 break; 285 default: 286 fprintf(stderr, "Unhandled trap: 0x%x\n", trapnr); 287 cpu_dump_state(cs, stderr, 0); 288 exit(EXIT_FAILURE); 289 } 290 process_pending_signals (env); 291 } 292 } 293 294 void target_cpu_copy_regs(CPUArchState *env, struct target_pt_regs *regs) 295 { 296 int i; 297 env->pc = regs->pc; 298 env->npc = regs->npc; 299 env->y = regs->y; 300 for(i = 0; i < 8; i++) 301 env->gregs[i] = regs->u_regs[i]; 302 for(i = 0; i < 8; i++) 303 env->regwptr[i] = regs->u_regs[i + 8]; 304 } 305