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

helper.c (6138B)


      1/*
      2 *  Misc Sparc helpers
      3 *
      4 *  Copyright (c) 2003-2005 Fabrice Bellard
      5 *
      6 * This library is free software; you can redistribute it and/or
      7 * modify it under the terms of the GNU Lesser General Public
      8 * License as published by the Free Software Foundation; either
      9 * version 2.1 of the License, or (at your option) any later version.
     10 *
     11 * This library 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 GNU
     14 * Lesser General Public License for more details.
     15 *
     16 * You should have received a copy of the GNU Lesser General Public
     17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
     18 */
     19
     20#include "qemu/osdep.h"
     21#include "cpu.h"
     22#include "exec/exec-all.h"
     23#include "qemu/host-utils.h"
     24#include "exec/helper-proto.h"
     25
     26void cpu_raise_exception_ra(CPUSPARCState *env, int tt, uintptr_t ra)
     27{
     28    CPUState *cs = env_cpu(env);
     29
     30    cs->exception_index = tt;
     31    cpu_loop_exit_restore(cs, ra);
     32}
     33
     34void helper_raise_exception(CPUSPARCState *env, int tt)
     35{
     36    CPUState *cs = env_cpu(env);
     37
     38    cs->exception_index = tt;
     39    cpu_loop_exit(cs);
     40}
     41
     42void helper_debug(CPUSPARCState *env)
     43{
     44    CPUState *cs = env_cpu(env);
     45
     46    cs->exception_index = EXCP_DEBUG;
     47    cpu_loop_exit(cs);
     48}
     49
     50#ifdef TARGET_SPARC64
     51void helper_tick_set_count(void *opaque, uint64_t count)
     52{
     53#if !defined(CONFIG_USER_ONLY)
     54    cpu_tick_set_count(opaque, count);
     55#endif
     56}
     57
     58uint64_t helper_tick_get_count(CPUSPARCState *env, void *opaque, int mem_idx)
     59{
     60#if !defined(CONFIG_USER_ONLY)
     61    CPUTimer *timer = opaque;
     62
     63    if (timer->npt && mem_idx < MMU_KERNEL_IDX) {
     64        cpu_raise_exception_ra(env, TT_PRIV_INSN, GETPC());
     65    }
     66
     67    return cpu_tick_get_count(timer);
     68#else
     69    /* In user-mode, QEMU_CLOCK_VIRTUAL doesn't exist.
     70       Just pass through the host cpu clock ticks.  */
     71    return cpu_get_host_ticks();
     72#endif
     73}
     74
     75void helper_tick_set_limit(void *opaque, uint64_t limit)
     76{
     77#if !defined(CONFIG_USER_ONLY)
     78    cpu_tick_set_limit(opaque, limit);
     79#endif
     80}
     81#endif
     82
     83static target_ulong do_udiv(CPUSPARCState *env, target_ulong a,
     84                            target_ulong b, int cc, uintptr_t ra)
     85{
     86    int overflow = 0;
     87    uint64_t x0;
     88    uint32_t x1;
     89
     90    x0 = (a & 0xffffffff) | ((int64_t) (env->y) << 32);
     91    x1 = (b & 0xffffffff);
     92
     93    if (x1 == 0) {
     94        cpu_raise_exception_ra(env, TT_DIV_ZERO, ra);
     95    }
     96
     97    x0 = x0 / x1;
     98    if (x0 > UINT32_MAX) {
     99        x0 = UINT32_MAX;
    100        overflow = 1;
    101    }
    102
    103    if (cc) {
    104        env->cc_dst = x0;
    105        env->cc_src2 = overflow;
    106        env->cc_op = CC_OP_DIV;
    107    }
    108    return x0;
    109}
    110
    111target_ulong helper_udiv(CPUSPARCState *env, target_ulong a, target_ulong b)
    112{
    113    return do_udiv(env, a, b, 0, GETPC());
    114}
    115
    116target_ulong helper_udiv_cc(CPUSPARCState *env, target_ulong a, target_ulong b)
    117{
    118    return do_udiv(env, a, b, 1, GETPC());
    119}
    120
    121static target_ulong do_sdiv(CPUSPARCState *env, target_ulong a,
    122                            target_ulong b, int cc, uintptr_t ra)
    123{
    124    int overflow = 0;
    125    int64_t x0;
    126    int32_t x1;
    127
    128    x0 = (a & 0xffffffff) | ((int64_t) (env->y) << 32);
    129    x1 = (b & 0xffffffff);
    130
    131    if (x1 == 0) {
    132        cpu_raise_exception_ra(env, TT_DIV_ZERO, ra);
    133    } else if (x1 == -1 && x0 == INT64_MIN) {
    134        x0 = INT32_MAX;
    135        overflow = 1;
    136    } else {
    137        x0 = x0 / x1;
    138        if ((int32_t) x0 != x0) {
    139            x0 = x0 < 0 ? INT32_MIN : INT32_MAX;
    140            overflow = 1;
    141        }
    142    }
    143
    144    if (cc) {
    145        env->cc_dst = x0;
    146        env->cc_src2 = overflow;
    147        env->cc_op = CC_OP_DIV;
    148    }
    149    return x0;
    150}
    151
    152target_ulong helper_sdiv(CPUSPARCState *env, target_ulong a, target_ulong b)
    153{
    154    return do_sdiv(env, a, b, 0, GETPC());
    155}
    156
    157target_ulong helper_sdiv_cc(CPUSPARCState *env, target_ulong a, target_ulong b)
    158{
    159    return do_sdiv(env, a, b, 1, GETPC());
    160}
    161
    162#ifdef TARGET_SPARC64
    163int64_t helper_sdivx(CPUSPARCState *env, int64_t a, int64_t b)
    164{
    165    if (b == 0) {
    166        /* Raise divide by zero trap.  */
    167        cpu_raise_exception_ra(env, TT_DIV_ZERO, GETPC());
    168    } else if (b == -1) {
    169        /* Avoid overflow trap with i386 divide insn.  */
    170        return -a;
    171    } else {
    172        return a / b;
    173    }
    174}
    175
    176uint64_t helper_udivx(CPUSPARCState *env, uint64_t a, uint64_t b)
    177{
    178    if (b == 0) {
    179        /* Raise divide by zero trap.  */
    180        cpu_raise_exception_ra(env, TT_DIV_ZERO, GETPC());
    181    }
    182    return a / b;
    183}
    184#endif
    185
    186target_ulong helper_taddcctv(CPUSPARCState *env, target_ulong src1,
    187                             target_ulong src2)
    188{
    189    target_ulong dst;
    190
    191    /* Tag overflow occurs if either input has bits 0 or 1 set.  */
    192    if ((src1 | src2) & 3) {
    193        goto tag_overflow;
    194    }
    195
    196    dst = src1 + src2;
    197
    198    /* Tag overflow occurs if the addition overflows.  */
    199    if (~(src1 ^ src2) & (src1 ^ dst) & (1u << 31)) {
    200        goto tag_overflow;
    201    }
    202
    203    /* Only modify the CC after any exceptions have been generated.  */
    204    env->cc_op = CC_OP_TADDTV;
    205    env->cc_src = src1;
    206    env->cc_src2 = src2;
    207    env->cc_dst = dst;
    208    return dst;
    209
    210 tag_overflow:
    211    cpu_raise_exception_ra(env, TT_TOVF, GETPC());
    212}
    213
    214target_ulong helper_tsubcctv(CPUSPARCState *env, target_ulong src1,
    215                             target_ulong src2)
    216{
    217    target_ulong dst;
    218
    219    /* Tag overflow occurs if either input has bits 0 or 1 set.  */
    220    if ((src1 | src2) & 3) {
    221        goto tag_overflow;
    222    }
    223
    224    dst = src1 - src2;
    225
    226    /* Tag overflow occurs if the subtraction overflows.  */
    227    if ((src1 ^ src2) & (src1 ^ dst) & (1u << 31)) {
    228        goto tag_overflow;
    229    }
    230
    231    /* Only modify the CC after any exceptions have been generated.  */
    232    env->cc_op = CC_OP_TSUBTV;
    233    env->cc_src = src1;
    234    env->cc_src2 = src2;
    235    env->cc_dst = dst;
    236    return dst;
    237
    238 tag_overflow:
    239    cpu_raise_exception_ra(env, TT_TOVF, GETPC());
    240}
    241
    242#ifndef TARGET_SPARC64
    243void helper_power_down(CPUSPARCState *env)
    244{
    245    CPUState *cs = env_cpu(env);
    246
    247    cs->halted = 1;
    248    cs->exception_index = EXCP_HLT;
    249    env->pc = env->npc;
    250    env->npc = env->pc + 4;
    251    cpu_loop_exit(cs);
    252}
    253#endif