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 (13398B)


      1/*
      2 * Copyright (c) 2011 - 2019, Max Filippov, Open Source and Linux Lab.
      3 * All rights reserved.
      4 *
      5 * Redistribution and use in source and binary forms, with or without
      6 * modification, are permitted provided that the following conditions are met:
      7 *     * Redistributions of source code must retain the above copyright
      8 *       notice, this list of conditions and the following disclaimer.
      9 *     * Redistributions in binary form must reproduce the above copyright
     10 *       notice, this list of conditions and the following disclaimer in the
     11 *       documentation and/or other materials provided with the distribution.
     12 *     * Neither the name of the Open Source and Linux Lab nor the
     13 *       names of its contributors may be used to endorse or promote products
     14 *       derived from this software without specific prior written permission.
     15 *
     16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
     17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
     20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
     23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
     25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     26 */
     27
     28#include "qemu/osdep.h"
     29#include "qemu/main-loop.h"
     30#include "cpu.h"
     31#include "exec/helper-proto.h"
     32#include "qemu/host-utils.h"
     33#include "exec/exec-all.h"
     34#include "fpu/softfloat.h"
     35
     36enum {
     37    XTENSA_FP_I = 0x1,
     38    XTENSA_FP_U = 0x2,
     39    XTENSA_FP_O = 0x4,
     40    XTENSA_FP_Z = 0x8,
     41    XTENSA_FP_V = 0x10,
     42};
     43
     44enum {
     45    XTENSA_FCR_FLAGS_SHIFT = 2,
     46    XTENSA_FSR_FLAGS_SHIFT = 7,
     47};
     48
     49static const struct {
     50    uint32_t xtensa_fp_flag;
     51    int softfloat_fp_flag;
     52} xtensa_fp_flag_map[] = {
     53    { XTENSA_FP_I, float_flag_inexact, },
     54    { XTENSA_FP_U, float_flag_underflow, },
     55    { XTENSA_FP_O, float_flag_overflow, },
     56    { XTENSA_FP_Z, float_flag_divbyzero, },
     57    { XTENSA_FP_V, float_flag_invalid, },
     58};
     59
     60void HELPER(wur_fpu2k_fcr)(CPUXtensaState *env, uint32_t v)
     61{
     62    static const int rounding_mode[] = {
     63        float_round_nearest_even,
     64        float_round_to_zero,
     65        float_round_up,
     66        float_round_down,
     67    };
     68
     69    env->uregs[FCR] = v & 0xfffff07f;
     70    set_float_rounding_mode(rounding_mode[v & 3], &env->fp_status);
     71}
     72
     73void HELPER(wur_fpu_fcr)(CPUXtensaState *env, uint32_t v)
     74{
     75    static const int rounding_mode[] = {
     76        float_round_nearest_even,
     77        float_round_to_zero,
     78        float_round_up,
     79        float_round_down,
     80    };
     81
     82    if (v & 0xfffff000) {
     83        qemu_log_mask(LOG_GUEST_ERROR,
     84                      "MBZ field of FCR is written non-zero: %08x\n", v);
     85    }
     86    env->uregs[FCR] = v & 0x0000007f;
     87    set_float_rounding_mode(rounding_mode[v & 3], &env->fp_status);
     88}
     89
     90void HELPER(wur_fpu_fsr)(CPUXtensaState *env, uint32_t v)
     91{
     92    uint32_t flags = v >> XTENSA_FSR_FLAGS_SHIFT;
     93    int fef = 0;
     94    unsigned i;
     95
     96    if (v & 0xfffff000) {
     97        qemu_log_mask(LOG_GUEST_ERROR,
     98                      "MBZ field of FSR is written non-zero: %08x\n", v);
     99    }
    100    env->uregs[FSR] = v & 0x00000f80;
    101    for (i = 0; i < ARRAY_SIZE(xtensa_fp_flag_map); ++i) {
    102        if (flags & xtensa_fp_flag_map[i].xtensa_fp_flag) {
    103            fef |= xtensa_fp_flag_map[i].softfloat_fp_flag;
    104        }
    105    }
    106    set_float_exception_flags(fef, &env->fp_status);
    107}
    108
    109uint32_t HELPER(rur_fpu_fsr)(CPUXtensaState *env)
    110{
    111    uint32_t flags = 0;
    112    int fef = get_float_exception_flags(&env->fp_status);
    113    unsigned i;
    114
    115    for (i = 0; i < ARRAY_SIZE(xtensa_fp_flag_map); ++i) {
    116        if (fef & xtensa_fp_flag_map[i].softfloat_fp_flag) {
    117            flags |= xtensa_fp_flag_map[i].xtensa_fp_flag;
    118        }
    119    }
    120    env->uregs[FSR] = flags << XTENSA_FSR_FLAGS_SHIFT;
    121    return flags << XTENSA_FSR_FLAGS_SHIFT;
    122}
    123
    124float64 HELPER(abs_d)(float64 v)
    125{
    126    return float64_abs(v);
    127}
    128
    129float32 HELPER(abs_s)(float32 v)
    130{
    131    return float32_abs(v);
    132}
    133
    134float64 HELPER(neg_d)(float64 v)
    135{
    136    return float64_chs(v);
    137}
    138
    139float32 HELPER(neg_s)(float32 v)
    140{
    141    return float32_chs(v);
    142}
    143
    144float32 HELPER(fpu2k_add_s)(CPUXtensaState *env, float32 a, float32 b)
    145{
    146    return float32_add(a, b, &env->fp_status);
    147}
    148
    149float32 HELPER(fpu2k_sub_s)(CPUXtensaState *env, float32 a, float32 b)
    150{
    151    return float32_sub(a, b, &env->fp_status);
    152}
    153
    154float32 HELPER(fpu2k_mul_s)(CPUXtensaState *env, float32 a, float32 b)
    155{
    156    return float32_mul(a, b, &env->fp_status);
    157}
    158
    159float32 HELPER(fpu2k_madd_s)(CPUXtensaState *env,
    160                             float32 a, float32 b, float32 c)
    161{
    162    return float32_muladd(b, c, a, 0, &env->fp_status);
    163}
    164
    165float32 HELPER(fpu2k_msub_s)(CPUXtensaState *env,
    166                             float32 a, float32 b, float32 c)
    167{
    168    return float32_muladd(b, c, a, float_muladd_negate_product,
    169                          &env->fp_status);
    170}
    171
    172float64 HELPER(add_d)(CPUXtensaState *env, float64 a, float64 b)
    173{
    174    set_use_first_nan(true, &env->fp_status);
    175    return float64_add(a, b, &env->fp_status);
    176}
    177
    178float32 HELPER(add_s)(CPUXtensaState *env, float32 a, float32 b)
    179{
    180    set_use_first_nan(env->config->use_first_nan, &env->fp_status);
    181    return float32_add(a, b, &env->fp_status);
    182}
    183
    184float64 HELPER(sub_d)(CPUXtensaState *env, float64 a, float64 b)
    185{
    186    set_use_first_nan(true, &env->fp_status);
    187    return float64_sub(a, b, &env->fp_status);
    188}
    189
    190float32 HELPER(sub_s)(CPUXtensaState *env, float32 a, float32 b)
    191{
    192    set_use_first_nan(env->config->use_first_nan, &env->fp_status);
    193    return float32_sub(a, b, &env->fp_status);
    194}
    195
    196float64 HELPER(mul_d)(CPUXtensaState *env, float64 a, float64 b)
    197{
    198    set_use_first_nan(true, &env->fp_status);
    199    return float64_mul(a, b, &env->fp_status);
    200}
    201
    202float32 HELPER(mul_s)(CPUXtensaState *env, float32 a, float32 b)
    203{
    204    set_use_first_nan(env->config->use_first_nan, &env->fp_status);
    205    return float32_mul(a, b, &env->fp_status);
    206}
    207
    208float64 HELPER(madd_d)(CPUXtensaState *env, float64 a, float64 b, float64 c)
    209{
    210    set_use_first_nan(env->config->use_first_nan, &env->fp_status);
    211    return float64_muladd(b, c, a, 0, &env->fp_status);
    212}
    213
    214float32 HELPER(madd_s)(CPUXtensaState *env, float32 a, float32 b, float32 c)
    215{
    216    set_use_first_nan(env->config->use_first_nan, &env->fp_status);
    217    return float32_muladd(b, c, a, 0, &env->fp_status);
    218}
    219
    220float64 HELPER(msub_d)(CPUXtensaState *env, float64 a, float64 b, float64 c)
    221{
    222    set_use_first_nan(env->config->use_first_nan, &env->fp_status);
    223    return float64_muladd(b, c, a, float_muladd_negate_product,
    224                          &env->fp_status);
    225}
    226
    227float32 HELPER(msub_s)(CPUXtensaState *env, float32 a, float32 b, float32 c)
    228{
    229    set_use_first_nan(env->config->use_first_nan, &env->fp_status);
    230    return float32_muladd(b, c, a, float_muladd_negate_product,
    231                          &env->fp_status);
    232}
    233
    234float64 HELPER(mkdadj_d)(CPUXtensaState *env, float64 a, float64 b)
    235{
    236    set_use_first_nan(true, &env->fp_status);
    237    return float64_div(b, a, &env->fp_status);
    238}
    239
    240float32 HELPER(mkdadj_s)(CPUXtensaState *env, float32 a, float32 b)
    241{
    242    set_use_first_nan(env->config->use_first_nan, &env->fp_status);
    243    return float32_div(b, a, &env->fp_status);
    244}
    245
    246float64 HELPER(mksadj_d)(CPUXtensaState *env, float64 v)
    247{
    248    set_use_first_nan(true, &env->fp_status);
    249    return float64_sqrt(v, &env->fp_status);
    250}
    251
    252float32 HELPER(mksadj_s)(CPUXtensaState *env, float32 v)
    253{
    254    set_use_first_nan(env->config->use_first_nan, &env->fp_status);
    255    return float32_sqrt(v, &env->fp_status);
    256}
    257
    258uint32_t HELPER(ftoi_d)(CPUXtensaState *env, float64 v,
    259                        uint32_t rounding_mode, uint32_t scale)
    260{
    261    float_status fp_status = env->fp_status;
    262    uint32_t res;
    263
    264    set_float_rounding_mode(rounding_mode, &fp_status);
    265    res = float64_to_int32(float64_scalbn(v, scale, &fp_status), &fp_status);
    266    set_float_exception_flags(get_float_exception_flags(&fp_status),
    267                              &env->fp_status);
    268    return res;
    269}
    270
    271uint32_t HELPER(ftoi_s)(CPUXtensaState *env, float32 v,
    272                        uint32_t rounding_mode, uint32_t scale)
    273{
    274    float_status fp_status = env->fp_status;
    275    uint32_t res;
    276
    277    set_float_rounding_mode(rounding_mode, &fp_status);
    278    res = float32_to_int32(float32_scalbn(v, scale, &fp_status), &fp_status);
    279    set_float_exception_flags(get_float_exception_flags(&fp_status),
    280                              &env->fp_status);
    281    return res;
    282}
    283
    284uint32_t HELPER(ftoui_d)(CPUXtensaState *env, float64 v,
    285                         uint32_t rounding_mode, uint32_t scale)
    286{
    287    float_status fp_status = env->fp_status;
    288    float64 res;
    289    uint32_t rv;
    290
    291    set_float_rounding_mode(rounding_mode, &fp_status);
    292
    293    res = float64_scalbn(v, scale, &fp_status);
    294
    295    if (float64_is_neg(v) && !float64_is_any_nan(v)) {
    296        set_float_exception_flags(float_flag_invalid, &fp_status);
    297        rv = float64_to_int32(res, &fp_status);
    298    } else {
    299        rv = float64_to_uint32(res, &fp_status);
    300    }
    301    set_float_exception_flags(get_float_exception_flags(&fp_status),
    302                              &env->fp_status);
    303    return rv;
    304}
    305
    306uint32_t HELPER(ftoui_s)(CPUXtensaState *env, float32 v,
    307                         uint32_t rounding_mode, uint32_t scale)
    308{
    309    float_status fp_status = env->fp_status;
    310    float32 res;
    311    uint32_t rv;
    312
    313    set_float_rounding_mode(rounding_mode, &fp_status);
    314
    315    res = float32_scalbn(v, scale, &fp_status);
    316
    317    if (float32_is_neg(v) && !float32_is_any_nan(v)) {
    318        rv = float32_to_int32(res, &fp_status);
    319        if (rv) {
    320            set_float_exception_flags(float_flag_invalid, &fp_status);
    321        }
    322    } else {
    323        rv = float32_to_uint32(res, &fp_status);
    324    }
    325    set_float_exception_flags(get_float_exception_flags(&fp_status),
    326                              &env->fp_status);
    327    return rv;
    328}
    329
    330float64 HELPER(itof_d)(CPUXtensaState *env, uint32_t v, uint32_t scale)
    331{
    332    return float64_scalbn(int32_to_float64(v, &env->fp_status),
    333                          (int32_t)scale, &env->fp_status);
    334}
    335
    336float32 HELPER(itof_s)(CPUXtensaState *env, uint32_t v, uint32_t scale)
    337{
    338    return float32_scalbn(int32_to_float32(v, &env->fp_status),
    339                          (int32_t)scale, &env->fp_status);
    340}
    341
    342float64 HELPER(uitof_d)(CPUXtensaState *env, uint32_t v, uint32_t scale)
    343{
    344    return float64_scalbn(uint32_to_float64(v, &env->fp_status),
    345                          (int32_t)scale, &env->fp_status);
    346}
    347
    348float32 HELPER(uitof_s)(CPUXtensaState *env, uint32_t v, uint32_t scale)
    349{
    350    return float32_scalbn(uint32_to_float32(v, &env->fp_status),
    351                          (int32_t)scale, &env->fp_status);
    352}
    353
    354float64 HELPER(cvtd_s)(CPUXtensaState *env, float32 v)
    355{
    356    return float32_to_float64(v, &env->fp_status);
    357}
    358
    359float32 HELPER(cvts_d)(CPUXtensaState *env, float64 v)
    360{
    361    return float64_to_float32(v, &env->fp_status);
    362}
    363
    364uint32_t HELPER(un_d)(CPUXtensaState *env, float64 a, float64 b)
    365{
    366    return float64_unordered_quiet(a, b, &env->fp_status);
    367}
    368
    369uint32_t HELPER(un_s)(CPUXtensaState *env, float32 a, float32 b)
    370{
    371    return float32_unordered_quiet(a, b, &env->fp_status);
    372}
    373
    374uint32_t HELPER(oeq_d)(CPUXtensaState *env, float64 a, float64 b)
    375{
    376    return float64_eq_quiet(a, b, &env->fp_status);
    377}
    378
    379uint32_t HELPER(oeq_s)(CPUXtensaState *env, float32 a, float32 b)
    380{
    381    return float32_eq_quiet(a, b, &env->fp_status);
    382}
    383
    384uint32_t HELPER(ueq_d)(CPUXtensaState *env, float64 a, float64 b)
    385{
    386    FloatRelation v = float64_compare_quiet(a, b, &env->fp_status);
    387
    388    return v == float_relation_equal ||
    389           v == float_relation_unordered;
    390}
    391
    392uint32_t HELPER(ueq_s)(CPUXtensaState *env, float32 a, float32 b)
    393{
    394    FloatRelation v = float32_compare_quiet(a, b, &env->fp_status);
    395
    396    return v == float_relation_equal ||
    397           v == float_relation_unordered;
    398}
    399
    400uint32_t HELPER(olt_d)(CPUXtensaState *env, float64 a, float64 b)
    401{
    402    return float64_lt(a, b, &env->fp_status);
    403}
    404
    405uint32_t HELPER(olt_s)(CPUXtensaState *env, float32 a, float32 b)
    406{
    407    return float32_lt(a, b, &env->fp_status);
    408}
    409
    410uint32_t HELPER(ult_d)(CPUXtensaState *env, float64 a, float64 b)
    411{
    412    FloatRelation v = float64_compare_quiet(a, b, &env->fp_status);
    413
    414    return v == float_relation_less ||
    415           v == float_relation_unordered;
    416}
    417
    418uint32_t HELPER(ult_s)(CPUXtensaState *env, float32 a, float32 b)
    419{
    420    FloatRelation v = float32_compare_quiet(a, b, &env->fp_status);
    421
    422    return v == float_relation_less ||
    423           v == float_relation_unordered;
    424}
    425
    426uint32_t HELPER(ole_d)(CPUXtensaState *env, float64 a, float64 b)
    427{
    428    return float64_le(a, b, &env->fp_status);
    429}
    430
    431uint32_t HELPER(ole_s)(CPUXtensaState *env, float32 a, float32 b)
    432{
    433    return float32_le(a, b, &env->fp_status);
    434}
    435
    436uint32_t HELPER(ule_d)(CPUXtensaState *env, float64 a, float64 b)
    437{
    438    FloatRelation v = float64_compare_quiet(a, b, &env->fp_status);
    439
    440    return v != float_relation_greater;
    441}
    442
    443uint32_t HELPER(ule_s)(CPUXtensaState *env, float32 a, float32 b)
    444{
    445    FloatRelation v = float32_compare_quiet(a, b, &env->fp_status);
    446
    447    return v != float_relation_greater;
    448}