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 /* XXX: exception */ 149 void helper_aam(CPUX86State *env, int base) 150 { 151 int al, ah; 152 153 al = env->regs[R_EAX] & 0xff; 154 ah = al / base; 155 al = al % base; 156 env->regs[R_EAX] = (env->regs[R_EAX] & ~0xffff) | al | (ah << 8); 157 CC_DST = al; 158 } 159 160 void helper_aad(CPUX86State *env, int base) 161 { 162 int al, ah; 163 164 al = env->regs[R_EAX] & 0xff; 165 ah = (env->regs[R_EAX] >> 8) & 0xff; 166 al = ((ah * base) + al) & 0xff; 167 env->regs[R_EAX] = (env->regs[R_EAX] & ~0xffff) | al; 168 CC_DST = al; 169 } 170 171 void helper_aaa(CPUX86State *env) 172 { 173 int icarry; 174 int al, ah, af; 175 int eflags; 176 177 eflags = cpu_cc_compute_all(env); 178 af = eflags & CC_A; 179 al = env->regs[R_EAX] & 0xff; 180 ah = (env->regs[R_EAX] >> 8) & 0xff; 181 182 icarry = (al > 0xf9); 183 if (((al & 0x0f) > 9) || af) { 184 al = (al + 6) & 0x0f; 185 ah = (ah + 1 + icarry) & 0xff; 186 eflags |= CC_C | CC_A; 187 } else { 188 eflags &= ~(CC_C | CC_A); 189 al &= 0x0f; 190 } 191 env->regs[R_EAX] = (env->regs[R_EAX] & ~0xffff) | al | (ah << 8); 192 CC_SRC = eflags; 193 } 194 195 void helper_aas(CPUX86State *env) 196 { 197 int icarry; 198 int al, ah, af; 199 int eflags; 200 201 eflags = cpu_cc_compute_all(env); 202 af = eflags & CC_A; 203 al = env->regs[R_EAX] & 0xff; 204 ah = (env->regs[R_EAX] >> 8) & 0xff; 205 206 icarry = (al < 6); 207 if (((al & 0x0f) > 9) || af) { 208 al = (al - 6) & 0x0f; 209 ah = (ah - 1 - icarry) & 0xff; 210 eflags |= CC_C | CC_A; 211 } else { 212 eflags &= ~(CC_C | CC_A); 213 al &= 0x0f; 214 } 215 env->regs[R_EAX] = (env->regs[R_EAX] & ~0xffff) | al | (ah << 8); 216 CC_SRC = eflags; 217 } 218 219 void helper_daa(CPUX86State *env) 220 { 221 int old_al, al, af, cf; 222 int eflags; 223 224 eflags = cpu_cc_compute_all(env); 225 cf = eflags & CC_C; 226 af = eflags & CC_A; 227 old_al = al = env->regs[R_EAX] & 0xff; 228 229 eflags = 0; 230 if (((al & 0x0f) > 9) || af) { 231 al = (al + 6) & 0xff; 232 eflags |= CC_A; 233 } 234 if ((old_al > 0x99) || cf) { 235 al = (al + 0x60) & 0xff; 236 eflags |= CC_C; 237 } 238 env->regs[R_EAX] = (env->regs[R_EAX] & ~0xff) | al; 239 /* well, speed is not an issue here, so we compute the flags by hand */ 240 eflags |= (al == 0) << 6; /* zf */ 241 eflags |= parity_table[al]; /* pf */ 242 eflags |= (al & 0x80); /* sf */ 243 CC_SRC = 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 |= parity_table[al]; /* pf */ 273 eflags |= (al & 0x80); /* sf */ 274 CC_SRC = 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 return 0; 456 } 457 458 /* Success sets CF and clears all others. */ 459 env->cc_src = CC_C; 460 return ret; 461 } 462