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