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