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