qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

cpu_loop.c (7658B)


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