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 } 496