qemu/target/i386/tcg/int_helper.c
<<
>>
Prefs
   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}
 495