]> git.proxmox.com Git - qemu.git/blame - helper-i386.c
update
[qemu.git] / helper-i386.c
CommitLineData
3ec9c4fc
FB
1/*
2 * i386 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, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20#include "exec-i386.h"
21
1e5ffbed
FB
22const uint8_t parity_table[256] = {
23 CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
24 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
25 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
26 CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
27 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
28 CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
29 CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
30 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
31 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
32 CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
33 CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
34 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
35 CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
36 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
37 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
38 CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
39 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
40 CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
41 CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
42 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
43 CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
44 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
45 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
46 CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
47 CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
48 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
49 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
50 CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
51 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
52 CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
53 CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
54 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
55};
56
57/* modulo 17 table */
58const uint8_t rclw_table[32] = {
59 0, 1, 2, 3, 4, 5, 6, 7,
60 8, 9,10,11,12,13,14,15,
61 16, 0, 1, 2, 3, 4, 5, 6,
62 7, 8, 9,10,11,12,13,14,
63};
64
65/* modulo 9 table */
66const uint8_t rclb_table[32] = {
67 0, 1, 2, 3, 4, 5, 6, 7,
68 8, 0, 1, 2, 3, 4, 5, 6,
69 7, 8, 0, 1, 2, 3, 4, 5,
70 6, 7, 8, 0, 1, 2, 3, 4,
71};
72
2d0e9143
FB
73const CPU86_LDouble f15rk[7] =
74{
75 0.00000000000000000000L,
76 1.00000000000000000000L,
77 3.14159265358979323851L, /*pi*/
78 0.30102999566398119523L, /*lg2*/
79 0.69314718055994530943L, /*ln2*/
80 1.44269504088896340739L, /*l2e*/
81 3.32192809488736234781L, /*l2t*/
82};
83
84/* thread support */
85
86spinlock_t global_cpu_lock = SPIN_LOCK_UNLOCKED;
87
88void cpu_lock(void)
89{
90 spin_lock(&global_cpu_lock);
91}
92
93void cpu_unlock(void)
94{
95 spin_unlock(&global_cpu_lock);
96}
97
98void cpu_loop_exit(void)
99{
100 /* NOTE: the register at this point must be saved by hand because
101 longjmp restore them */
102#ifdef reg_EAX
103 env->regs[R_EAX] = EAX;
104#endif
105#ifdef reg_ECX
106 env->regs[R_ECX] = ECX;
107#endif
108#ifdef reg_EDX
109 env->regs[R_EDX] = EDX;
110#endif
111#ifdef reg_EBX
112 env->regs[R_EBX] = EBX;
113#endif
114#ifdef reg_ESP
115 env->regs[R_ESP] = ESP;
116#endif
117#ifdef reg_EBP
118 env->regs[R_EBP] = EBP;
119#endif
120#ifdef reg_ESI
121 env->regs[R_ESI] = ESI;
122#endif
123#ifdef reg_EDI
124 env->regs[R_EDI] = EDI;
125#endif
126 longjmp(env->jmp_env, 1);
127}
128
90a9fdae
FB
129static inline void get_ss_esp_from_tss(uint32_t *ss_ptr,
130 uint32_t *esp_ptr, int dpl)
131{
132 int type, index, shift;
133
3ec9c4fc 134#if 0
90a9fdae
FB
135 {
136 int i;
137 printf("TR: base=%p limit=%x\n", env->tr.base, env->tr.limit);
138 for(i=0;i<env->tr.limit;i++) {
139 printf("%02x ", env->tr.base[i]);
140 if ((i & 7) == 7) printf("\n");
141 }
142 printf("\n");
143 }
144#endif
145
146 if (!(env->tr.flags & DESC_P_MASK))
147 cpu_abort(env, "invalid tss");
148 type = (env->tr.flags >> DESC_TYPE_SHIFT) & 0xf;
149 if ((type & 7) != 1)
150 cpu_abort(env, "invalid tss type");
151 shift = type >> 3;
152 index = (dpl * 4 + 2) << shift;
153 if (index + (4 << shift) - 1 > env->tr.limit)
154 raise_exception_err(EXCP0A_TSS, env->tr.selector & 0xfffc);
155 if (shift == 0) {
156 *esp_ptr = lduw(env->tr.base + index);
157 *ss_ptr = lduw(env->tr.base + index + 2);
158 } else {
159 *esp_ptr = ldl(env->tr.base + index);
160 *ss_ptr = lduw(env->tr.base + index + 4);
161 }
162}
163
164/* return non zero if error */
165static inline int load_segment(uint32_t *e1_ptr, uint32_t *e2_ptr,
166 int selector)
3ec9c4fc 167{
90a9fdae
FB
168 SegmentCache *dt;
169 int index;
3ec9c4fc 170 uint8_t *ptr;
90a9fdae
FB
171
172 if (selector & 0x4)
173 dt = &env->ldt;
174 else
175 dt = &env->gdt;
176 index = selector & ~7;
177 if ((index + 7) > dt->limit)
178 return -1;
179 ptr = dt->base + index;
180 *e1_ptr = ldl(ptr);
181 *e2_ptr = ldl(ptr + 4);
182 return 0;
183}
184
185
186/* protected mode interrupt */
187static void do_interrupt_protected(int intno, int is_int, int error_code,
188 unsigned int next_eip)
189{
190 SegmentCache *dt;
191 uint8_t *ptr, *ssp;
192 int type, dpl, cpl, selector, ss_dpl;
193 int has_error_code, new_stack, shift;
194 uint32_t e1, e2, offset, ss, esp, ss_e1, ss_e2, push_size;
195 uint32_t old_cs, old_ss, old_esp, old_eip;
196
3ec9c4fc
FB
197 dt = &env->idt;
198 if (intno * 8 + 7 > dt->limit)
199 raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
200 ptr = dt->base + intno * 8;
201 e1 = ldl(ptr);
202 e2 = ldl(ptr + 4);
203 /* check gate type */
204 type = (e2 >> DESC_TYPE_SHIFT) & 0x1f;
205 switch(type) {
206 case 5: /* task gate */
90a9fdae
FB
207 cpu_abort(env, "task gate not supported");
208 break;
3ec9c4fc
FB
209 case 6: /* 286 interrupt gate */
210 case 7: /* 286 trap gate */
211 case 14: /* 386 interrupt gate */
212 case 15: /* 386 trap gate */
213 break;
214 default:
215 raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
216 break;
217 }
218 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
a363e34c
FB
219 if (env->eflags & VM_MASK)
220 cpl = 3;
221 else
222 cpl = env->segs[R_CS].selector & 3;
3ec9c4fc
FB
223 /* check privledge if software int */
224 if (is_int && dpl < cpl)
225 raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
226 /* check valid bit */
227 if (!(e2 & DESC_P_MASK))
228 raise_exception_err(EXCP0B_NOSEG, intno * 8 + 2);
90a9fdae
FB
229 selector = e1 >> 16;
230 offset = (e2 & 0xffff0000) | (e1 & 0x0000ffff);
231 if ((selector & 0xfffc) == 0)
232 raise_exception_err(EXCP0D_GPF, 0);
233
234 if (load_segment(&e1, &e2, selector) != 0)
235 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
236 if (!(e2 & DESC_S_MASK) || !(e2 & (DESC_CS_MASK)))
237 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
238 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
239 if (dpl > cpl)
240 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
241 if (!(e2 & DESC_P_MASK))
242 raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
243 if (!(e2 & DESC_C_MASK) && dpl < cpl) {
244 /* to inner priviledge */
245 get_ss_esp_from_tss(&ss, &esp, dpl);
246 if ((ss & 0xfffc) == 0)
247 raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
248 if ((ss & 3) != dpl)
249 raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
250 if (load_segment(&ss_e1, &ss_e2, ss) != 0)
251 raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
252 ss_dpl = (ss_e2 >> DESC_DPL_SHIFT) & 3;
253 if (ss_dpl != dpl)
254 raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
255 if (!(ss_e2 & DESC_S_MASK) ||
256 (ss_e2 & DESC_CS_MASK) ||
257 !(ss_e2 & DESC_W_MASK))
258 raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
259 if (!(ss_e2 & DESC_P_MASK))
260 raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
261 new_stack = 1;
262 } else if ((e2 & DESC_C_MASK) || dpl == cpl) {
263 /* to same priviledge */
264 new_stack = 0;
265 } else {
266 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
267 new_stack = 0; /* avoid warning */
268 }
269
270 shift = type >> 3;
271 has_error_code = 0;
272 if (!is_int) {
273 switch(intno) {
274 case 8:
275 case 10:
276 case 11:
277 case 12:
278 case 13:
279 case 14:
280 case 17:
281 has_error_code = 1;
282 break;
283 }
284 }
285 push_size = 6 + (new_stack << 2) + (has_error_code << 1);
286 if (env->eflags & VM_MASK)
287 push_size += 8;
288 push_size <<= shift;
289
290 /* XXX: check that enough room is available */
291 if (new_stack) {
292 old_esp = env->regs[R_ESP];
293 old_ss = env->segs[R_SS].selector;
294 load_seg(R_SS, ss, env->eip);
295 } else {
296 old_esp = 0;
297 old_ss = 0;
298 esp = env->regs[R_ESP];
299 }
300 if (is_int)
301 old_eip = next_eip;
302 else
303 old_eip = env->eip;
304 old_cs = env->segs[R_CS].selector;
305 load_seg(R_CS, selector, env->eip);
306 env->eip = offset;
307 env->regs[R_ESP] = esp - push_size;
308 ssp = env->segs[R_SS].base + esp;
309 if (shift == 1) {
310 int old_eflags;
311 if (env->eflags & VM_MASK) {
312 ssp -= 4;
313 stl(ssp, env->segs[R_GS].selector);
314 ssp -= 4;
315 stl(ssp, env->segs[R_FS].selector);
316 ssp -= 4;
317 stl(ssp, env->segs[R_DS].selector);
318 ssp -= 4;
319 stl(ssp, env->segs[R_ES].selector);
320 }
321 if (new_stack) {
322 ssp -= 4;
323 stl(ssp, old_ss);
324 ssp -= 4;
325 stl(ssp, old_esp);
326 }
327 ssp -= 4;
328 old_eflags = compute_eflags();
329 stl(ssp, old_eflags);
330 ssp -= 4;
331 stl(ssp, old_cs);
332 ssp -= 4;
333 stl(ssp, old_eip);
334 if (has_error_code) {
335 ssp -= 4;
336 stl(ssp, error_code);
337 }
338 } else {
339 if (new_stack) {
340 ssp -= 2;
341 stw(ssp, old_ss);
342 ssp -= 2;
343 stw(ssp, old_esp);
344 }
345 ssp -= 2;
346 stw(ssp, compute_eflags());
347 ssp -= 2;
348 stw(ssp, old_cs);
349 ssp -= 2;
350 stw(ssp, old_eip);
351 if (has_error_code) {
352 ssp -= 2;
353 stw(ssp, error_code);
354 }
355 }
356
357 /* interrupt gate clear IF mask */
358 if ((type & 1) == 0) {
359 env->eflags &= ~IF_MASK;
360 }
361 env->eflags &= ~(TF_MASK | VM_MASK | RF_MASK | NT_MASK);
3ec9c4fc
FB
362}
363
90a9fdae
FB
364/* real mode interrupt */
365static void do_interrupt_real(int intno, int is_int, int error_code,
366 unsigned int next_eip)
367{
368 SegmentCache *dt;
369 uint8_t *ptr, *ssp;
370 int selector;
371 uint32_t offset, esp;
372 uint32_t old_cs, old_eip;
3ec9c4fc 373
90a9fdae
FB
374 /* real mode (simpler !) */
375 dt = &env->idt;
376 if (intno * 4 + 3 > dt->limit)
377 raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
378 ptr = dt->base + intno * 4;
379 offset = lduw(ptr);
380 selector = lduw(ptr + 2);
381 esp = env->regs[R_ESP] & 0xffff;
382 ssp = env->segs[R_SS].base + esp;
383 if (is_int)
384 old_eip = next_eip;
385 else
386 old_eip = env->eip;
387 old_cs = env->segs[R_CS].selector;
388 ssp -= 2;
389 stw(ssp, compute_eflags());
390 ssp -= 2;
391 stw(ssp, old_cs);
392 ssp -= 2;
393 stw(ssp, old_eip);
394 esp -= 6;
395
396 /* update processor state */
397 env->regs[R_ESP] = (env->regs[R_ESP] & ~0xffff) | (esp & 0xffff);
398 env->eip = offset;
399 env->segs[R_CS].selector = selector;
400 env->segs[R_CS].base = (uint8_t *)(selector << 4);
401 env->eflags &= ~(IF_MASK | TF_MASK | AC_MASK | RF_MASK);
402}
403
404/* fake user mode interrupt */
405void do_interrupt_user(int intno, int is_int, int error_code,
406 unsigned int next_eip)
3ec9c4fc 407{
d8bc1fd0 408 SegmentCache *dt;
3ec9c4fc
FB
409 uint8_t *ptr;
410 int dpl, cpl;
411 uint32_t e2;
412
413 dt = &env->idt;
414 ptr = dt->base + (intno * 8);
415 e2 = ldl(ptr + 4);
416
417 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
418 cpl = 3;
419 /* check privledge if software int */
420 if (is_int && dpl < cpl)
421 raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
422
423 /* Since we emulate only user space, we cannot do more than
424 exiting the emulation with the suitable exception and error
425 code */
426 if (is_int)
427 EIP = next_eip;
90a9fdae
FB
428}
429
430/*
431 * Begin excution of an interruption. is_int is TRUE if coming from
432 * the int instruction. next_eip is the EIP value AFTER the interrupt
433 * instruction. It is only relevant if is_int is TRUE.
434 */
435void do_interrupt(int intno, int is_int, int error_code,
436 unsigned int next_eip)
437{
438 if (env->cr[0] & CR0_PE_MASK) {
439 do_interrupt_protected(intno, is_int, error_code, next_eip);
440 } else {
441 do_interrupt_real(intno, is_int, error_code, next_eip);
442 }
443}
444
445/*
446 * Signal an interruption. It is executed in the main CPU loop.
447 * is_int is TRUE if coming from the int instruction. next_eip is the
448 * EIP value AFTER the interrupt instruction. It is only relevant if
449 * is_int is TRUE.
450 */
451void raise_interrupt(int intno, int is_int, int error_code,
452 unsigned int next_eip)
453{
3ec9c4fc
FB
454 env->exception_index = intno;
455 env->error_code = error_code;
90a9fdae
FB
456 env->exception_is_int = is_int;
457 env->exception_next_eip = next_eip;
3ec9c4fc
FB
458 cpu_loop_exit();
459}
460
3ec9c4fc
FB
461/* shortcuts to generate exceptions */
462void raise_exception_err(int exception_index, int error_code)
463{
464 raise_interrupt(exception_index, 0, error_code, 0);
465}
466
467void raise_exception(int exception_index)
468{
469 raise_interrupt(exception_index, 0, 0, 0);
470}
471
2d0e9143
FB
472#ifdef BUGGY_GCC_DIV64
473/* gcc 2.95.4 on PowerPC does not seem to like using __udivdi3, so we
474 call it from another function */
475uint32_t div64(uint32_t *q_ptr, uint64_t num, uint32_t den)
476{
477 *q_ptr = num / den;
478 return num % den;
479}
480
481int32_t idiv64(int32_t *q_ptr, int64_t num, int32_t den)
482{
483 *q_ptr = num / den;
484 return num % den;
485}
486#endif
487
488void helper_divl_EAX_T0(uint32_t eip)
489{
490 unsigned int den, q, r;
491 uint64_t num;
492
493 num = EAX | ((uint64_t)EDX << 32);
494 den = T0;
495 if (den == 0) {
496 EIP = eip;
497 raise_exception(EXCP00_DIVZ);
498 }
499#ifdef BUGGY_GCC_DIV64
500 r = div64(&q, num, den);
501#else
502 q = (num / den);
503 r = (num % den);
504#endif
505 EAX = q;
506 EDX = r;
507}
508
509void helper_idivl_EAX_T0(uint32_t eip)
510{
511 int den, q, r;
512 int64_t num;
513
514 num = EAX | ((uint64_t)EDX << 32);
515 den = T0;
516 if (den == 0) {
517 EIP = eip;
518 raise_exception(EXCP00_DIVZ);
519 }
520#ifdef BUGGY_GCC_DIV64
521 r = idiv64(&q, num, den);
522#else
523 q = (num / den);
524 r = (num % den);
525#endif
526 EAX = q;
527 EDX = r;
528}
529
530void helper_cmpxchg8b(void)
531{
532 uint64_t d;
533 int eflags;
534
535 eflags = cc_table[CC_OP].compute_all();
536 d = ldq((uint8_t *)A0);
537 if (d == (((uint64_t)EDX << 32) | EAX)) {
538 stq((uint8_t *)A0, ((uint64_t)ECX << 32) | EBX);
539 eflags |= CC_Z;
540 } else {
541 EDX = d >> 32;
542 EAX = d;
543 eflags &= ~CC_Z;
544 }
545 CC_SRC = eflags;
546}
547
3ec9c4fc
FB
548/* We simulate a pre-MMX pentium as in valgrind */
549#define CPUID_FP87 (1 << 0)
550#define CPUID_VME (1 << 1)
551#define CPUID_DE (1 << 2)
552#define CPUID_PSE (1 << 3)
553#define CPUID_TSC (1 << 4)
554#define CPUID_MSR (1 << 5)
555#define CPUID_PAE (1 << 6)
556#define CPUID_MCE (1 << 7)
557#define CPUID_CX8 (1 << 8)
558#define CPUID_APIC (1 << 9)
559#define CPUID_SEP (1 << 11) /* sysenter/sysexit */
560#define CPUID_MTRR (1 << 12)
561#define CPUID_PGE (1 << 13)
562#define CPUID_MCA (1 << 14)
563#define CPUID_CMOV (1 << 15)
564/* ... */
565#define CPUID_MMX (1 << 23)
566#define CPUID_FXSR (1 << 24)
567#define CPUID_SSE (1 << 25)
568#define CPUID_SSE2 (1 << 26)
569
570void helper_cpuid(void)
571{
572 if (EAX == 0) {
573 EAX = 1; /* max EAX index supported */
574 EBX = 0x756e6547;
575 ECX = 0x6c65746e;
576 EDX = 0x49656e69;
577 } else if (EAX == 1) {
a363e34c 578 int family, model, stepping;
3ec9c4fc 579 /* EAX = 1 info */
a363e34c
FB
580#if 0
581 /* pentium 75-200 */
582 family = 5;
583 model = 2;
584 stepping = 11;
585#else
586 /* pentium pro */
587 family = 6;
588 model = 1;
589 stepping = 3;
590#endif
591 EAX = (family << 8) | (model << 4) | stepping;
3ec9c4fc
FB
592 EBX = 0;
593 ECX = 0;
594 EDX = CPUID_FP87 | CPUID_DE | CPUID_PSE |
595 CPUID_TSC | CPUID_MSR | CPUID_MCE |
a363e34c 596 CPUID_CX8 | CPUID_PGE | CPUID_CMOV;
3ec9c4fc
FB
597 }
598}
599
d8bc1fd0
FB
600static inline void load_seg_cache(SegmentCache *sc, uint32_t e1, uint32_t e2)
601{
602 sc->base = (void *)((e1 >> 16) | ((e2 & 0xff) << 16) | (e2 & 0xff000000));
603 sc->limit = (e1 & 0xffff) | (e2 & 0x000f0000);
90a9fdae 604 if (e2 & DESC_G_MASK)
d8bc1fd0 605 sc->limit = (sc->limit << 12) | 0xfff;
90a9fdae 606 sc->flags = e2;
d8bc1fd0
FB
607}
608
609void helper_lldt_T0(void)
610{
611 int selector;
612 SegmentCache *dt;
613 uint32_t e1, e2;
614 int index;
615 uint8_t *ptr;
616
617 selector = T0 & 0xffff;
618 if ((selector & 0xfffc) == 0) {
619 /* XXX: NULL selector case: invalid LDT */
620 env->ldt.base = NULL;
621 env->ldt.limit = 0;
622 } else {
623 if (selector & 0x4)
624 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
625 dt = &env->gdt;
626 index = selector & ~7;
627 if ((index + 7) > dt->limit)
628 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
629 ptr = dt->base + index;
630 e1 = ldl(ptr);
631 e2 = ldl(ptr + 4);
632 if ((e2 & DESC_S_MASK) || ((e2 >> DESC_TYPE_SHIFT) & 0xf) != 2)
633 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
634 if (!(e2 & DESC_P_MASK))
635 raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
636 load_seg_cache(&env->ldt, e1, e2);
637 }
638 env->ldt.selector = selector;
639}
640
641void helper_ltr_T0(void)
642{
643 int selector;
644 SegmentCache *dt;
645 uint32_t e1, e2;
646 int index, type;
647 uint8_t *ptr;
648
649 selector = T0 & 0xffff;
650 if ((selector & 0xfffc) == 0) {
90a9fdae 651 /* NULL selector case: invalid LDT */
d8bc1fd0
FB
652 env->tr.base = NULL;
653 env->tr.limit = 0;
90a9fdae 654 env->tr.flags = 0;
d8bc1fd0
FB
655 } else {
656 if (selector & 0x4)
657 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
658 dt = &env->gdt;
659 index = selector & ~7;
660 if ((index + 7) > dt->limit)
661 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
662 ptr = dt->base + index;
663 e1 = ldl(ptr);
664 e2 = ldl(ptr + 4);
665 type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
666 if ((e2 & DESC_S_MASK) ||
667 (type != 2 && type != 9))
668 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
669 if (!(e2 & DESC_P_MASK))
670 raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
671 load_seg_cache(&env->tr, e1, e2);
672 e2 |= 0x00000200; /* set the busy bit */
673 stl(ptr + 4, e2);
674 }
675 env->tr.selector = selector;
676}
677
3ec9c4fc 678/* only works if protected mode and not VM86 */
d8bc1fd0 679void load_seg(int seg_reg, int selector, unsigned int cur_eip)
3ec9c4fc
FB
680{
681 SegmentCache *sc;
3ec9c4fc 682 uint32_t e1, e2;
d8bc1fd0
FB
683
684 sc = &env->segs[seg_reg];
3ec9c4fc
FB
685 if ((selector & 0xfffc) == 0) {
686 /* null selector case */
687 if (seg_reg == R_SS) {
688 EIP = cur_eip;
d8bc1fd0 689 raise_exception_err(EXCP0D_GPF, 0);
3ec9c4fc
FB
690 } else {
691 /* XXX: each access should trigger an exception */
692 sc->base = NULL;
693 sc->limit = 0;
90a9fdae 694 sc->flags = 0;
3ec9c4fc
FB
695 }
696 } else {
90a9fdae 697 if (load_segment(&e1, &e2, selector) != 0) {
3ec9c4fc
FB
698 EIP = cur_eip;
699 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
700 }
3ec9c4fc
FB
701 if (!(e2 & DESC_S_MASK) ||
702 (e2 & (DESC_CS_MASK | DESC_R_MASK)) == DESC_CS_MASK) {
703 EIP = cur_eip;
704 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
705 }
706
707 if (seg_reg == R_SS) {
708 if ((e2 & (DESC_CS_MASK | DESC_W_MASK)) == 0) {
709 EIP = cur_eip;
710 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
711 }
712 } else {
713 if ((e2 & (DESC_CS_MASK | DESC_R_MASK)) == DESC_CS_MASK) {
714 EIP = cur_eip;
715 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
716 }
717 }
718
719 if (!(e2 & DESC_P_MASK)) {
720 EIP = cur_eip;
721 if (seg_reg == R_SS)
722 raise_exception_err(EXCP0C_STACK, selector & 0xfffc);
723 else
724 raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
725 }
d8bc1fd0 726 load_seg_cache(sc, e1, e2);
3ec9c4fc 727#if 0
90a9fdae
FB
728 fprintf(logfile, "load_seg: sel=0x%04x base=0x%08lx limit=0x%08lx flags=%08x\n",
729 selector, (unsigned long)sc->base, sc->limit, sc->flags);
3ec9c4fc
FB
730#endif
731 }
d8bc1fd0
FB
732 sc->selector = selector;
733}
734
735/* protected mode jump */
736void jmp_seg(int selector, unsigned int new_eip)
737{
738 SegmentCache sc1;
d8bc1fd0 739 uint32_t e1, e2, cpl, dpl, rpl;
d8bc1fd0
FB
740
741 if ((selector & 0xfffc) == 0) {
742 raise_exception_err(EXCP0D_GPF, 0);
743 }
744
90a9fdae 745 if (load_segment(&e1, &e2, selector) != 0)
d8bc1fd0 746 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
d8bc1fd0
FB
747 cpl = env->segs[R_CS].selector & 3;
748 if (e2 & DESC_S_MASK) {
749 if (!(e2 & DESC_CS_MASK))
750 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
751 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
752 if (e2 & DESC_CS_MASK) {
753 /* conforming code segment */
754 if (dpl > cpl)
755 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
756 } else {
757 /* non conforming code segment */
758 rpl = selector & 3;
759 if (rpl > cpl)
760 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
761 if (dpl != cpl)
762 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
763 }
764 if (!(e2 & DESC_P_MASK))
765 raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
766 load_seg_cache(&sc1, e1, e2);
767 if (new_eip > sc1.limit)
768 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
a363e34c
FB
769 env->segs[R_CS].base = sc1.base;
770 env->segs[R_CS].limit = sc1.limit;
771 env->segs[R_CS].flags = sc1.flags;
d8bc1fd0
FB
772 env->segs[R_CS].selector = (selector & 0xfffc) | cpl;
773 EIP = new_eip;
774 } else {
775 cpu_abort(env, "jmp to call/task gate not supported 0x%04x:0x%08x",
776 selector, new_eip);
777 }
778}
779
90a9fdae
FB
780/* init the segment cache in vm86 mode */
781static inline void load_seg_vm(int seg, int selector)
782{
783 SegmentCache *sc = &env->segs[seg];
784 selector &= 0xffff;
785 sc->base = (uint8_t *)(selector << 4);
786 sc->selector = selector;
787 sc->flags = 0;
788 sc->limit = 0xffff;
789}
790
791/* protected mode iret */
792void helper_iret_protected(int shift)
793{
794 uint32_t sp, new_cs, new_eip, new_eflags, new_esp, new_ss;
795 uint32_t new_es, new_ds, new_fs, new_gs;
796 uint32_t e1, e2;
797 int cpl, dpl, rpl, eflags_mask;
798 uint8_t *ssp;
799
800 sp = env->regs[R_ESP];
801 if (!(env->segs[R_SS].flags & DESC_B_MASK))
802 sp &= 0xffff;
803 ssp = env->segs[R_SS].base + sp;
804 if (shift == 1) {
805 /* 32 bits */
806 new_eflags = ldl(ssp + 8);
807 new_cs = ldl(ssp + 4) & 0xffff;
808 new_eip = ldl(ssp);
809 if (new_eflags & VM_MASK)
810 goto return_to_vm86;
811 } else {
812 /* 16 bits */
813 new_eflags = lduw(ssp + 4);
814 new_cs = lduw(ssp + 2);
815 new_eip = lduw(ssp);
816 }
817 if ((new_cs & 0xfffc) == 0)
818 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
819 if (load_segment(&e1, &e2, new_cs) != 0)
820 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
821 if (!(e2 & DESC_S_MASK) ||
822 !(e2 & DESC_CS_MASK))
823 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
824 cpl = env->segs[R_CS].selector & 3;
825 rpl = new_cs & 3;
826 if (rpl < cpl)
827 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
828 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
829 if (e2 & DESC_CS_MASK) {
830 if (dpl > rpl)
831 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
832 } else {
833 if (dpl != rpl)
834 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
835 }
836 if (!(e2 & DESC_P_MASK))
837 raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc);
838
839 if (rpl == cpl) {
840 /* return to same priledge level */
841 load_seg(R_CS, new_cs, env->eip);
842 new_esp = sp + (6 << shift);
843 } else {
844 /* return to differentr priviledge level */
845 if (shift == 1) {
846 /* 32 bits */
847 new_esp = ldl(ssp + 12);
848 new_ss = ldl(ssp + 16) & 0xffff;
849 } else {
850 /* 16 bits */
851 new_esp = lduw(ssp + 6);
852 new_ss = lduw(ssp + 8);
853 }
854
855 if ((new_ss & 3) != rpl)
856 raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc);
857 if (load_segment(&e1, &e2, new_ss) != 0)
858 raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc);
859 if (!(e2 & DESC_S_MASK) ||
860 (e2 & DESC_CS_MASK) ||
861 !(e2 & DESC_W_MASK))
862 raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc);
863 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
864 if (dpl != rpl)
865 raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc);
866 if (!(e2 & DESC_P_MASK))
867 raise_exception_err(EXCP0B_NOSEG, new_ss & 0xfffc);
868
869 load_seg(R_CS, new_cs, env->eip);
870 load_seg(R_SS, new_ss, env->eip);
871 }
872 if (env->segs[R_SS].flags & DESC_B_MASK)
873 env->regs[R_ESP] = new_esp;
874 else
875 env->regs[R_ESP] = (env->regs[R_ESP] & 0xffff0000) |
876 (new_esp & 0xffff);
877 env->eip = new_eip;
878 if (cpl == 0)
879 eflags_mask = FL_UPDATE_CPL0_MASK;
880 else
881 eflags_mask = FL_UPDATE_MASK32;
882 if (shift == 0)
883 eflags_mask &= 0xffff;
884 load_eflags(new_eflags, eflags_mask);
885 return;
886
887 return_to_vm86:
888 new_esp = ldl(ssp + 12);
889 new_ss = ldl(ssp + 16);
890 new_es = ldl(ssp + 20);
891 new_ds = ldl(ssp + 24);
892 new_fs = ldl(ssp + 28);
893 new_gs = ldl(ssp + 32);
894
895 /* modify processor state */
896 load_eflags(new_eflags, FL_UPDATE_CPL0_MASK | VM_MASK | VIF_MASK | VIP_MASK);
897 load_seg_vm(R_CS, new_cs);
898 load_seg_vm(R_SS, new_ss);
899 load_seg_vm(R_ES, new_es);
900 load_seg_vm(R_DS, new_ds);
901 load_seg_vm(R_FS, new_fs);
902 load_seg_vm(R_GS, new_gs);
903
904 env->eip = new_eip;
905 env->regs[R_ESP] = new_esp;
906}
907
d8bc1fd0
FB
908void helper_movl_crN_T0(int reg)
909{
90a9fdae 910 env->cr[reg] = T0;
d8bc1fd0
FB
911 switch(reg) {
912 case 0:
90a9fdae 913 cpu_x86_update_cr0(env);
d8bc1fd0
FB
914 break;
915 case 3:
90a9fdae 916 cpu_x86_update_cr3(env);
d8bc1fd0
FB
917 break;
918 }
919}
920
921/* XXX: do more */
922void helper_movl_drN_T0(int reg)
923{
924 env->dr[reg] = T0;
3ec9c4fc
FB
925}
926
90a9fdae
FB
927void helper_invlpg(unsigned int addr)
928{
929 cpu_x86_flush_tlb(env, addr);
930}
931
2d0e9143
FB
932/* rdtsc */
933#ifndef __i386__
934uint64_t emu_time;
935#endif
936
937void helper_rdtsc(void)
938{
939 uint64_t val;
940#ifdef __i386__
941 asm("rdtsc" : "=A" (val));
942#else
943 /* better than nothing: the time increases */
944 val = emu_time++;
945#endif
946 EAX = val;
947 EDX = val >> 32;
948}
949
3c1cf9fa
FB
950void helper_wrmsr(void)
951{
952 switch(ECX) {
953 case MSR_IA32_SYSENTER_CS:
954 env->sysenter_cs = EAX & 0xffff;
955 break;
956 case MSR_IA32_SYSENTER_ESP:
957 env->sysenter_esp = EAX;
958 break;
959 case MSR_IA32_SYSENTER_EIP:
960 env->sysenter_eip = EAX;
961 break;
962 default:
963 /* XXX: exception ? */
964 break;
965 }
966}
967
968void helper_rdmsr(void)
969{
970 switch(ECX) {
971 case MSR_IA32_SYSENTER_CS:
972 EAX = env->sysenter_cs;
973 EDX = 0;
974 break;
975 case MSR_IA32_SYSENTER_ESP:
976 EAX = env->sysenter_esp;
977 EDX = 0;
978 break;
979 case MSR_IA32_SYSENTER_EIP:
980 EAX = env->sysenter_eip;
981 EDX = 0;
982 break;
983 default:
984 /* XXX: exception ? */
985 break;
986 }
987}
988
3ec9c4fc
FB
989void helper_lsl(void)
990{
991 unsigned int selector, limit;
3ec9c4fc 992 uint32_t e1, e2;
3ec9c4fc
FB
993
994 CC_SRC = cc_table[CC_OP].compute_all() & ~CC_Z;
995 selector = T0 & 0xffff;
90a9fdae 996 if (load_segment(&e1, &e2, selector) != 0)
3ec9c4fc 997 return;
3ec9c4fc
FB
998 limit = (e1 & 0xffff) | (e2 & 0x000f0000);
999 if (e2 & (1 << 23))
1000 limit = (limit << 12) | 0xfff;
1001 T1 = limit;
1002 CC_SRC |= CC_Z;
1003}
1004
1005void helper_lar(void)
1006{
1007 unsigned int selector;
90a9fdae 1008 uint32_t e1, e2;
3ec9c4fc
FB
1009
1010 CC_SRC = cc_table[CC_OP].compute_all() & ~CC_Z;
1011 selector = T0 & 0xffff;
90a9fdae 1012 if (load_segment(&e1, &e2, selector) != 0)
3ec9c4fc 1013 return;
3ec9c4fc
FB
1014 T1 = e2 & 0x00f0ff00;
1015 CC_SRC |= CC_Z;
1016}
1017
1018/* FPU helpers */
1019
1020#ifndef USE_X86LDOUBLE
1021void helper_fldt_ST0_A0(void)
1022{
4d40895f
FB
1023 int new_fpstt;
1024 new_fpstt = (env->fpstt - 1) & 7;
1025 env->fpregs[new_fpstt] = helper_fldt((uint8_t *)A0);
1026 env->fpstt = new_fpstt;
1027 env->fptags[new_fpstt] = 0; /* validate stack entry */
3ec9c4fc
FB
1028}
1029
1030void helper_fstt_ST0_A0(void)
1031{
1032 helper_fstt(ST0, (uint8_t *)A0);
1033}
1034#endif
1035
1036/* BCD ops */
1037
1038#define MUL10(iv) ( iv + iv + (iv << 3) )
1039
1040void helper_fbld_ST0_A0(void)
1041{
4d40895f
FB
1042 CPU86_LDouble tmp;
1043 uint64_t val;
3ec9c4fc 1044 unsigned int v;
4d40895f 1045 int i;
3ec9c4fc 1046
4d40895f
FB
1047 val = 0;
1048 for(i = 8; i >= 0; i--) {
1049 v = ldub((uint8_t *)A0 + i);
1050 val = (val * 100) + ((v >> 4) * 10) + (v & 0xf);
1051 }
1052 tmp = val;
1053 if (ldub((uint8_t *)A0 + 9) & 0x80)
1054 tmp = -tmp;
1055 fpush();
1056 ST0 = tmp;
3ec9c4fc
FB
1057}
1058
1059void helper_fbst_ST0_A0(void)
1060{
4d40895f 1061 CPU86_LDouble tmp;
3ec9c4fc
FB
1062 int v;
1063 uint8_t *mem_ref, *mem_end;
4d40895f 1064 int64_t val;
3ec9c4fc 1065
4d40895f
FB
1066 tmp = rint(ST0);
1067 val = (int64_t)tmp;
3ec9c4fc 1068 mem_ref = (uint8_t *)A0;
4d40895f
FB
1069 mem_end = mem_ref + 9;
1070 if (val < 0) {
1071 stb(mem_end, 0x80);
1072 val = -val;
3ec9c4fc 1073 } else {
4d40895f 1074 stb(mem_end, 0x00);
3ec9c4fc
FB
1075 }
1076 while (mem_ref < mem_end) {
4d40895f 1077 if (val == 0)
3ec9c4fc 1078 break;
4d40895f
FB
1079 v = val % 100;
1080 val = val / 100;
1081 v = ((v / 10) << 4) | (v % 10);
3ec9c4fc 1082 stb(mem_ref++, v);
3ec9c4fc
FB
1083 }
1084 while (mem_ref < mem_end) {
1085 stb(mem_ref++, 0);
1086 }
1087}
1088
1089void helper_f2xm1(void)
1090{
1091 ST0 = pow(2.0,ST0) - 1.0;
1092}
1093
1094void helper_fyl2x(void)
1095{
1096 CPU86_LDouble fptemp;
1097
1098 fptemp = ST0;
1099 if (fptemp>0.0){
1100 fptemp = log(fptemp)/log(2.0); /* log2(ST) */
1101 ST1 *= fptemp;
1102 fpop();
1103 } else {
1104 env->fpus &= (~0x4700);
1105 env->fpus |= 0x400;
1106 }
1107}
1108
1109void helper_fptan(void)
1110{
1111 CPU86_LDouble fptemp;
1112
1113 fptemp = ST0;
1114 if((fptemp > MAXTAN)||(fptemp < -MAXTAN)) {
1115 env->fpus |= 0x400;
1116 } else {
1117 ST0 = tan(fptemp);
1118 fpush();
1119 ST0 = 1.0;
1120 env->fpus &= (~0x400); /* C2 <-- 0 */
1121 /* the above code is for |arg| < 2**52 only */
1122 }
1123}
1124
1125void helper_fpatan(void)
1126{
1127 CPU86_LDouble fptemp, fpsrcop;
1128
1129 fpsrcop = ST1;
1130 fptemp = ST0;
1131 ST1 = atan2(fpsrcop,fptemp);
1132 fpop();
1133}
1134
1135void helper_fxtract(void)
1136{
1137 CPU86_LDoubleU temp;
1138 unsigned int expdif;
1139
1140 temp.d = ST0;
1141 expdif = EXPD(temp) - EXPBIAS;
1142 /*DP exponent bias*/
1143 ST0 = expdif;
1144 fpush();
1145 BIASEXPONENT(temp);
1146 ST0 = temp.d;
1147}
1148
1149void helper_fprem1(void)
1150{
1151 CPU86_LDouble dblq, fpsrcop, fptemp;
1152 CPU86_LDoubleU fpsrcop1, fptemp1;
1153 int expdif;
1154 int q;
1155
1156 fpsrcop = ST0;
1157 fptemp = ST1;
1158 fpsrcop1.d = fpsrcop;
1159 fptemp1.d = fptemp;
1160 expdif = EXPD(fpsrcop1) - EXPD(fptemp1);
1161 if (expdif < 53) {
1162 dblq = fpsrcop / fptemp;
1163 dblq = (dblq < 0.0)? ceil(dblq): floor(dblq);
1164 ST0 = fpsrcop - fptemp*dblq;
1165 q = (int)dblq; /* cutting off top bits is assumed here */
1166 env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
1167 /* (C0,C1,C3) <-- (q2,q1,q0) */
1168 env->fpus |= (q&0x4) << 6; /* (C0) <-- q2 */
1169 env->fpus |= (q&0x2) << 8; /* (C1) <-- q1 */
1170 env->fpus |= (q&0x1) << 14; /* (C3) <-- q0 */
1171 } else {
1172 env->fpus |= 0x400; /* C2 <-- 1 */
1173 fptemp = pow(2.0, expdif-50);
1174 fpsrcop = (ST0 / ST1) / fptemp;
1175 /* fpsrcop = integer obtained by rounding to the nearest */
1176 fpsrcop = (fpsrcop-floor(fpsrcop) < ceil(fpsrcop)-fpsrcop)?
1177 floor(fpsrcop): ceil(fpsrcop);
1178 ST0 -= (ST1 * fpsrcop * fptemp);
1179 }
1180}
1181
1182void helper_fprem(void)
1183{
1184 CPU86_LDouble dblq, fpsrcop, fptemp;
1185 CPU86_LDoubleU fpsrcop1, fptemp1;
1186 int expdif;
1187 int q;
1188
1189 fpsrcop = ST0;
1190 fptemp = ST1;
1191 fpsrcop1.d = fpsrcop;
1192 fptemp1.d = fptemp;
1193 expdif = EXPD(fpsrcop1) - EXPD(fptemp1);
1194 if ( expdif < 53 ) {
1195 dblq = fpsrcop / fptemp;
1196 dblq = (dblq < 0.0)? ceil(dblq): floor(dblq);
1197 ST0 = fpsrcop - fptemp*dblq;
1198 q = (int)dblq; /* cutting off top bits is assumed here */
1199 env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
1200 /* (C0,C1,C3) <-- (q2,q1,q0) */
1201 env->fpus |= (q&0x4) << 6; /* (C0) <-- q2 */
1202 env->fpus |= (q&0x2) << 8; /* (C1) <-- q1 */
1203 env->fpus |= (q&0x1) << 14; /* (C3) <-- q0 */
1204 } else {
1205 env->fpus |= 0x400; /* C2 <-- 1 */
1206 fptemp = pow(2.0, expdif-50);
1207 fpsrcop = (ST0 / ST1) / fptemp;
1208 /* fpsrcop = integer obtained by chopping */
1209 fpsrcop = (fpsrcop < 0.0)?
1210 -(floor(fabs(fpsrcop))): floor(fpsrcop);
1211 ST0 -= (ST1 * fpsrcop * fptemp);
1212 }
1213}
1214
1215void helper_fyl2xp1(void)
1216{
1217 CPU86_LDouble fptemp;
1218
1219 fptemp = ST0;
1220 if ((fptemp+1.0)>0.0) {
1221 fptemp = log(fptemp+1.0) / log(2.0); /* log2(ST+1.0) */
1222 ST1 *= fptemp;
1223 fpop();
1224 } else {
1225 env->fpus &= (~0x4700);
1226 env->fpus |= 0x400;
1227 }
1228}
1229
1230void helper_fsqrt(void)
1231{
1232 CPU86_LDouble fptemp;
1233
1234 fptemp = ST0;
1235 if (fptemp<0.0) {
1236 env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
1237 env->fpus |= 0x400;
1238 }
1239 ST0 = sqrt(fptemp);
1240}
1241
1242void helper_fsincos(void)
1243{
1244 CPU86_LDouble fptemp;
1245
1246 fptemp = ST0;
1247 if ((fptemp > MAXTAN)||(fptemp < -MAXTAN)) {
1248 env->fpus |= 0x400;
1249 } else {
1250 ST0 = sin(fptemp);
1251 fpush();
1252 ST0 = cos(fptemp);
1253 env->fpus &= (~0x400); /* C2 <-- 0 */
1254 /* the above code is for |arg| < 2**63 only */
1255 }
1256}
1257
1258void helper_frndint(void)
1259{
1e5ffbed
FB
1260 CPU86_LDouble a;
1261
1262 a = ST0;
1263#ifdef __arm__
1264 switch(env->fpuc & RC_MASK) {
1265 default:
1266 case RC_NEAR:
1267 asm("rndd %0, %1" : "=f" (a) : "f"(a));
1268 break;
1269 case RC_DOWN:
1270 asm("rnddm %0, %1" : "=f" (a) : "f"(a));
1271 break;
1272 case RC_UP:
1273 asm("rnddp %0, %1" : "=f" (a) : "f"(a));
1274 break;
1275 case RC_CHOP:
1276 asm("rnddz %0, %1" : "=f" (a) : "f"(a));
1277 break;
1278 }
1279#else
1280 a = rint(a);
1281#endif
1282 ST0 = a;
3ec9c4fc
FB
1283}
1284
1285void helper_fscale(void)
1286{
1287 CPU86_LDouble fpsrcop, fptemp;
1288
1289 fpsrcop = 2.0;
1290 fptemp = pow(fpsrcop,ST1);
1291 ST0 *= fptemp;
1292}
1293
1294void helper_fsin(void)
1295{
1296 CPU86_LDouble fptemp;
1297
1298 fptemp = ST0;
1299 if ((fptemp > MAXTAN)||(fptemp < -MAXTAN)) {
1300 env->fpus |= 0x400;
1301 } else {
1302 ST0 = sin(fptemp);
1303 env->fpus &= (~0x400); /* C2 <-- 0 */
1304 /* the above code is for |arg| < 2**53 only */
1305 }
1306}
1307
1308void helper_fcos(void)
1309{
1310 CPU86_LDouble fptemp;
1311
1312 fptemp = ST0;
1313 if((fptemp > MAXTAN)||(fptemp < -MAXTAN)) {
1314 env->fpus |= 0x400;
1315 } else {
1316 ST0 = cos(fptemp);
1317 env->fpus &= (~0x400); /* C2 <-- 0 */
1318 /* the above code is for |arg5 < 2**63 only */
1319 }
1320}
1321
1322void helper_fxam_ST0(void)
1323{
1324 CPU86_LDoubleU temp;
1325 int expdif;
1326
1327 temp.d = ST0;
1328
1329 env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
1330 if (SIGND(temp))
1331 env->fpus |= 0x200; /* C1 <-- 1 */
1332
1333 expdif = EXPD(temp);
1334 if (expdif == MAXEXPD) {
1335 if (MANTD(temp) == 0)
1336 env->fpus |= 0x500 /*Infinity*/;
1337 else
1338 env->fpus |= 0x100 /*NaN*/;
1339 } else if (expdif == 0) {
1340 if (MANTD(temp) == 0)
1341 env->fpus |= 0x4000 /*Zero*/;
1342 else
1343 env->fpus |= 0x4400 /*Denormal*/;
1344 } else {
1345 env->fpus |= 0x400;
1346 }
1347}
1348
1349void helper_fstenv(uint8_t *ptr, int data32)
1350{
1351 int fpus, fptag, exp, i;
1352 uint64_t mant;
1353 CPU86_LDoubleU tmp;
1354
1355 fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
1356 fptag = 0;
1357 for (i=7; i>=0; i--) {
1358 fptag <<= 2;
1359 if (env->fptags[i]) {
1360 fptag |= 3;
1361 } else {
1362 tmp.d = env->fpregs[i];
1363 exp = EXPD(tmp);
1364 mant = MANTD(tmp);
1365 if (exp == 0 && mant == 0) {
1366 /* zero */
1367 fptag |= 1;
1368 } else if (exp == 0 || exp == MAXEXPD
1369#ifdef USE_X86LDOUBLE
1370 || (mant & (1LL << 63)) == 0
1371#endif
1372 ) {
1373 /* NaNs, infinity, denormal */
1374 fptag |= 2;
1375 }
1376 }
1377 }
1378 if (data32) {
1379 /* 32 bit */
1380 stl(ptr, env->fpuc);
1381 stl(ptr + 4, fpus);
1382 stl(ptr + 8, fptag);
1383 stl(ptr + 12, 0);
1384 stl(ptr + 16, 0);
1385 stl(ptr + 20, 0);
1386 stl(ptr + 24, 0);
1387 } else {
1388 /* 16 bit */
1389 stw(ptr, env->fpuc);
1390 stw(ptr + 2, fpus);
1391 stw(ptr + 4, fptag);
1392 stw(ptr + 6, 0);
1393 stw(ptr + 8, 0);
1394 stw(ptr + 10, 0);
1395 stw(ptr + 12, 0);
1396 }
1397}
1398
1399void helper_fldenv(uint8_t *ptr, int data32)
1400{
1401 int i, fpus, fptag;
1402
1403 if (data32) {
1404 env->fpuc = lduw(ptr);
1405 fpus = lduw(ptr + 4);
1406 fptag = lduw(ptr + 8);
1407 }
1408 else {
1409 env->fpuc = lduw(ptr);
1410 fpus = lduw(ptr + 2);
1411 fptag = lduw(ptr + 4);
1412 }
1413 env->fpstt = (fpus >> 11) & 7;
1414 env->fpus = fpus & ~0x3800;
1415 for(i = 0;i < 7; i++) {
1416 env->fptags[i] = ((fptag & 3) == 3);
1417 fptag >>= 2;
1418 }
1419}
1420
1421void helper_fsave(uint8_t *ptr, int data32)
1422{
1423 CPU86_LDouble tmp;
1424 int i;
1425
1426 helper_fstenv(ptr, data32);
1427
1428 ptr += (14 << data32);
1429 for(i = 0;i < 8; i++) {
1430 tmp = ST(i);
1431#ifdef USE_X86LDOUBLE
1432 *(long double *)ptr = tmp;
1433#else
1434 helper_fstt(tmp, ptr);
1435#endif
1436 ptr += 10;
1437 }
1438
1439 /* fninit */
1440 env->fpus = 0;
1441 env->fpstt = 0;
1442 env->fpuc = 0x37f;
1443 env->fptags[0] = 1;
1444 env->fptags[1] = 1;
1445 env->fptags[2] = 1;
1446 env->fptags[3] = 1;
1447 env->fptags[4] = 1;
1448 env->fptags[5] = 1;
1449 env->fptags[6] = 1;
1450 env->fptags[7] = 1;
1451}
1452
1453void helper_frstor(uint8_t *ptr, int data32)
1454{
1455 CPU86_LDouble tmp;
1456 int i;
1457
1458 helper_fldenv(ptr, data32);
1459 ptr += (14 << data32);
1460
1461 for(i = 0;i < 8; i++) {
1462#ifdef USE_X86LDOUBLE
1463 tmp = *(long double *)ptr;
1464#else
1465 tmp = helper_fldt(ptr);
1466#endif
1467 ST(i) = tmp;
1468 ptr += 10;
1469 }
1470}
1471