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

int_helper.c (11761B)


      1/*
      2 *  x86 integer helpers
      3 *
      4 *  Copyright (c) 2003 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#include "qapi/error.h"
     26#include "qemu/guest-random.h"
     27#include "helper-tcg.h"
     28
     29//#define DEBUG_MULDIV
     30
     31/* modulo 9 table */
     32static const uint8_t rclb_table[32] = {
     33    0, 1, 2, 3, 4, 5, 6, 7,
     34    8, 0, 1, 2, 3, 4, 5, 6,
     35    7, 8, 0, 1, 2, 3, 4, 5,
     36    6, 7, 8, 0, 1, 2, 3, 4,
     37};
     38
     39/* modulo 17 table */
     40static const uint8_t rclw_table[32] = {
     41    0, 1, 2, 3, 4, 5, 6, 7,
     42    8, 9, 10, 11, 12, 13, 14, 15,
     43    16, 0, 1, 2, 3, 4, 5, 6,
     44    7, 8, 9, 10, 11, 12, 13, 14,
     45};
     46
     47/* division, flags are undefined */
     48
     49void helper_divb_AL(CPUX86State *env, target_ulong t0)
     50{
     51    unsigned int num, den, q, r;
     52
     53    num = (env->regs[R_EAX] & 0xffff);
     54    den = (t0 & 0xff);
     55    if (den == 0) {
     56        raise_exception_ra(env, EXCP00_DIVZ, GETPC());
     57    }
     58    q = (num / den);
     59    if (q > 0xff) {
     60        raise_exception_ra(env, EXCP00_DIVZ, GETPC());
     61    }
     62    q &= 0xff;
     63    r = (num % den) & 0xff;
     64    env->regs[R_EAX] = (env->regs[R_EAX] & ~0xffff) | (r << 8) | q;
     65}
     66
     67void helper_idivb_AL(CPUX86State *env, target_ulong t0)
     68{
     69    int num, den, q, r;
     70
     71    num = (int16_t)env->regs[R_EAX];
     72    den = (int8_t)t0;
     73    if (den == 0) {
     74        raise_exception_ra(env, EXCP00_DIVZ, GETPC());
     75    }
     76    q = (num / den);
     77    if (q != (int8_t)q) {
     78        raise_exception_ra(env, EXCP00_DIVZ, GETPC());
     79    }
     80    q &= 0xff;
     81    r = (num % den) & 0xff;
     82    env->regs[R_EAX] = (env->regs[R_EAX] & ~0xffff) | (r << 8) | q;
     83}
     84
     85void helper_divw_AX(CPUX86State *env, target_ulong t0)
     86{
     87    unsigned int num, den, q, r;
     88
     89    num = (env->regs[R_EAX] & 0xffff) | ((env->regs[R_EDX] & 0xffff) << 16);
     90    den = (t0 & 0xffff);
     91    if (den == 0) {
     92        raise_exception_ra(env, EXCP00_DIVZ, GETPC());
     93    }
     94    q = (num / den);
     95    if (q > 0xffff) {
     96        raise_exception_ra(env, EXCP00_DIVZ, GETPC());
     97    }
     98    q &= 0xffff;
     99    r = (num % den) & 0xffff;
    100    env->regs[R_EAX] = (env->regs[R_EAX] & ~0xffff) | q;
    101    env->regs[R_EDX] = (env->regs[R_EDX] & ~0xffff) | r;
    102}
    103
    104void helper_idivw_AX(CPUX86State *env, target_ulong t0)
    105{
    106    int num, den, q, r;
    107
    108    num = (env->regs[R_EAX] & 0xffff) | ((env->regs[R_EDX] & 0xffff) << 16);
    109    den = (int16_t)t0;
    110    if (den == 0) {
    111        raise_exception_ra(env, EXCP00_DIVZ, GETPC());
    112    }
    113    q = (num / den);
    114    if (q != (int16_t)q) {
    115        raise_exception_ra(env, EXCP00_DIVZ, GETPC());
    116    }
    117    q &= 0xffff;
    118    r = (num % den) & 0xffff;
    119    env->regs[R_EAX] = (env->regs[R_EAX] & ~0xffff) | q;
    120    env->regs[R_EDX] = (env->regs[R_EDX] & ~0xffff) | r;
    121}
    122
    123void helper_divl_EAX(CPUX86State *env, target_ulong t0)
    124{
    125    unsigned int den, r;
    126    uint64_t num, q;
    127
    128    num = ((uint32_t)env->regs[R_EAX]) | ((uint64_t)((uint32_t)env->regs[R_EDX]) << 32);
    129    den = t0;
    130    if (den == 0) {
    131        raise_exception_ra(env, EXCP00_DIVZ, GETPC());
    132    }
    133    q = (num / den);
    134    r = (num % den);
    135    if (q > 0xffffffff) {
    136        raise_exception_ra(env, EXCP00_DIVZ, GETPC());
    137    }
    138    env->regs[R_EAX] = (uint32_t)q;
    139    env->regs[R_EDX] = (uint32_t)r;
    140}
    141
    142void helper_idivl_EAX(CPUX86State *env, target_ulong t0)
    143{
    144    int den, r;
    145    int64_t num, q;
    146
    147    num = ((uint32_t)env->regs[R_EAX]) | ((uint64_t)((uint32_t)env->regs[R_EDX]) << 32);
    148    den = t0;
    149    if (den == 0) {
    150        raise_exception_ra(env, EXCP00_DIVZ, GETPC());
    151    }
    152    q = (num / den);
    153    r = (num % den);
    154    if (q != (int32_t)q) {
    155        raise_exception_ra(env, EXCP00_DIVZ, GETPC());
    156    }
    157    env->regs[R_EAX] = (uint32_t)q;
    158    env->regs[R_EDX] = (uint32_t)r;
    159}
    160
    161/* bcd */
    162
    163/* XXX: exception */
    164void helper_aam(CPUX86State *env, int base)
    165{
    166    int al, ah;
    167
    168    al = env->regs[R_EAX] & 0xff;
    169    ah = al / base;
    170    al = al % base;
    171    env->regs[R_EAX] = (env->regs[R_EAX] & ~0xffff) | al | (ah << 8);
    172    CC_DST = al;
    173}
    174
    175void helper_aad(CPUX86State *env, int base)
    176{
    177    int al, ah;
    178
    179    al = env->regs[R_EAX] & 0xff;
    180    ah = (env->regs[R_EAX] >> 8) & 0xff;
    181    al = ((ah * base) + al) & 0xff;
    182    env->regs[R_EAX] = (env->regs[R_EAX] & ~0xffff) | al;
    183    CC_DST = al;
    184}
    185
    186void helper_aaa(CPUX86State *env)
    187{
    188    int icarry;
    189    int al, ah, af;
    190    int eflags;
    191
    192    eflags = cpu_cc_compute_all(env, CC_OP);
    193    af = eflags & CC_A;
    194    al = env->regs[R_EAX] & 0xff;
    195    ah = (env->regs[R_EAX] >> 8) & 0xff;
    196
    197    icarry = (al > 0xf9);
    198    if (((al & 0x0f) > 9) || af) {
    199        al = (al + 6) & 0x0f;
    200        ah = (ah + 1 + icarry) & 0xff;
    201        eflags |= CC_C | CC_A;
    202    } else {
    203        eflags &= ~(CC_C | CC_A);
    204        al &= 0x0f;
    205    }
    206    env->regs[R_EAX] = (env->regs[R_EAX] & ~0xffff) | al | (ah << 8);
    207    CC_SRC = eflags;
    208}
    209
    210void helper_aas(CPUX86State *env)
    211{
    212    int icarry;
    213    int al, ah, af;
    214    int eflags;
    215
    216    eflags = cpu_cc_compute_all(env, CC_OP);
    217    af = eflags & CC_A;
    218    al = env->regs[R_EAX] & 0xff;
    219    ah = (env->regs[R_EAX] >> 8) & 0xff;
    220
    221    icarry = (al < 6);
    222    if (((al & 0x0f) > 9) || af) {
    223        al = (al - 6) & 0x0f;
    224        ah = (ah - 1 - icarry) & 0xff;
    225        eflags |= CC_C | CC_A;
    226    } else {
    227        eflags &= ~(CC_C | CC_A);
    228        al &= 0x0f;
    229    }
    230    env->regs[R_EAX] = (env->regs[R_EAX] & ~0xffff) | al | (ah << 8);
    231    CC_SRC = eflags;
    232}
    233
    234void helper_daa(CPUX86State *env)
    235{
    236    int old_al, al, af, cf;
    237    int eflags;
    238
    239    eflags = cpu_cc_compute_all(env, CC_OP);
    240    cf = eflags & CC_C;
    241    af = eflags & CC_A;
    242    old_al = al = env->regs[R_EAX] & 0xff;
    243
    244    eflags = 0;
    245    if (((al & 0x0f) > 9) || af) {
    246        al = (al + 6) & 0xff;
    247        eflags |= CC_A;
    248    }
    249    if ((old_al > 0x99) || cf) {
    250        al = (al + 0x60) & 0xff;
    251        eflags |= CC_C;
    252    }
    253    env->regs[R_EAX] = (env->regs[R_EAX] & ~0xff) | al;
    254    /* well, speed is not an issue here, so we compute the flags by hand */
    255    eflags |= (al == 0) << 6; /* zf */
    256    eflags |= parity_table[al]; /* pf */
    257    eflags |= (al & 0x80); /* sf */
    258    CC_SRC = eflags;
    259}
    260
    261void helper_das(CPUX86State *env)
    262{
    263    int al, al1, af, cf;
    264    int eflags;
    265
    266    eflags = cpu_cc_compute_all(env, CC_OP);
    267    cf = eflags & CC_C;
    268    af = eflags & CC_A;
    269    al = env->regs[R_EAX] & 0xff;
    270
    271    eflags = 0;
    272    al1 = al;
    273    if (((al & 0x0f) > 9) || af) {
    274        eflags |= CC_A;
    275        if (al < 6 || cf) {
    276            eflags |= CC_C;
    277        }
    278        al = (al - 6) & 0xff;
    279    }
    280    if ((al1 > 0x99) || cf) {
    281        al = (al - 0x60) & 0xff;
    282        eflags |= CC_C;
    283    }
    284    env->regs[R_EAX] = (env->regs[R_EAX] & ~0xff) | al;
    285    /* well, speed is not an issue here, so we compute the flags by hand */
    286    eflags |= (al == 0) << 6; /* zf */
    287    eflags |= parity_table[al]; /* pf */
    288    eflags |= (al & 0x80); /* sf */
    289    CC_SRC = eflags;
    290}
    291
    292#ifdef TARGET_X86_64
    293static void add128(uint64_t *plow, uint64_t *phigh, uint64_t a, uint64_t b)
    294{
    295    *plow += a;
    296    /* carry test */
    297    if (*plow < a) {
    298        (*phigh)++;
    299    }
    300    *phigh += b;
    301}
    302
    303static void neg128(uint64_t *plow, uint64_t *phigh)
    304{
    305    *plow = ~*plow;
    306    *phigh = ~*phigh;
    307    add128(plow, phigh, 1, 0);
    308}
    309
    310/* return TRUE if overflow */
    311static int div64(uint64_t *plow, uint64_t *phigh, uint64_t b)
    312{
    313    uint64_t q, r, a1, a0;
    314    int i, qb, ab;
    315
    316    a0 = *plow;
    317    a1 = *phigh;
    318    if (a1 == 0) {
    319        q = a0 / b;
    320        r = a0 % b;
    321        *plow = q;
    322        *phigh = r;
    323    } else {
    324        if (a1 >= b) {
    325            return 1;
    326        }
    327        /* XXX: use a better algorithm */
    328        for (i = 0; i < 64; i++) {
    329            ab = a1 >> 63;
    330            a1 = (a1 << 1) | (a0 >> 63);
    331            if (ab || a1 >= b) {
    332                a1 -= b;
    333                qb = 1;
    334            } else {
    335                qb = 0;
    336            }
    337            a0 = (a0 << 1) | qb;
    338        }
    339#if defined(DEBUG_MULDIV)
    340        printf("div: 0x%016" PRIx64 "%016" PRIx64 " / 0x%016" PRIx64
    341               ": q=0x%016" PRIx64 " r=0x%016" PRIx64 "\n",
    342               *phigh, *plow, b, a0, a1);
    343#endif
    344        *plow = a0;
    345        *phigh = a1;
    346    }
    347    return 0;
    348}
    349
    350/* return TRUE if overflow */
    351static int idiv64(uint64_t *plow, uint64_t *phigh, int64_t b)
    352{
    353    int sa, sb;
    354
    355    sa = ((int64_t)*phigh < 0);
    356    if (sa) {
    357        neg128(plow, phigh);
    358    }
    359    sb = (b < 0);
    360    if (sb) {
    361        b = -b;
    362    }
    363    if (div64(plow, phigh, b) != 0) {
    364        return 1;
    365    }
    366    if (sa ^ sb) {
    367        if (*plow > (1ULL << 63)) {
    368            return 1;
    369        }
    370        *plow = -*plow;
    371    } else {
    372        if (*plow >= (1ULL << 63)) {
    373            return 1;
    374        }
    375    }
    376    if (sa) {
    377        *phigh = -*phigh;
    378    }
    379    return 0;
    380}
    381
    382void helper_divq_EAX(CPUX86State *env, target_ulong t0)
    383{
    384    uint64_t r0, r1;
    385
    386    if (t0 == 0) {
    387        raise_exception_ra(env, EXCP00_DIVZ, GETPC());
    388    }
    389    r0 = env->regs[R_EAX];
    390    r1 = env->regs[R_EDX];
    391    if (div64(&r0, &r1, t0)) {
    392        raise_exception_ra(env, EXCP00_DIVZ, GETPC());
    393    }
    394    env->regs[R_EAX] = r0;
    395    env->regs[R_EDX] = r1;
    396}
    397
    398void helper_idivq_EAX(CPUX86State *env, target_ulong t0)
    399{
    400    uint64_t r0, r1;
    401
    402    if (t0 == 0) {
    403        raise_exception_ra(env, EXCP00_DIVZ, GETPC());
    404    }
    405    r0 = env->regs[R_EAX];
    406    r1 = env->regs[R_EDX];
    407    if (idiv64(&r0, &r1, t0)) {
    408        raise_exception_ra(env, EXCP00_DIVZ, GETPC());
    409    }
    410    env->regs[R_EAX] = r0;
    411    env->regs[R_EDX] = r1;
    412}
    413#endif
    414
    415#if TARGET_LONG_BITS == 32
    416# define ctztl  ctz32
    417# define clztl  clz32
    418#else
    419# define ctztl  ctz64
    420# define clztl  clz64
    421#endif
    422
    423target_ulong helper_pdep(target_ulong src, target_ulong mask)
    424{
    425    target_ulong dest = 0;
    426    int i, o;
    427
    428    for (i = 0; mask != 0; i++) {
    429        o = ctztl(mask);
    430        mask &= mask - 1;
    431        dest |= ((src >> i) & 1) << o;
    432    }
    433    return dest;
    434}
    435
    436target_ulong helper_pext(target_ulong src, target_ulong mask)
    437{
    438    target_ulong dest = 0;
    439    int i, o;
    440
    441    for (o = 0; mask != 0; o++) {
    442        i = ctztl(mask);
    443        mask &= mask - 1;
    444        dest |= ((src >> i) & 1) << o;
    445    }
    446    return dest;
    447}
    448
    449#define SHIFT 0
    450#include "shift_helper_template.h"
    451#undef SHIFT
    452
    453#define SHIFT 1
    454#include "shift_helper_template.h"
    455#undef SHIFT
    456
    457#define SHIFT 2
    458#include "shift_helper_template.h"
    459#undef SHIFT
    460
    461#ifdef TARGET_X86_64
    462#define SHIFT 3
    463#include "shift_helper_template.h"
    464#undef SHIFT
    465#endif
    466
    467/* Test that BIT is enabled in CR4.  If not, raise an illegal opcode
    468   exception.  This reduces the requirements for rare CR4 bits being
    469   mapped into HFLAGS.  */
    470void helper_cr4_testbit(CPUX86State *env, uint32_t bit)
    471{
    472    if (unlikely((env->cr[4] & bit) == 0)) {
    473        raise_exception_ra(env, EXCP06_ILLOP, GETPC());
    474    }
    475}
    476
    477target_ulong HELPER(rdrand)(CPUX86State *env)
    478{
    479    Error *err = NULL;
    480    target_ulong ret;
    481
    482    if (qemu_guest_getrandom(&ret, sizeof(ret), &err) < 0) {
    483        qemu_log_mask(LOG_UNIMP, "rdrand: Crypto failure: %s",
    484                      error_get_pretty(err));
    485        error_free(err);
    486        /* Failure clears CF and all other flags, and returns 0.  */
    487        env->cc_src = 0;
    488        return 0;
    489    }
    490
    491    /* Success sets CF and clears all others.  */
    492    env->cc_src = CC_C;
    493    return ret;
    494}