qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

int_helper.c (11783B)


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