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}