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