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

fpu_helper.c (14669B)


      1/*
      2 *  Helpers for floating point instructions.
      3 *
      4 *  Copyright (c) 2007 Jocelyn Mayer
      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 "exec/helper-proto.h"
     24#include "fpu/softfloat.h"
     25
     26#define FP_STATUS (env->fp_status)
     27
     28
     29void helper_setroundmode(CPUAlphaState *env, uint32_t val)
     30{
     31    set_float_rounding_mode(val, &FP_STATUS);
     32}
     33
     34void helper_setflushzero(CPUAlphaState *env, uint32_t val)
     35{
     36    set_flush_to_zero(val, &FP_STATUS);
     37}
     38
     39#define CONVERT_BIT(X, SRC, DST) \
     40    (SRC > DST ? (X) / (SRC / DST) & (DST) : ((X) & SRC) * (DST / SRC))
     41
     42static uint32_t soft_to_fpcr_exc(CPUAlphaState *env)
     43{
     44    uint8_t exc = get_float_exception_flags(&FP_STATUS);
     45    uint32_t ret = 0;
     46
     47    if (unlikely(exc)) {
     48        set_float_exception_flags(0, &FP_STATUS);
     49        ret |= CONVERT_BIT(exc, float_flag_invalid, FPCR_INV);
     50        ret |= CONVERT_BIT(exc, float_flag_divbyzero, FPCR_DZE);
     51        ret |= CONVERT_BIT(exc, float_flag_overflow, FPCR_OVF);
     52        ret |= CONVERT_BIT(exc, float_flag_underflow, FPCR_UNF);
     53        ret |= CONVERT_BIT(exc, float_flag_inexact, FPCR_INE);
     54    }
     55
     56    return ret;
     57}
     58
     59static void fp_exc_raise1(CPUAlphaState *env, uintptr_t retaddr,
     60                          uint32_t exc, uint32_t regno, uint32_t hw_exc)
     61{
     62    hw_exc |= CONVERT_BIT(exc, FPCR_INV, EXC_M_INV);
     63    hw_exc |= CONVERT_BIT(exc, FPCR_DZE, EXC_M_DZE);
     64    hw_exc |= CONVERT_BIT(exc, FPCR_OVF, EXC_M_FOV);
     65    hw_exc |= CONVERT_BIT(exc, FPCR_UNF, EXC_M_UNF);
     66    hw_exc |= CONVERT_BIT(exc, FPCR_INE, EXC_M_INE);
     67    hw_exc |= CONVERT_BIT(exc, FPCR_IOV, EXC_M_IOV);
     68
     69    arith_excp(env, retaddr, hw_exc, 1ull << regno);
     70}
     71
     72/* Raise exceptions for ieee fp insns without software completion.
     73   In that case there are no exceptions that don't trap; the mask
     74   doesn't apply.  */
     75void helper_fp_exc_raise(CPUAlphaState *env, uint32_t ignore, uint32_t regno)
     76{
     77    uint32_t exc = env->error_code;
     78    if (exc) {
     79        env->fpcr |= exc;
     80        exc &= ~ignore;
     81        if (exc) {
     82            fp_exc_raise1(env, GETPC(), exc, regno, 0);
     83        }
     84    }
     85}
     86
     87/* Raise exceptions for ieee fp insns with software completion.  */
     88void helper_fp_exc_raise_s(CPUAlphaState *env, uint32_t ignore, uint32_t regno)
     89{
     90    uint32_t exc = env->error_code & ~ignore;
     91    if (exc) {
     92        env->fpcr |= exc;
     93        exc &= env->fpcr_exc_enable;
     94        /*
     95         * In system mode, the software handler gets invoked
     96         * for any non-ignored exception.
     97         * In user mode, the kernel's software handler only
     98         * delivers a signal if the exception is enabled.
     99         */
    100#ifdef CONFIG_USER_ONLY
    101        if (!exc) {
    102            return;
    103        }
    104#endif
    105        fp_exc_raise1(env, GETPC(), exc, regno, EXC_M_SWC);
    106    }
    107}
    108
    109/* Input handing without software completion.  Trap for all
    110   non-finite numbers.  */
    111void helper_ieee_input(CPUAlphaState *env, uint64_t val)
    112{
    113    uint32_t exp = (uint32_t)(val >> 52) & 0x7ff;
    114    uint64_t frac = val & 0xfffffffffffffull;
    115
    116    if (exp == 0) {
    117        /* Denormals without /S raise an exception.  */
    118        if (frac != 0) {
    119            arith_excp(env, GETPC(), EXC_M_INV, 0);
    120        }
    121    } else if (exp == 0x7ff) {
    122        /* Infinity or NaN.  */
    123        env->fpcr |= FPCR_INV;
    124        arith_excp(env, GETPC(), EXC_M_INV, 0);
    125    }
    126}
    127
    128/* Similar, but does not trap for infinities.  Used for comparisons.  */
    129void helper_ieee_input_cmp(CPUAlphaState *env, uint64_t val)
    130{
    131    uint32_t exp = (uint32_t)(val >> 52) & 0x7ff;
    132    uint64_t frac = val & 0xfffffffffffffull;
    133
    134    if (exp == 0) {
    135        /* Denormals without /S raise an exception.  */
    136        if (frac != 0) {
    137            arith_excp(env, GETPC(), EXC_M_INV, 0);
    138        }
    139    } else if (exp == 0x7ff && frac) {
    140        /* NaN.  */
    141        env->fpcr |= FPCR_INV;
    142        arith_excp(env, GETPC(), EXC_M_INV, 0);
    143    }
    144}
    145
    146/* Input handing with software completion.  Trap for denorms, unless DNZ
    147   is set.  If we try to support DNOD (which none of the produced hardware
    148   did, AFAICS), we'll need to suppress the trap when FPCR.DNOD is set;
    149   then the code downstream of that will need to cope with denorms sans
    150   flush_input_to_zero.  Most of it should work sanely, but there's
    151   nothing to compare with.  */
    152void helper_ieee_input_s(CPUAlphaState *env, uint64_t val)
    153{
    154    if (unlikely(2 * val - 1 < 0x1fffffffffffffull)
    155        && !env->fp_status.flush_inputs_to_zero) {
    156        arith_excp(env, GETPC(), EXC_M_INV | EXC_M_SWC, 0);
    157    }
    158}
    159
    160/* S floating (single) */
    161
    162/* Taken from linux/arch/alpha/kernel/traps.c, s_mem_to_reg.  */
    163static inline uint64_t float32_to_s_int(uint32_t fi)
    164{
    165    uint32_t frac = fi & 0x7fffff;
    166    uint32_t sign = fi >> 31;
    167    uint32_t exp_msb = (fi >> 30) & 1;
    168    uint32_t exp_low = (fi >> 23) & 0x7f;
    169    uint32_t exp;
    170
    171    exp = (exp_msb << 10) | exp_low;
    172    if (exp_msb) {
    173        if (exp_low == 0x7f) {
    174            exp = 0x7ff;
    175        }
    176    } else {
    177        if (exp_low != 0x00) {
    178            exp |= 0x380;
    179        }
    180    }
    181
    182    return (((uint64_t)sign << 63)
    183            | ((uint64_t)exp << 52)
    184            | ((uint64_t)frac << 29));
    185}
    186
    187static inline uint64_t float32_to_s(float32 fa)
    188{
    189    CPU_FloatU a;
    190    a.f = fa;
    191    return float32_to_s_int(a.l);
    192}
    193
    194static inline uint32_t s_to_float32_int(uint64_t a)
    195{
    196    return ((a >> 32) & 0xc0000000) | ((a >> 29) & 0x3fffffff);
    197}
    198
    199static inline float32 s_to_float32(uint64_t a)
    200{
    201    CPU_FloatU r;
    202    r.l = s_to_float32_int(a);
    203    return r.f;
    204}
    205
    206uint32_t helper_s_to_memory(uint64_t a)
    207{
    208    return s_to_float32_int(a);
    209}
    210
    211uint64_t helper_memory_to_s(uint32_t a)
    212{
    213    return float32_to_s_int(a);
    214}
    215
    216uint64_t helper_adds(CPUAlphaState *env, uint64_t a, uint64_t b)
    217{
    218    float32 fa, fb, fr;
    219
    220    fa = s_to_float32(a);
    221    fb = s_to_float32(b);
    222    fr = float32_add(fa, fb, &FP_STATUS);
    223    env->error_code = soft_to_fpcr_exc(env);
    224
    225    return float32_to_s(fr);
    226}
    227
    228uint64_t helper_subs(CPUAlphaState *env, uint64_t a, uint64_t b)
    229{
    230    float32 fa, fb, fr;
    231
    232    fa = s_to_float32(a);
    233    fb = s_to_float32(b);
    234    fr = float32_sub(fa, fb, &FP_STATUS);
    235    env->error_code = soft_to_fpcr_exc(env);
    236
    237    return float32_to_s(fr);
    238}
    239
    240uint64_t helper_muls(CPUAlphaState *env, uint64_t a, uint64_t b)
    241{
    242    float32 fa, fb, fr;
    243
    244    fa = s_to_float32(a);
    245    fb = s_to_float32(b);
    246    fr = float32_mul(fa, fb, &FP_STATUS);
    247    env->error_code = soft_to_fpcr_exc(env);
    248
    249    return float32_to_s(fr);
    250}
    251
    252uint64_t helper_divs(CPUAlphaState *env, uint64_t a, uint64_t b)
    253{
    254    float32 fa, fb, fr;
    255
    256    fa = s_to_float32(a);
    257    fb = s_to_float32(b);
    258    fr = float32_div(fa, fb, &FP_STATUS);
    259    env->error_code = soft_to_fpcr_exc(env);
    260
    261    return float32_to_s(fr);
    262}
    263
    264uint64_t helper_sqrts(CPUAlphaState *env, uint64_t a)
    265{
    266    float32 fa, fr;
    267
    268    fa = s_to_float32(a);
    269    fr = float32_sqrt(fa, &FP_STATUS);
    270    env->error_code = soft_to_fpcr_exc(env);
    271
    272    return float32_to_s(fr);
    273}
    274
    275
    276/* T floating (double) */
    277static inline float64 t_to_float64(uint64_t a)
    278{
    279    /* Memory format is the same as float64 */
    280    CPU_DoubleU r;
    281    r.ll = a;
    282    return r.d;
    283}
    284
    285static inline uint64_t float64_to_t(float64 fa)
    286{
    287    /* Memory format is the same as float64 */
    288    CPU_DoubleU r;
    289    r.d = fa;
    290    return r.ll;
    291}
    292
    293uint64_t helper_addt(CPUAlphaState *env, uint64_t a, uint64_t b)
    294{
    295    float64 fa, fb, fr;
    296
    297    fa = t_to_float64(a);
    298    fb = t_to_float64(b);
    299    fr = float64_add(fa, fb, &FP_STATUS);
    300    env->error_code = soft_to_fpcr_exc(env);
    301
    302    return float64_to_t(fr);
    303}
    304
    305uint64_t helper_subt(CPUAlphaState *env, uint64_t a, uint64_t b)
    306{
    307    float64 fa, fb, fr;
    308
    309    fa = t_to_float64(a);
    310    fb = t_to_float64(b);
    311    fr = float64_sub(fa, fb, &FP_STATUS);
    312    env->error_code = soft_to_fpcr_exc(env);
    313
    314    return float64_to_t(fr);
    315}
    316
    317uint64_t helper_mult(CPUAlphaState *env, uint64_t a, uint64_t b)
    318{
    319    float64 fa, fb, fr;
    320
    321    fa = t_to_float64(a);
    322    fb = t_to_float64(b);
    323    fr = float64_mul(fa, fb, &FP_STATUS);
    324    env->error_code = soft_to_fpcr_exc(env);
    325
    326    return float64_to_t(fr);
    327}
    328
    329uint64_t helper_divt(CPUAlphaState *env, uint64_t a, uint64_t b)
    330{
    331    float64 fa, fb, fr;
    332
    333    fa = t_to_float64(a);
    334    fb = t_to_float64(b);
    335    fr = float64_div(fa, fb, &FP_STATUS);
    336    env->error_code = soft_to_fpcr_exc(env);
    337
    338    return float64_to_t(fr);
    339}
    340
    341uint64_t helper_sqrtt(CPUAlphaState *env, uint64_t a)
    342{
    343    float64 fa, fr;
    344
    345    fa = t_to_float64(a);
    346    fr = float64_sqrt(fa, &FP_STATUS);
    347    env->error_code = soft_to_fpcr_exc(env);
    348
    349    return float64_to_t(fr);
    350}
    351
    352/* Comparisons */
    353uint64_t helper_cmptun(CPUAlphaState *env, uint64_t a, uint64_t b)
    354{
    355    float64 fa, fb;
    356    uint64_t ret = 0;
    357
    358    fa = t_to_float64(a);
    359    fb = t_to_float64(b);
    360
    361    if (float64_unordered_quiet(fa, fb, &FP_STATUS)) {
    362        ret = 0x4000000000000000ULL;
    363    }
    364    env->error_code = soft_to_fpcr_exc(env);
    365
    366    return ret;
    367}
    368
    369uint64_t helper_cmpteq(CPUAlphaState *env, uint64_t a, uint64_t b)
    370{
    371    float64 fa, fb;
    372    uint64_t ret = 0;
    373
    374    fa = t_to_float64(a);
    375    fb = t_to_float64(b);
    376
    377    if (float64_eq_quiet(fa, fb, &FP_STATUS)) {
    378        ret = 0x4000000000000000ULL;
    379    }
    380    env->error_code = soft_to_fpcr_exc(env);
    381
    382    return ret;
    383}
    384
    385uint64_t helper_cmptle(CPUAlphaState *env, uint64_t a, uint64_t b)
    386{
    387    float64 fa, fb;
    388    uint64_t ret = 0;
    389
    390    fa = t_to_float64(a);
    391    fb = t_to_float64(b);
    392
    393    if (float64_le(fa, fb, &FP_STATUS)) {
    394        ret = 0x4000000000000000ULL;
    395    }
    396    env->error_code = soft_to_fpcr_exc(env);
    397
    398    return ret;
    399}
    400
    401uint64_t helper_cmptlt(CPUAlphaState *env, uint64_t a, uint64_t b)
    402{
    403    float64 fa, fb;
    404    uint64_t ret = 0;
    405
    406    fa = t_to_float64(a);
    407    fb = t_to_float64(b);
    408
    409    if (float64_lt(fa, fb, &FP_STATUS)) {
    410        ret = 0x4000000000000000ULL;
    411    }
    412    env->error_code = soft_to_fpcr_exc(env);
    413
    414    return ret;
    415}
    416
    417/* Floating point format conversion */
    418uint64_t helper_cvtts(CPUAlphaState *env, uint64_t a)
    419{
    420    float64 fa;
    421    float32 fr;
    422
    423    fa = t_to_float64(a);
    424    fr = float64_to_float32(fa, &FP_STATUS);
    425    env->error_code = soft_to_fpcr_exc(env);
    426
    427    return float32_to_s(fr);
    428}
    429
    430uint64_t helper_cvtst(CPUAlphaState *env, uint64_t a)
    431{
    432    float32 fa;
    433    float64 fr;
    434
    435    fa = s_to_float32(a);
    436    fr = float32_to_float64(fa, &FP_STATUS);
    437    env->error_code = soft_to_fpcr_exc(env);
    438
    439    return float64_to_t(fr);
    440}
    441
    442uint64_t helper_cvtqs(CPUAlphaState *env, uint64_t a)
    443{
    444    float32 fr = int64_to_float32(a, &FP_STATUS);
    445    env->error_code = soft_to_fpcr_exc(env);
    446
    447    return float32_to_s(fr);
    448}
    449
    450/* Implement float64 to uint64_t conversion without saturation -- we must
    451   supply the truncated result.  This behaviour is used by the compiler
    452   to get unsigned conversion for free with the same instruction.  */
    453
    454static uint64_t do_cvttq(CPUAlphaState *env, uint64_t a, int roundmode)
    455{
    456    uint64_t frac, ret = 0;
    457    uint32_t exp, sign, exc = 0;
    458    int shift;
    459
    460    sign = (a >> 63);
    461    exp = (uint32_t)(a >> 52) & 0x7ff;
    462    frac = a & 0xfffffffffffffull;
    463
    464    if (exp == 0) {
    465        if (unlikely(frac != 0) && !env->fp_status.flush_inputs_to_zero) {
    466            goto do_underflow;
    467        }
    468    } else if (exp == 0x7ff) {
    469        exc = FPCR_INV;
    470    } else {
    471        /* Restore implicit bit.  */
    472        frac |= 0x10000000000000ull;
    473
    474        shift = exp - 1023 - 52;
    475        if (shift >= 0) {
    476            /* In this case the number is so large that we must shift
    477               the fraction left.  There is no rounding to do.  */
    478            if (shift < 64) {
    479                ret = frac << shift;
    480            }
    481            /* Check for overflow.  Note the special case of -0x1p63.  */
    482            if (shift >= 11 && a != 0xC3E0000000000000ull) {
    483                exc = FPCR_IOV | FPCR_INE;
    484            }
    485        } else {
    486            uint64_t round;
    487
    488            /* In this case the number is smaller than the fraction as
    489               represented by the 52 bit number.  Here we must think
    490               about rounding the result.  Handle this by shifting the
    491               fractional part of the number into the high bits of ROUND.
    492               This will let us efficiently handle round-to-nearest.  */
    493            shift = -shift;
    494            if (shift < 63) {
    495                ret = frac >> shift;
    496                round = frac << (64 - shift);
    497            } else {
    498                /* The exponent is so small we shift out everything.
    499                   Leave a sticky bit for proper rounding below.  */
    500            do_underflow:
    501                round = 1;
    502            }
    503
    504            if (round) {
    505                exc = FPCR_INE;
    506                switch (roundmode) {
    507                case float_round_nearest_even:
    508                    if (round == (1ull << 63)) {
    509                        /* Fraction is exactly 0.5; round to even.  */
    510                        ret += (ret & 1);
    511                    } else if (round > (1ull << 63)) {
    512                        ret += 1;
    513                    }
    514                    break;
    515                case float_round_to_zero:
    516                    break;
    517                case float_round_up:
    518                    ret += 1 - sign;
    519                    break;
    520                case float_round_down:
    521                    ret += sign;
    522                    break;
    523                }
    524            }
    525        }
    526        if (sign) {
    527            ret = -ret;
    528        }
    529    }
    530    env->error_code = exc;
    531
    532    return ret;
    533}
    534
    535uint64_t helper_cvttq(CPUAlphaState *env, uint64_t a)
    536{
    537    return do_cvttq(env, a, FP_STATUS.float_rounding_mode);
    538}
    539
    540uint64_t helper_cvttq_c(CPUAlphaState *env, uint64_t a)
    541{
    542    return do_cvttq(env, a, float_round_to_zero);
    543}
    544
    545uint64_t helper_cvtqt(CPUAlphaState *env, uint64_t a)
    546{
    547    float64 fr = int64_to_float64(a, &FP_STATUS);
    548    env->error_code = soft_to_fpcr_exc(env);
    549    return float64_to_t(fr);
    550}
    551
    552uint64_t helper_cvtql(CPUAlphaState *env, uint64_t val)
    553{
    554    uint32_t exc = 0;
    555    if (val != (int32_t)val) {
    556        exc = FPCR_IOV | FPCR_INE;
    557    }
    558    env->error_code = exc;
    559
    560    return ((val & 0xc0000000) << 32) | ((val & 0x3fffffff) << 29);
    561}