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 "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 */
  33static 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 */
  41static 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
  50void 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
  68void 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
  86void 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
 105void 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
 124void 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
 143void 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 */
 165void 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
 176void 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
 187void 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
 211void 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
 235void 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
 262void 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
 294static 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
 304static 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 */
 312static 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 */
 352static 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
 383void 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
 399void 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
 424target_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
 437target_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.  */
 471void 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
 478target_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}
 496