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