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