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