qemu/linux-user/sparc/cpu_loop.c
<<
>>
Prefs
   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 "user-internals.h"
  24#include "cpu_loop-common.h"
  25#include "signal-common.h"
  26
  27#define SPARC64_STACK_BIAS 2047
  28
  29//#define DEBUG_WIN
  30
  31/* WARNING: dealing with register windows _is_ complicated. More info
  32   can be found at http://www.sics.se/~psm/sparcstack.html */
  33static inline int get_reg_index(CPUSPARCState *env, int cwp, int index)
  34{
  35    index = (index + cwp * 16) % (16 * env->nwindows);
  36    /* wrap handling : if cwp is on the last window, then we use the
  37       registers 'after' the end */
  38    if (index < 8 && env->cwp == env->nwindows - 1)
  39        index += 16 * env->nwindows;
  40    return index;
  41}
  42
  43/* save the register window 'cwp1' */
  44static inline void save_window_offset(CPUSPARCState *env, int cwp1)
  45{
  46    unsigned int i;
  47    abi_ulong sp_ptr;
  48
  49    sp_ptr = env->regbase[get_reg_index(env, cwp1, 6)];
  50#ifdef TARGET_SPARC64
  51    if (sp_ptr & 3)
  52        sp_ptr += SPARC64_STACK_BIAS;
  53#endif
  54#if defined(DEBUG_WIN)
  55    printf("win_overflow: sp_ptr=0x" TARGET_ABI_FMT_lx " save_cwp=%d\n",
  56           sp_ptr, cwp1);
  57#endif
  58    for(i = 0; i < 16; i++) {
  59        /* FIXME - what to do if put_user() fails? */
  60        put_user_ual(env->regbase[get_reg_index(env, cwp1, 8 + i)], sp_ptr);
  61        sp_ptr += sizeof(abi_ulong);
  62    }
  63}
  64
  65static void save_window(CPUSPARCState *env)
  66{
  67#ifndef TARGET_SPARC64
  68    unsigned int new_wim;
  69    new_wim = ((env->wim >> 1) | (env->wim << (env->nwindows - 1))) &
  70        ((1LL << env->nwindows) - 1);
  71    save_window_offset(env, cpu_cwp_dec(env, env->cwp - 2));
  72    env->wim = new_wim;
  73#else
  74    /*
  75     * cansave is zero if the spill trap handler is triggered by `save` and
  76     * nonzero if triggered by a `flushw`
  77     */
  78    save_window_offset(env, cpu_cwp_dec(env, env->cwp - env->cansave - 2));
  79    env->cansave++;
  80    env->canrestore--;
  81#endif
  82}
  83
  84static void restore_window(CPUSPARCState *env)
  85{
  86#ifndef TARGET_SPARC64
  87    unsigned int new_wim;
  88#endif
  89    unsigned int i, cwp1;
  90    abi_ulong sp_ptr;
  91
  92#ifndef TARGET_SPARC64
  93    new_wim = ((env->wim << 1) | (env->wim >> (env->nwindows - 1))) &
  94        ((1LL << env->nwindows) - 1);
  95#endif
  96
  97    /* restore the invalid window */
  98    cwp1 = cpu_cwp_inc(env, env->cwp + 1);
  99    sp_ptr = env->regbase[get_reg_index(env, cwp1, 6)];
 100#ifdef TARGET_SPARC64
 101    if (sp_ptr & 3)
 102        sp_ptr += SPARC64_STACK_BIAS;
 103#endif
 104#if defined(DEBUG_WIN)
 105    printf("win_underflow: sp_ptr=0x" TARGET_ABI_FMT_lx " load_cwp=%d\n",
 106           sp_ptr, cwp1);
 107#endif
 108    for(i = 0; i < 16; i++) {
 109        /* FIXME - what to do if get_user() fails? */
 110        get_user_ual(env->regbase[get_reg_index(env, cwp1, 8 + i)], sp_ptr);
 111        sp_ptr += sizeof(abi_ulong);
 112    }
 113#ifdef TARGET_SPARC64
 114    env->canrestore++;
 115    if (env->cleanwin < env->nwindows - 1)
 116        env->cleanwin++;
 117    env->cansave--;
 118#else
 119    env->wim = new_wim;
 120#endif
 121}
 122
 123static void flush_windows(CPUSPARCState *env)
 124{
 125    int offset, cwp1;
 126
 127    offset = 1;
 128    for(;;) {
 129        /* if restore would invoke restore_window(), then we can stop */
 130        cwp1 = cpu_cwp_inc(env, env->cwp + offset);
 131#ifndef TARGET_SPARC64
 132        if (env->wim & (1 << cwp1))
 133            break;
 134#else
 135        if (env->canrestore == 0)
 136            break;
 137        env->cansave++;
 138        env->canrestore--;
 139#endif
 140        save_window_offset(env, cwp1);
 141        offset++;
 142    }
 143    cwp1 = cpu_cwp_inc(env, env->cwp + 1);
 144#ifndef TARGET_SPARC64
 145    /* set wim so that restore will reload the registers */
 146    env->wim = 1 << cwp1;
 147#endif
 148#if defined(DEBUG_WIN)
 149    printf("flush_windows: nb=%d\n", offset - 1);
 150#endif
 151}
 152
 153void cpu_loop (CPUSPARCState *env)
 154{
 155    CPUState *cs = env_cpu(env);
 156    int trapnr;
 157    abi_long ret;
 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 == -QEMU_ERESTARTSYS || ret == -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#else
 222        case TT_SPILL: /* window overflow */
 223            save_window(env);
 224            break;
 225        case TT_FILL: /* window underflow */
 226            restore_window(env);
 227            break;
 228#ifndef TARGET_ABI32
 229        case 0x16e:
 230            flush_windows(env);
 231            sparc64_get_context(env);
 232            break;
 233        case 0x16f:
 234            flush_windows(env);
 235            sparc64_set_context(env);
 236            break;
 237#endif
 238#endif
 239        case EXCP_INTERRUPT:
 240            /* just indicate that signals should be handled asap */
 241            break;
 242        case TT_ILL_INSN:
 243            force_sig_fault(TARGET_SIGILL, TARGET_ILL_ILLOPC, env->pc);
 244            break;
 245        case EXCP_DEBUG:
 246            force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->pc);
 247            break;
 248        case EXCP_ATOMIC:
 249            cpu_exec_step_atomic(cs);
 250            break;
 251        default:
 252            fprintf(stderr, "Unhandled trap: 0x%x\n", trapnr);
 253            cpu_dump_state(cs, stderr, 0);
 254            exit(EXIT_FAILURE);
 255        }
 256        process_pending_signals (env);
 257    }
 258}
 259
 260void target_cpu_copy_regs(CPUArchState *env, struct target_pt_regs *regs)
 261{
 262    int i;
 263    env->pc = regs->pc;
 264    env->npc = regs->npc;
 265    env->y = regs->y;
 266    for(i = 0; i < 8; i++)
 267        env->gregs[i] = regs->u_regs[i];
 268    for(i = 0; i < 8; i++)
 269        env->regwptr[i] = regs->u_regs[i + 8];
 270}
 271