cachepc-qemu

Fork of AMDESE/qemu with changes for cachepc side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-qemu
Log | Files | Refs | Submodules | LICENSE | sfeed.txt

cpu_loop.c (9030B)


      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        case TT_TFAULT:
    223        case TT_DFAULT:
    224            {
    225                info.si_signo = TARGET_SIGSEGV;
    226                info.si_errno = 0;
    227                /* XXX: check env->error_code */
    228                info.si_code = TARGET_SEGV_MAPERR;
    229                info._sifields._sigfault._addr = env->mmuregs[4];
    230                queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
    231            }
    232            break;
    233#else
    234        case TT_SPILL: /* window overflow */
    235            save_window(env);
    236            break;
    237        case TT_FILL: /* window underflow */
    238            restore_window(env);
    239            break;
    240        case TT_TFAULT:
    241        case TT_DFAULT:
    242            {
    243                info.si_signo = TARGET_SIGSEGV;
    244                info.si_errno = 0;
    245                /* XXX: check env->error_code */
    246                info.si_code = TARGET_SEGV_MAPERR;
    247                if (trapnr == TT_DFAULT)
    248                    info._sifields._sigfault._addr = env->dmmu.mmuregs[4];
    249                else
    250                    info._sifields._sigfault._addr = cpu_tsptr(env)->tpc;
    251                queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
    252            }
    253            break;
    254#ifndef TARGET_ABI32
    255        case 0x16e:
    256            flush_windows(env);
    257            sparc64_get_context(env);
    258            break;
    259        case 0x16f:
    260            flush_windows(env);
    261            sparc64_set_context(env);
    262            break;
    263#endif
    264#endif
    265        case EXCP_INTERRUPT:
    266            /* just indicate that signals should be handled asap */
    267            break;
    268        case TT_ILL_INSN:
    269            {
    270                info.si_signo = TARGET_SIGILL;
    271                info.si_errno = 0;
    272                info.si_code = TARGET_ILL_ILLOPC;
    273                info._sifields._sigfault._addr = env->pc;
    274                queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
    275            }
    276            break;
    277        case EXCP_DEBUG:
    278            info.si_signo = TARGET_SIGTRAP;
    279            info.si_errno = 0;
    280            info.si_code = TARGET_TRAP_BRKPT;
    281            queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
    282            break;
    283        case EXCP_ATOMIC:
    284            cpu_exec_step_atomic(cs);
    285            break;
    286        default:
    287            fprintf(stderr, "Unhandled trap: 0x%x\n", trapnr);
    288            cpu_dump_state(cs, stderr, 0);
    289            exit(EXIT_FAILURE);
    290        }
    291        process_pending_signals (env);
    292    }
    293}
    294
    295void target_cpu_copy_regs(CPUArchState *env, struct target_pt_regs *regs)
    296{
    297    int i;
    298    env->pc = regs->pc;
    299    env->npc = regs->npc;
    300    env->y = regs->y;
    301    for(i = 0; i < 8; i++)
    302        env->gregs[i] = regs->u_regs[i];
    303    for(i = 0; i < 8; i++)
    304        env->regwptr[i] = regs->u_regs[i + 8];
    305}