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