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
helper_divb_AL(CPUX86State * env,target_ulong t0)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
helper_idivb_AL(CPUX86State * env,target_ulong t0)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
helper_divw_AX(CPUX86State * env,target_ulong t0)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
helper_idivw_AX(CPUX86State * env,target_ulong t0)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
helper_divl_EAX(CPUX86State * env,target_ulong t0)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
helper_idivl_EAX(CPUX86State * env,target_ulong t0)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
helper_aam(target_ulong al,target_ulong base)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
helper_aad(target_ulong ax,target_ulong base)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
helper_aaa(CPUX86State * env)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
helper_aas(CPUX86State * env)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
helper_daa(CPUX86State * env)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
helper_das(CPUX86State * env)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
add128(uint64_t * plow,uint64_t * phigh,uint64_t a,uint64_t b)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
neg128(uint64_t * plow,uint64_t * phigh)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 */
div64(uint64_t * plow,uint64_t * phigh,uint64_t b)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 */
idiv64(uint64_t * plow,uint64_t * phigh,int64_t b)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
helper_divq_EAX(CPUX86State * env,target_ulong t0)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
helper_idivq_EAX(CPUX86State * env,target_ulong t0)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
helper_pdep(target_ulong src,target_ulong mask)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
helper_pext(target_ulong src,target_ulong mask)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. */
helper_cr4_testbit(CPUX86State * env,uint32_t bit)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
HELPER(rdrand)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