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