diff options
Diffstat (limited to 'helper-i386.c')
-rw-r--r-- | helper-i386.c | 1803 |
1 files changed, 0 insertions, 1803 deletions
diff --git a/helper-i386.c b/helper-i386.c deleted file mode 100644 index 67c3aec6c5..0000000000 --- a/helper-i386.c +++ /dev/null @@ -1,1803 +0,0 @@ -/* - * i386 helpers - * - * Copyright (c) 2003 Fabrice Bellard - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#include "exec-i386.h" - -const uint8_t parity_table[256] = { - CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, - 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, - 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, - CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, - 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, - CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, - CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, - 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, - 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, - CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, - CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, - 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, - CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, - 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, - 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, - CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, - 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, - CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, - CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, - 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, - CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, - 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, - 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, - CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, - CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, - 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, - 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, - CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, - 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, - CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, - CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, - 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, -}; - -/* modulo 17 table */ -const uint8_t rclw_table[32] = { - 0, 1, 2, 3, 4, 5, 6, 7, - 8, 9,10,11,12,13,14,15, - 16, 0, 1, 2, 3, 4, 5, 6, - 7, 8, 9,10,11,12,13,14, -}; - -/* modulo 9 table */ -const uint8_t rclb_table[32] = { - 0, 1, 2, 3, 4, 5, 6, 7, - 8, 0, 1, 2, 3, 4, 5, 6, - 7, 8, 0, 1, 2, 3, 4, 5, - 6, 7, 8, 0, 1, 2, 3, 4, -}; - -const CPU86_LDouble f15rk[7] = -{ - 0.00000000000000000000L, - 1.00000000000000000000L, - 3.14159265358979323851L, /*pi*/ - 0.30102999566398119523L, /*lg2*/ - 0.69314718055994530943L, /*ln2*/ - 1.44269504088896340739L, /*l2e*/ - 3.32192809488736234781L, /*l2t*/ -}; - -/* thread support */ - -spinlock_t global_cpu_lock = SPIN_LOCK_UNLOCKED; - -void cpu_lock(void) -{ - spin_lock(&global_cpu_lock); -} - -void cpu_unlock(void) -{ - spin_unlock(&global_cpu_lock); -} - -void cpu_loop_exit(void) -{ - /* NOTE: the register at this point must be saved by hand because - longjmp restore them */ -#ifdef reg_EAX - env->regs[R_EAX] = EAX; -#endif -#ifdef reg_ECX - env->regs[R_ECX] = ECX; -#endif -#ifdef reg_EDX - env->regs[R_EDX] = EDX; -#endif -#ifdef reg_EBX - env->regs[R_EBX] = EBX; -#endif -#ifdef reg_ESP - env->regs[R_ESP] = ESP; -#endif -#ifdef reg_EBP - env->regs[R_EBP] = EBP; -#endif -#ifdef reg_ESI - env->regs[R_ESI] = ESI; -#endif -#ifdef reg_EDI - env->regs[R_EDI] = EDI; -#endif - longjmp(env->jmp_env, 1); -} - -static inline void get_ss_esp_from_tss(uint32_t *ss_ptr, - uint32_t *esp_ptr, int dpl) -{ - int type, index, shift; - -#if 0 - { - int i; - printf("TR: base=%p limit=%x\n", env->tr.base, env->tr.limit); - for(i=0;i<env->tr.limit;i++) { - printf("%02x ", env->tr.base[i]); - if ((i & 7) == 7) printf("\n"); - } - printf("\n"); - } -#endif - - if (!(env->tr.flags & DESC_P_MASK)) - cpu_abort(env, "invalid tss"); - type = (env->tr.flags >> DESC_TYPE_SHIFT) & 0xf; - if ((type & 7) != 1) - cpu_abort(env, "invalid tss type"); - shift = type >> 3; - index = (dpl * 4 + 2) << shift; - if (index + (4 << shift) - 1 > env->tr.limit) - raise_exception_err(EXCP0A_TSS, env->tr.selector & 0xfffc); - if (shift == 0) { - *esp_ptr = lduw(env->tr.base + index); - *ss_ptr = lduw(env->tr.base + index + 2); - } else { - *esp_ptr = ldl(env->tr.base + index); - *ss_ptr = lduw(env->tr.base + index + 4); - } -} - -/* return non zero if error */ -static inline int load_segment(uint32_t *e1_ptr, uint32_t *e2_ptr, - int selector) -{ - SegmentCache *dt; - int index; - uint8_t *ptr; - - if (selector & 0x4) - dt = &env->ldt; - else - dt = &env->gdt; - index = selector & ~7; - if ((index + 7) > dt->limit) - return -1; - ptr = dt->base + index; - *e1_ptr = ldl(ptr); - *e2_ptr = ldl(ptr + 4); - return 0; -} - -static inline unsigned int get_seg_limit(uint32_t e1, uint32_t e2) -{ - unsigned int limit; - limit = (e1 & 0xffff) | (e2 & 0x000f0000); - if (e2 & DESC_G_MASK) - limit = (limit << 12) | 0xfff; - return limit; -} - -static inline uint8_t *get_seg_base(uint32_t e1, uint32_t e2) -{ - return (uint8_t *)((e1 >> 16) | ((e2 & 0xff) << 16) | (e2 & 0xff000000)); -} - -static inline void load_seg_cache_raw_dt(SegmentCache *sc, uint32_t e1, uint32_t e2) -{ - sc->base = get_seg_base(e1, e2); - sc->limit = get_seg_limit(e1, e2); - sc->flags = e2; -} - -/* init the segment cache in vm86 mode. */ -static inline void load_seg_vm(int seg, int selector) -{ - selector &= 0xffff; - cpu_x86_load_seg_cache(env, seg, selector, - (uint8_t *)(selector << 4), 0xffff, 0); -} - -/* protected mode interrupt */ -static void do_interrupt_protected(int intno, int is_int, int error_code, - unsigned int next_eip, int is_hw) -{ - SegmentCache *dt; - uint8_t *ptr, *ssp; - int type, dpl, selector, ss_dpl, cpl; - int has_error_code, new_stack, shift; - uint32_t e1, e2, offset, ss, esp, ss_e1, ss_e2, push_size; - uint32_t old_cs, old_ss, old_esp, old_eip; - - dt = &env->idt; - if (intno * 8 + 7 > dt->limit) - raise_exception_err(EXCP0D_GPF, intno * 8 + 2); - ptr = dt->base + intno * 8; - e1 = ldl(ptr); - e2 = ldl(ptr + 4); - /* check gate type */ - type = (e2 >> DESC_TYPE_SHIFT) & 0x1f; - switch(type) { - case 5: /* task gate */ - cpu_abort(env, "task gate not supported"); - break; - case 6: /* 286 interrupt gate */ - case 7: /* 286 trap gate */ - case 14: /* 386 interrupt gate */ - case 15: /* 386 trap gate */ - break; - default: - raise_exception_err(EXCP0D_GPF, intno * 8 + 2); - break; - } - dpl = (e2 >> DESC_DPL_SHIFT) & 3; - cpl = env->hflags & HF_CPL_MASK; - /* check privledge if software int */ - if (is_int && dpl < cpl) - raise_exception_err(EXCP0D_GPF, intno * 8 + 2); - /* check valid bit */ - if (!(e2 & DESC_P_MASK)) - raise_exception_err(EXCP0B_NOSEG, intno * 8 + 2); - selector = e1 >> 16; - offset = (e2 & 0xffff0000) | (e1 & 0x0000ffff); - if ((selector & 0xfffc) == 0) - raise_exception_err(EXCP0D_GPF, 0); - - if (load_segment(&e1, &e2, selector) != 0) - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); - if (!(e2 & DESC_S_MASK) || !(e2 & (DESC_CS_MASK))) - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); - dpl = (e2 >> DESC_DPL_SHIFT) & 3; - if (dpl > cpl) - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); - if (!(e2 & DESC_P_MASK)) - raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc); - if (!(e2 & DESC_C_MASK) && dpl < cpl) { - /* to inner priviledge */ - get_ss_esp_from_tss(&ss, &esp, dpl); - if ((ss & 0xfffc) == 0) - raise_exception_err(EXCP0A_TSS, ss & 0xfffc); - if ((ss & 3) != dpl) - raise_exception_err(EXCP0A_TSS, ss & 0xfffc); - if (load_segment(&ss_e1, &ss_e2, ss) != 0) - raise_exception_err(EXCP0A_TSS, ss & 0xfffc); - ss_dpl = (ss_e2 >> DESC_DPL_SHIFT) & 3; - if (ss_dpl != dpl) - raise_exception_err(EXCP0A_TSS, ss & 0xfffc); - if (!(ss_e2 & DESC_S_MASK) || - (ss_e2 & DESC_CS_MASK) || - !(ss_e2 & DESC_W_MASK)) - raise_exception_err(EXCP0A_TSS, ss & 0xfffc); - if (!(ss_e2 & DESC_P_MASK)) - raise_exception_err(EXCP0A_TSS, ss & 0xfffc); - new_stack = 1; - } else if ((e2 & DESC_C_MASK) || dpl == cpl) { - /* to same priviledge */ - new_stack = 0; - } else { - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); - new_stack = 0; /* avoid warning */ - } - - shift = type >> 3; - has_error_code = 0; - if (!is_int && !is_hw) { - switch(intno) { - case 8: - case 10: - case 11: - case 12: - case 13: - case 14: - case 17: - has_error_code = 1; - break; - } - } - push_size = 6 + (new_stack << 2) + (has_error_code << 1); - if (env->eflags & VM_MASK) - push_size += 8; - push_size <<= shift; - - /* XXX: check that enough room is available */ - if (new_stack) { - old_esp = ESP; - old_ss = env->segs[R_SS].selector; - ss = (ss & ~3) | dpl; - cpu_x86_load_seg_cache(env, R_SS, ss, - get_seg_base(ss_e1, ss_e2), - get_seg_limit(ss_e1, ss_e2), - ss_e2); - } else { - old_esp = 0; - old_ss = 0; - esp = ESP; - } - if (is_int) - old_eip = next_eip; - else - old_eip = env->eip; - old_cs = env->segs[R_CS].selector; - selector = (selector & ~3) | dpl; - cpu_x86_load_seg_cache(env, R_CS, selector, - get_seg_base(e1, e2), - get_seg_limit(e1, e2), - e2); - cpu_x86_set_cpl(env, dpl); - env->eip = offset; - ESP = esp - push_size; - ssp = env->segs[R_SS].base + esp; - if (shift == 1) { - int old_eflags; - if (env->eflags & VM_MASK) { - ssp -= 4; - stl(ssp, env->segs[R_GS].selector); - ssp -= 4; - stl(ssp, env->segs[R_FS].selector); - ssp -= 4; - stl(ssp, env->segs[R_DS].selector); - ssp -= 4; - stl(ssp, env->segs[R_ES].selector); - } - if (new_stack) { - ssp -= 4; - stl(ssp, old_ss); - ssp -= 4; - stl(ssp, old_esp); - } - ssp -= 4; - old_eflags = compute_eflags(); - stl(ssp, old_eflags); - ssp -= 4; - stl(ssp, old_cs); - ssp -= 4; - stl(ssp, old_eip); - if (has_error_code) { - ssp -= 4; - stl(ssp, error_code); - } - } else { - if (new_stack) { - ssp -= 2; - stw(ssp, old_ss); - ssp -= 2; - stw(ssp, old_esp); - } - ssp -= 2; - stw(ssp, compute_eflags()); - ssp -= 2; - stw(ssp, old_cs); - ssp -= 2; - stw(ssp, old_eip); - if (has_error_code) { - ssp -= 2; - stw(ssp, error_code); - } - } - - /* interrupt gate clear IF mask */ - if ((type & 1) == 0) { - env->eflags &= ~IF_MASK; - } - env->eflags &= ~(TF_MASK | VM_MASK | RF_MASK | NT_MASK); -} - -/* real mode interrupt */ -static void do_interrupt_real(int intno, int is_int, int error_code, - unsigned int next_eip) -{ - SegmentCache *dt; - uint8_t *ptr, *ssp; - int selector; - uint32_t offset, esp; - uint32_t old_cs, old_eip; - - /* real mode (simpler !) */ - dt = &env->idt; - if (intno * 4 + 3 > dt->limit) - raise_exception_err(EXCP0D_GPF, intno * 8 + 2); - ptr = dt->base + intno * 4; - offset = lduw(ptr); - selector = lduw(ptr + 2); - esp = ESP; - ssp = env->segs[R_SS].base; - if (is_int) - old_eip = next_eip; - else - old_eip = env->eip; - old_cs = env->segs[R_CS].selector; - esp -= 2; - stw(ssp + (esp & 0xffff), compute_eflags()); - esp -= 2; - stw(ssp + (esp & 0xffff), old_cs); - esp -= 2; - stw(ssp + (esp & 0xffff), old_eip); - - /* update processor state */ - ESP = (ESP & ~0xffff) | (esp & 0xffff); - env->eip = offset; - env->segs[R_CS].selector = selector; - env->segs[R_CS].base = (uint8_t *)(selector << 4); - env->eflags &= ~(IF_MASK | TF_MASK | AC_MASK | RF_MASK); -} - -/* fake user mode interrupt */ -void do_interrupt_user(int intno, int is_int, int error_code, - unsigned int next_eip) -{ - SegmentCache *dt; - uint8_t *ptr; - int dpl, cpl; - uint32_t e2; - - dt = &env->idt; - ptr = dt->base + (intno * 8); - e2 = ldl(ptr + 4); - - dpl = (e2 >> DESC_DPL_SHIFT) & 3; - cpl = env->hflags & HF_CPL_MASK; - /* check privledge if software int */ - if (is_int && dpl < cpl) - raise_exception_err(EXCP0D_GPF, intno * 8 + 2); - - /* Since we emulate only user space, we cannot do more than - exiting the emulation with the suitable exception and error - code */ - if (is_int) - EIP = next_eip; -} - -/* - * Begin excution of an interruption. is_int is TRUE if coming from - * the int instruction. next_eip is the EIP value AFTER the interrupt - * instruction. It is only relevant if is_int is TRUE. - */ -void do_interrupt(int intno, int is_int, int error_code, - unsigned int next_eip, int is_hw) -{ - if (env->cr[0] & CR0_PE_MASK) { - do_interrupt_protected(intno, is_int, error_code, next_eip, is_hw); - } else { - do_interrupt_real(intno, is_int, error_code, next_eip); - } -} - -/* - * Signal an interruption. It is executed in the main CPU loop. - * is_int is TRUE if coming from the int instruction. next_eip is the - * EIP value AFTER the interrupt instruction. It is only relevant if - * is_int is TRUE. - */ -void raise_interrupt(int intno, int is_int, int error_code, - unsigned int next_eip) -{ - env->exception_index = intno; - env->error_code = error_code; - env->exception_is_int = is_int; - env->exception_next_eip = next_eip; - cpu_loop_exit(); -} - -/* shortcuts to generate exceptions */ -void raise_exception_err(int exception_index, int error_code) -{ - raise_interrupt(exception_index, 0, error_code, 0); -} - -void raise_exception(int exception_index) -{ - raise_interrupt(exception_index, 0, 0, 0); -} - -#ifdef BUGGY_GCC_DIV64 -/* gcc 2.95.4 on PowerPC does not seem to like using __udivdi3, so we - call it from another function */ -uint32_t div64(uint32_t *q_ptr, uint64_t num, uint32_t den) -{ - *q_ptr = num / den; - return num % den; -} - -int32_t idiv64(int32_t *q_ptr, int64_t num, int32_t den) -{ - *q_ptr = num / den; - return num % den; -} -#endif - -void helper_divl_EAX_T0(uint32_t eip) -{ - unsigned int den, q, r; - uint64_t num; - - num = EAX | ((uint64_t)EDX << 32); - den = T0; - if (den == 0) { - EIP = eip; - raise_exception(EXCP00_DIVZ); - } -#ifdef BUGGY_GCC_DIV64 - r = div64(&q, num, den); -#else - q = (num / den); - r = (num % den); -#endif - EAX = q; - EDX = r; -} - -void helper_idivl_EAX_T0(uint32_t eip) -{ - int den, q, r; - int64_t num; - - num = EAX | ((uint64_t)EDX << 32); - den = T0; - if (den == 0) { - EIP = eip; - raise_exception(EXCP00_DIVZ); - } -#ifdef BUGGY_GCC_DIV64 - r = idiv64(&q, num, den); -#else - q = (num / den); - r = (num % den); -#endif - EAX = q; - EDX = r; -} - -void helper_cmpxchg8b(void) -{ - uint64_t d; - int eflags; - - eflags = cc_table[CC_OP].compute_all(); - d = ldq((uint8_t *)A0); - if (d == (((uint64_t)EDX << 32) | EAX)) { - stq((uint8_t *)A0, ((uint64_t)ECX << 32) | EBX); - eflags |= CC_Z; - } else { - EDX = d >> 32; - EAX = d; - eflags &= ~CC_Z; - } - CC_SRC = eflags; -} - -/* We simulate a pre-MMX pentium as in valgrind */ -#define CPUID_FP87 (1 << 0) -#define CPUID_VME (1 << 1) -#define CPUID_DE (1 << 2) -#define CPUID_PSE (1 << 3) -#define CPUID_TSC (1 << 4) -#define CPUID_MSR (1 << 5) -#define CPUID_PAE (1 << 6) -#define CPUID_MCE (1 << 7) -#define CPUID_CX8 (1 << 8) -#define CPUID_APIC (1 << 9) -#define CPUID_SEP (1 << 11) /* sysenter/sysexit */ -#define CPUID_MTRR (1 << 12) -#define CPUID_PGE (1 << 13) -#define CPUID_MCA (1 << 14) -#define CPUID_CMOV (1 << 15) -/* ... */ -#define CPUID_MMX (1 << 23) -#define CPUID_FXSR (1 << 24) -#define CPUID_SSE (1 << 25) -#define CPUID_SSE2 (1 << 26) - -void helper_cpuid(void) -{ - if (EAX == 0) { - EAX = 1; /* max EAX index supported */ - EBX = 0x756e6547; - ECX = 0x6c65746e; - EDX = 0x49656e69; - } else if (EAX == 1) { - int family, model, stepping; - /* EAX = 1 info */ -#if 0 - /* pentium 75-200 */ - family = 5; - model = 2; - stepping = 11; -#else - /* pentium pro */ - family = 6; - model = 1; - stepping = 3; -#endif - EAX = (family << 8) | (model << 4) | stepping; - EBX = 0; - ECX = 0; - EDX = CPUID_FP87 | CPUID_DE | CPUID_PSE | - CPUID_TSC | CPUID_MSR | CPUID_MCE | - CPUID_CX8 | CPUID_PGE | CPUID_CMOV; - } -} - -void helper_lldt_T0(void) -{ - int selector; - SegmentCache *dt; - uint32_t e1, e2; - int index; - uint8_t *ptr; - - selector = T0 & 0xffff; - if ((selector & 0xfffc) == 0) { - /* XXX: NULL selector case: invalid LDT */ - env->ldt.base = NULL; - env->ldt.limit = 0; - } else { - if (selector & 0x4) - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); - dt = &env->gdt; - index = selector & ~7; - if ((index + 7) > dt->limit) - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); - ptr = dt->base + index; - e1 = ldl(ptr); - e2 = ldl(ptr + 4); - if ((e2 & DESC_S_MASK) || ((e2 >> DESC_TYPE_SHIFT) & 0xf) != 2) - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); - if (!(e2 & DESC_P_MASK)) - raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc); - load_seg_cache_raw_dt(&env->ldt, e1, e2); - } - env->ldt.selector = selector; -} - -void helper_ltr_T0(void) -{ - int selector; - SegmentCache *dt; - uint32_t e1, e2; - int index, type; - uint8_t *ptr; - - selector = T0 & 0xffff; - if ((selector & 0xfffc) == 0) { - /* NULL selector case: invalid LDT */ - env->tr.base = NULL; - env->tr.limit = 0; - env->tr.flags = 0; - } else { - if (selector & 0x4) - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); - dt = &env->gdt; - index = selector & ~7; - if ((index + 7) > dt->limit) - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); - ptr = dt->base + index; - e1 = ldl(ptr); - e2 = ldl(ptr + 4); - type = (e2 >> DESC_TYPE_SHIFT) & 0xf; - if ((e2 & DESC_S_MASK) || - (type != 2 && type != 9)) - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); - if (!(e2 & DESC_P_MASK)) - raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc); - load_seg_cache_raw_dt(&env->tr, e1, e2); - e2 |= 0x00000200; /* set the busy bit */ - stl(ptr + 4, e2); - } - env->tr.selector = selector; -} - -/* only works if protected mode and not VM86. Calling load_seg with - seg_reg == R_CS is discouraged */ -void load_seg(int seg_reg, int selector, unsigned int cur_eip) -{ - uint32_t e1, e2; - - if ((selector & 0xfffc) == 0) { - /* null selector case */ - if (seg_reg == R_SS) { - EIP = cur_eip; - raise_exception_err(EXCP0D_GPF, 0); - } else { - cpu_x86_load_seg_cache(env, seg_reg, selector, NULL, 0, 0); - } - } else { - if (load_segment(&e1, &e2, selector) != 0) { - EIP = cur_eip; - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); - } - if (!(e2 & DESC_S_MASK) || - (e2 & (DESC_CS_MASK | DESC_R_MASK)) == DESC_CS_MASK) { - EIP = cur_eip; - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); - } - - if (seg_reg == R_SS) { - if ((e2 & (DESC_CS_MASK | DESC_W_MASK)) == 0) { - EIP = cur_eip; - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); - } - } else { - if ((e2 & (DESC_CS_MASK | DESC_R_MASK)) == DESC_CS_MASK) { - EIP = cur_eip; - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); - } - } - - if (!(e2 & DESC_P_MASK)) { - EIP = cur_eip; - if (seg_reg == R_SS) - raise_exception_err(EXCP0C_STACK, selector & 0xfffc); - else - raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc); - } - cpu_x86_load_seg_cache(env, seg_reg, selector, - get_seg_base(e1, e2), - get_seg_limit(e1, e2), - e2); -#if 0 - fprintf(logfile, "load_seg: sel=0x%04x base=0x%08lx limit=0x%08lx flags=%08x\n", - selector, (unsigned long)sc->base, sc->limit, sc->flags); -#endif - } -} - -/* protected mode jump */ -void helper_ljmp_protected_T0_T1(void) -{ - int new_cs, new_eip; - uint32_t e1, e2, cpl, dpl, rpl, limit; - - new_cs = T0; - new_eip = T1; - if ((new_cs & 0xfffc) == 0) - raise_exception_err(EXCP0D_GPF, 0); - if (load_segment(&e1, &e2, new_cs) != 0) - raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); - cpl = env->hflags & HF_CPL_MASK; - if (e2 & DESC_S_MASK) { - if (!(e2 & DESC_CS_MASK)) - raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); - dpl = (e2 >> DESC_DPL_SHIFT) & 3; - if (e2 & DESC_CS_MASK) { - /* conforming code segment */ - if (dpl > cpl) - raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); - } else { - /* non conforming code segment */ - rpl = new_cs & 3; - if (rpl > cpl) - raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); - if (dpl != cpl) - raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); - } - if (!(e2 & DESC_P_MASK)) - raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc); - limit = get_seg_limit(e1, e2); - if (new_eip > limit) - raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); - cpu_x86_load_seg_cache(env, R_CS, (new_cs & 0xfffc) | cpl, - get_seg_base(e1, e2), limit, e2); - EIP = new_eip; - } else { - cpu_abort(env, "jmp to call/task gate not supported 0x%04x:0x%08x", - new_cs, new_eip); - } -} - -/* real mode call */ -void helper_lcall_real_T0_T1(int shift, int next_eip) -{ - int new_cs, new_eip; - uint32_t esp, esp_mask; - uint8_t *ssp; - - new_cs = T0; - new_eip = T1; - esp = ESP; - esp_mask = 0xffffffff; - if (!(env->segs[R_SS].flags & DESC_B_MASK)) - esp_mask = 0xffff; - ssp = env->segs[R_SS].base; - if (shift) { - esp -= 4; - stl(ssp + (esp & esp_mask), env->segs[R_CS].selector); - esp -= 4; - stl(ssp + (esp & esp_mask), next_eip); - } else { - esp -= 2; - stw(ssp + (esp & esp_mask), env->segs[R_CS].selector); - esp -= 2; - stw(ssp + (esp & esp_mask), next_eip); - } - - if (!(env->segs[R_SS].flags & DESC_B_MASK)) - ESP = (ESP & ~0xffff) | (esp & 0xffff); - else - ESP = esp; - env->eip = new_eip; - env->segs[R_CS].selector = new_cs; - env->segs[R_CS].base = (uint8_t *)(new_cs << 4); -} - -/* protected mode call */ -void helper_lcall_protected_T0_T1(int shift, int next_eip) -{ - int new_cs, new_eip; - uint32_t e1, e2, cpl, dpl, rpl, selector, offset, param_count; - uint32_t ss, ss_e1, ss_e2, push_size, sp, type, ss_dpl; - uint32_t old_ss, old_esp, val, i, limit; - uint8_t *ssp, *old_ssp; - - new_cs = T0; - new_eip = T1; - if ((new_cs & 0xfffc) == 0) - raise_exception_err(EXCP0D_GPF, 0); - if (load_segment(&e1, &e2, new_cs) != 0) - raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); - cpl = env->hflags & HF_CPL_MASK; - if (e2 & DESC_S_MASK) { - if (!(e2 & DESC_CS_MASK)) - raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); - dpl = (e2 >> DESC_DPL_SHIFT) & 3; - if (e2 & DESC_CS_MASK) { - /* conforming code segment */ - if (dpl > cpl) - raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); - } else { - /* non conforming code segment */ - rpl = new_cs & 3; - if (rpl > cpl) - raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); - if (dpl != cpl) - raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); - } - if (!(e2 & DESC_P_MASK)) - raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc); - - sp = ESP; - if (!(env->segs[R_SS].flags & DESC_B_MASK)) - sp &= 0xffff; - ssp = env->segs[R_SS].base + sp; - if (shift) { - ssp -= 4; - stl(ssp, env->segs[R_CS].selector); - ssp -= 4; - stl(ssp, next_eip); - } else { - ssp -= 2; - stw(ssp, env->segs[R_CS].selector); - ssp -= 2; - stw(ssp, next_eip); - } - sp -= (4 << shift); - - limit = get_seg_limit(e1, e2); - if (new_eip > limit) - raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); - /* from this point, not restartable */ - if (!(env->segs[R_SS].flags & DESC_B_MASK)) - ESP = (ESP & 0xffff0000) | (sp & 0xffff); - else - ESP = sp; - cpu_x86_load_seg_cache(env, R_CS, (new_cs & 0xfffc) | cpl, - get_seg_base(e1, e2), limit, e2); - EIP = new_eip; - } else { - /* check gate type */ - type = (e2 >> DESC_TYPE_SHIFT) & 0x1f; - switch(type) { - case 1: /* available 286 TSS */ - case 9: /* available 386 TSS */ - case 5: /* task gate */ - cpu_abort(env, "task gate not supported"); - break; - case 4: /* 286 call gate */ - case 12: /* 386 call gate */ - break; - default: - raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); - break; - } - shift = type >> 3; - - dpl = (e2 >> DESC_DPL_SHIFT) & 3; - rpl = new_cs & 3; - if (dpl < cpl || dpl < rpl) - raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); - /* check valid bit */ - if (!(e2 & DESC_P_MASK)) - raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc); - selector = e1 >> 16; - offset = (e2 & 0xffff0000) | (e1 & 0x0000ffff); - if ((selector & 0xfffc) == 0) - raise_exception_err(EXCP0D_GPF, 0); - - if (load_segment(&e1, &e2, selector) != 0) - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); - if (!(e2 & DESC_S_MASK) || !(e2 & (DESC_CS_MASK))) - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); - dpl = (e2 >> DESC_DPL_SHIFT) & 3; - if (dpl > cpl) - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); - if (!(e2 & DESC_P_MASK)) - raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc); - - if (!(e2 & DESC_C_MASK) && dpl < cpl) { - /* to inner priviledge */ - get_ss_esp_from_tss(&ss, &sp, dpl); - if ((ss & 0xfffc) == 0) - raise_exception_err(EXCP0A_TSS, ss & 0xfffc); - if ((ss & 3) != dpl) - raise_exception_err(EXCP0A_TSS, ss & 0xfffc); - if (load_segment(&ss_e1, &ss_e2, ss) != 0) - raise_exception_err(EXCP0A_TSS, ss & 0xfffc); - ss_dpl = (ss_e2 >> DESC_DPL_SHIFT) & 3; - if (ss_dpl != dpl) - raise_exception_err(EXCP0A_TSS, ss & 0xfffc); - if (!(ss_e2 & DESC_S_MASK) || - (ss_e2 & DESC_CS_MASK) || - !(ss_e2 & DESC_W_MASK)) - raise_exception_err(EXCP0A_TSS, ss & 0xfffc); - if (!(ss_e2 & DESC_P_MASK)) - raise_exception_err(EXCP0A_TSS, ss & 0xfffc); - - param_count = e2 & 0x1f; - push_size = ((param_count * 2) + 8) << shift; - - old_esp = ESP; - old_ss = env->segs[R_SS].selector; - if (!(env->segs[R_SS].flags & DESC_B_MASK)) - old_esp &= 0xffff; - old_ssp = env->segs[R_SS].base + old_esp; - - /* XXX: from this point not restartable */ - ss = (ss & ~3) | dpl; - cpu_x86_load_seg_cache(env, R_SS, ss, - get_seg_base(ss_e1, ss_e2), - get_seg_limit(ss_e1, ss_e2), - ss_e2); - - if (!(env->segs[R_SS].flags & DESC_B_MASK)) - sp &= 0xffff; - ssp = env->segs[R_SS].base + sp; - if (shift) { - ssp -= 4; - stl(ssp, old_ss); - ssp -= 4; - stl(ssp, old_esp); - ssp -= 4 * param_count; - for(i = 0; i < param_count; i++) { - val = ldl(old_ssp + i * 4); - stl(ssp + i * 4, val); - } - } else { - ssp -= 2; - stw(ssp, old_ss); - ssp -= 2; - stw(ssp, old_esp); - ssp -= 2 * param_count; - for(i = 0; i < param_count; i++) { - val = lduw(old_ssp + i * 2); - stw(ssp + i * 2, val); - } - } - } else { - /* to same priviledge */ - if (!(env->segs[R_SS].flags & DESC_B_MASK)) - sp &= 0xffff; - ssp = env->segs[R_SS].base + sp; - push_size = (4 << shift); - } - - if (shift) { - ssp -= 4; - stl(ssp, env->segs[R_CS].selector); - ssp -= 4; - stl(ssp, next_eip); - } else { - ssp -= 2; - stw(ssp, env->segs[R_CS].selector); - ssp -= 2; - stw(ssp, next_eip); - } - - sp -= push_size; - selector = (selector & ~3) | dpl; - cpu_x86_load_seg_cache(env, R_CS, selector, - get_seg_base(e1, e2), - get_seg_limit(e1, e2), - e2); - cpu_x86_set_cpl(env, dpl); - - /* from this point, not restartable if same priviledge */ - if (!(env->segs[R_SS].flags & DESC_B_MASK)) - ESP = (ESP & 0xffff0000) | (sp & 0xffff); - else - ESP = sp; - EIP = offset; - } -} - -/* real mode iret */ -void helper_iret_real(int shift) -{ - uint32_t sp, new_cs, new_eip, new_eflags, new_esp; - uint8_t *ssp; - int eflags_mask; - - sp = ESP & 0xffff; - ssp = env->segs[R_SS].base + sp; - if (shift == 1) { - /* 32 bits */ - new_eflags = ldl(ssp + 8); - new_cs = ldl(ssp + 4) & 0xffff; - new_eip = ldl(ssp) & 0xffff; - } else { - /* 16 bits */ - new_eflags = lduw(ssp + 4); - new_cs = lduw(ssp + 2); - new_eip = lduw(ssp); - } - new_esp = sp + (6 << shift); - ESP = (ESP & 0xffff0000) | - (new_esp & 0xffff); - load_seg_vm(R_CS, new_cs); - env->eip = new_eip; - eflags_mask = FL_UPDATE_CPL0_MASK; - if (shift == 0) - eflags_mask &= 0xffff; - load_eflags(new_eflags, eflags_mask); -} - -/* protected mode iret */ -static inline void helper_ret_protected(int shift, int is_iret, int addend) -{ - uint32_t sp, new_cs, new_eip, new_eflags, new_esp, new_ss; - uint32_t new_es, new_ds, new_fs, new_gs; - uint32_t e1, e2, ss_e1, ss_e2; - int cpl, dpl, rpl, eflags_mask; - uint8_t *ssp; - - sp = ESP; - if (!(env->segs[R_SS].flags & DESC_B_MASK)) - sp &= 0xffff; - ssp = env->segs[R_SS].base + sp; - if (shift == 1) { - /* 32 bits */ - if (is_iret) - new_eflags = ldl(ssp + 8); - new_cs = ldl(ssp + 4) & 0xffff; - new_eip = ldl(ssp); - if (is_iret && (new_eflags & VM_MASK)) - goto return_to_vm86; - } else { - /* 16 bits */ - if (is_iret) - new_eflags = lduw(ssp + 4); - new_cs = lduw(ssp + 2); - new_eip = lduw(ssp); - } - if ((new_cs & 0xfffc) == 0) - raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); - if (load_segment(&e1, &e2, new_cs) != 0) - raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); - if (!(e2 & DESC_S_MASK) || - !(e2 & DESC_CS_MASK)) - raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); - cpl = env->hflags & HF_CPL_MASK; - rpl = new_cs & 3; - if (rpl < cpl) - raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); - dpl = (e2 >> DESC_DPL_SHIFT) & 3; - if (e2 & DESC_CS_MASK) { - if (dpl > rpl) - raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); - } else { - if (dpl != rpl) - raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); - } - if (!(e2 & DESC_P_MASK)) - raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc); - - if (rpl == cpl) { - /* return to same priledge level */ - cpu_x86_load_seg_cache(env, R_CS, new_cs, - get_seg_base(e1, e2), - get_seg_limit(e1, e2), - e2); - new_esp = sp + (4 << shift) + ((2 * is_iret) << shift) + addend; - } else { - /* return to different priviledge level */ - ssp += (4 << shift) + ((2 * is_iret) << shift) + addend; - if (shift == 1) { - /* 32 bits */ - new_esp = ldl(ssp); - new_ss = ldl(ssp + 4) & 0xffff; - } else { - /* 16 bits */ - new_esp = lduw(ssp); - new_ss = lduw(ssp + 2); - } - - if ((new_ss & 3) != rpl) - raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc); - if (load_segment(&ss_e1, &ss_e2, new_ss) != 0) - raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc); - if (!(ss_e2 & DESC_S_MASK) || - (ss_e2 & DESC_CS_MASK) || - !(ss_e2 & DESC_W_MASK)) - raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc); - dpl = (ss_e2 >> DESC_DPL_SHIFT) & 3; - if (dpl != rpl) - raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc); - if (!(ss_e2 & DESC_P_MASK)) - raise_exception_err(EXCP0B_NOSEG, new_ss & 0xfffc); - - cpu_x86_load_seg_cache(env, R_CS, new_cs, - get_seg_base(e1, e2), - get_seg_limit(e1, e2), - e2); - cpu_x86_load_seg_cache(env, R_SS, new_ss, - get_seg_base(ss_e1, ss_e2), - get_seg_limit(ss_e1, ss_e2), - ss_e2); - cpu_x86_set_cpl(env, rpl); - } - if (env->segs[R_SS].flags & DESC_B_MASK) - ESP = new_esp; - else - ESP = (ESP & 0xffff0000) | - (new_esp & 0xffff); - env->eip = new_eip; - if (is_iret) { - /* NOTE: 'cpl' can be different from the current CPL */ - if (cpl == 0) - eflags_mask = FL_UPDATE_CPL0_MASK; - else - eflags_mask = FL_UPDATE_MASK32; - if (shift == 0) - eflags_mask &= 0xffff; - load_eflags(new_eflags, eflags_mask); - } - return; - - return_to_vm86: - new_esp = ldl(ssp + 12); - new_ss = ldl(ssp + 16); - new_es = ldl(ssp + 20); - new_ds = ldl(ssp + 24); - new_fs = ldl(ssp + 28); - new_gs = ldl(ssp + 32); - - /* modify processor state */ - load_eflags(new_eflags, FL_UPDATE_CPL0_MASK | VM_MASK | VIF_MASK | VIP_MASK); - load_seg_vm(R_CS, new_cs); - cpu_x86_set_cpl(env, 3); - load_seg_vm(R_SS, new_ss); - load_seg_vm(R_ES, new_es); - load_seg_vm(R_DS, new_ds); - load_seg_vm(R_FS, new_fs); - load_seg_vm(R_GS, new_gs); - - env->eip = new_eip; - ESP = new_esp; -} - -void helper_iret_protected(int shift) -{ - helper_ret_protected(shift, 1, 0); -} - -void helper_lret_protected(int shift, int addend) -{ - helper_ret_protected(shift, 0, addend); -} - -void helper_movl_crN_T0(int reg) -{ - env->cr[reg] = T0; - switch(reg) { - case 0: - cpu_x86_update_cr0(env); - break; - case 3: - cpu_x86_update_cr3(env); - break; - } -} - -/* XXX: do more */ -void helper_movl_drN_T0(int reg) -{ - env->dr[reg] = T0; -} - -void helper_invlpg(unsigned int addr) -{ - cpu_x86_flush_tlb(env, addr); -} - -/* rdtsc */ -#ifndef __i386__ -uint64_t emu_time; -#endif - -void helper_rdtsc(void) -{ - uint64_t val; -#ifdef __i386__ - asm("rdtsc" : "=A" (val)); -#else - /* better than nothing: the time increases */ - val = emu_time++; -#endif - EAX = val; - EDX = val >> 32; -} - -void helper_wrmsr(void) -{ - switch(ECX) { - case MSR_IA32_SYSENTER_CS: - env->sysenter_cs = EAX & 0xffff; - break; - case MSR_IA32_SYSENTER_ESP: - env->sysenter_esp = EAX; - break; - case MSR_IA32_SYSENTER_EIP: - env->sysenter_eip = EAX; - break; - default: - /* XXX: exception ? */ - break; - } -} - -void helper_rdmsr(void) -{ - switch(ECX) { - case MSR_IA32_SYSENTER_CS: - EAX = env->sysenter_cs; - EDX = 0; - break; - case MSR_IA32_SYSENTER_ESP: - EAX = env->sysenter_esp; - EDX = 0; - break; - case MSR_IA32_SYSENTER_EIP: - EAX = env->sysenter_eip; - EDX = 0; - break; - default: - /* XXX: exception ? */ - break; - } -} - -void helper_lsl(void) -{ - unsigned int selector, limit; - uint32_t e1, e2; - - CC_SRC = cc_table[CC_OP].compute_all() & ~CC_Z; - selector = T0 & 0xffff; - if (load_segment(&e1, &e2, selector) != 0) - return; - limit = (e1 & 0xffff) | (e2 & 0x000f0000); - if (e2 & (1 << 23)) - limit = (limit << 12) | 0xfff; - T1 = limit; - CC_SRC |= CC_Z; -} - -void helper_lar(void) -{ - unsigned int selector; - uint32_t e1, e2; - - CC_SRC = cc_table[CC_OP].compute_all() & ~CC_Z; - selector = T0 & 0xffff; - if (load_segment(&e1, &e2, selector) != 0) - return; - T1 = e2 & 0x00f0ff00; - CC_SRC |= CC_Z; -} - -/* FPU helpers */ - -#ifndef USE_X86LDOUBLE -void helper_fldt_ST0_A0(void) -{ - int new_fpstt; - new_fpstt = (env->fpstt - 1) & 7; - env->fpregs[new_fpstt] = helper_fldt((uint8_t *)A0); - env->fpstt = new_fpstt; - env->fptags[new_fpstt] = 0; /* validate stack entry */ -} - -void helper_fstt_ST0_A0(void) -{ - helper_fstt(ST0, (uint8_t *)A0); -} -#endif - -/* BCD ops */ - -#define MUL10(iv) ( iv + iv + (iv << 3) ) - -void helper_fbld_ST0_A0(void) -{ - CPU86_LDouble tmp; - uint64_t val; - unsigned int v; - int i; - - val = 0; - for(i = 8; i >= 0; i--) { - v = ldub((uint8_t *)A0 + i); - val = (val * 100) + ((v >> 4) * 10) + (v & 0xf); - } - tmp = val; - if (ldub((uint8_t *)A0 + 9) & 0x80) - tmp = -tmp; - fpush(); - ST0 = tmp; -} - -void helper_fbst_ST0_A0(void) -{ - CPU86_LDouble tmp; - int v; - uint8_t *mem_ref, *mem_end; - int64_t val; - - tmp = rint(ST0); - val = (int64_t)tmp; - mem_ref = (uint8_t *)A0; - mem_end = mem_ref + 9; - if (val < 0) { - stb(mem_end, 0x80); - val = -val; - } else { - stb(mem_end, 0x00); - } - while (mem_ref < mem_end) { - if (val == 0) - break; - v = val % 100; - val = val / 100; - v = ((v / 10) << 4) | (v % 10); - stb(mem_ref++, v); - } - while (mem_ref < mem_end) { - stb(mem_ref++, 0); - } -} - -void helper_f2xm1(void) -{ - ST0 = pow(2.0,ST0) - 1.0; -} - -void helper_fyl2x(void) -{ - CPU86_LDouble fptemp; - - fptemp = ST0; - if (fptemp>0.0){ - fptemp = log(fptemp)/log(2.0); /* log2(ST) */ - ST1 *= fptemp; - fpop(); - } else { - env->fpus &= (~0x4700); - env->fpus |= 0x400; - } -} - -void helper_fptan(void) -{ - CPU86_LDouble fptemp; - - fptemp = ST0; - if((fptemp > MAXTAN)||(fptemp < -MAXTAN)) { - env->fpus |= 0x400; - } else { - ST0 = tan(fptemp); - fpush(); - ST0 = 1.0; - env->fpus &= (~0x400); /* C2 <-- 0 */ - /* the above code is for |arg| < 2**52 only */ - } -} - -void helper_fpatan(void) -{ - CPU86_LDouble fptemp, fpsrcop; - - fpsrcop = ST1; - fptemp = ST0; - ST1 = atan2(fpsrcop,fptemp); - fpop(); -} - -void helper_fxtract(void) -{ - CPU86_LDoubleU temp; - unsigned int expdif; - - temp.d = ST0; - expdif = EXPD(temp) - EXPBIAS; - /*DP exponent bias*/ - ST0 = expdif; - fpush(); - BIASEXPONENT(temp); - ST0 = temp.d; -} - -void helper_fprem1(void) -{ - CPU86_LDouble dblq, fpsrcop, fptemp; - CPU86_LDoubleU fpsrcop1, fptemp1; - int expdif; - int q; - - fpsrcop = ST0; - fptemp = ST1; - fpsrcop1.d = fpsrcop; - fptemp1.d = fptemp; - expdif = EXPD(fpsrcop1) - EXPD(fptemp1); - if (expdif < 53) { - dblq = fpsrcop / fptemp; - dblq = (dblq < 0.0)? ceil(dblq): floor(dblq); - ST0 = fpsrcop - fptemp*dblq; - q = (int)dblq; /* cutting off top bits is assumed here */ - env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */ - /* (C0,C1,C3) <-- (q2,q1,q0) */ - env->fpus |= (q&0x4) << 6; /* (C0) <-- q2 */ - env->fpus |= (q&0x2) << 8; /* (C1) <-- q1 */ - env->fpus |= (q&0x1) << 14; /* (C3) <-- q0 */ - } else { - env->fpus |= 0x400; /* C2 <-- 1 */ - fptemp = pow(2.0, expdif-50); - fpsrcop = (ST0 / ST1) / fptemp; - /* fpsrcop = integer obtained by rounding to the nearest */ - fpsrcop = (fpsrcop-floor(fpsrcop) < ceil(fpsrcop)-fpsrcop)? - floor(fpsrcop): ceil(fpsrcop); - ST0 -= (ST1 * fpsrcop * fptemp); - } -} - -void helper_fprem(void) -{ - CPU86_LDouble dblq, fpsrcop, fptemp; - CPU86_LDoubleU fpsrcop1, fptemp1; - int expdif; - int q; - - fpsrcop = ST0; - fptemp = ST1; - fpsrcop1.d = fpsrcop; - fptemp1.d = fptemp; - expdif = EXPD(fpsrcop1) - EXPD(fptemp1); - if ( expdif < 53 ) { - dblq = fpsrcop / fptemp; - dblq = (dblq < 0.0)? ceil(dblq): floor(dblq); - ST0 = fpsrcop - fptemp*dblq; - q = (int)dblq; /* cutting off top bits is assumed here */ - env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */ - /* (C0,C1,C3) <-- (q2,q1,q0) */ - env->fpus |= (q&0x4) << 6; /* (C0) <-- q2 */ - env->fpus |= (q&0x2) << 8; /* (C1) <-- q1 */ - env->fpus |= (q&0x1) << 14; /* (C3) <-- q0 */ - } else { - env->fpus |= 0x400; /* C2 <-- 1 */ - fptemp = pow(2.0, expdif-50); - fpsrcop = (ST0 / ST1) / fptemp; - /* fpsrcop = integer obtained by chopping */ - fpsrcop = (fpsrcop < 0.0)? - -(floor(fabs(fpsrcop))): floor(fpsrcop); - ST0 -= (ST1 * fpsrcop * fptemp); - } -} - -void helper_fyl2xp1(void) -{ - CPU86_LDouble fptemp; - - fptemp = ST0; - if ((fptemp+1.0)>0.0) { - fptemp = log(fptemp+1.0) / log(2.0); /* log2(ST+1.0) */ - ST1 *= fptemp; - fpop(); - } else { - env->fpus &= (~0x4700); - env->fpus |= 0x400; - } -} - -void helper_fsqrt(void) -{ - CPU86_LDouble fptemp; - - fptemp = ST0; - if (fptemp<0.0) { - env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */ - env->fpus |= 0x400; - } - ST0 = sqrt(fptemp); -} - -void helper_fsincos(void) -{ - CPU86_LDouble fptemp; - - fptemp = ST0; - if ((fptemp > MAXTAN)||(fptemp < -MAXTAN)) { - env->fpus |= 0x400; - } else { - ST0 = sin(fptemp); - fpush(); - ST0 = cos(fptemp); - env->fpus &= (~0x400); /* C2 <-- 0 */ - /* the above code is for |arg| < 2**63 only */ - } -} - -void helper_frndint(void) -{ - CPU86_LDouble a; - - a = ST0; -#ifdef __arm__ - switch(env->fpuc & RC_MASK) { - default: - case RC_NEAR: - asm("rndd %0, %1" : "=f" (a) : "f"(a)); - break; - case RC_DOWN: - asm("rnddm %0, %1" : "=f" (a) : "f"(a)); - break; - case RC_UP: - asm("rnddp %0, %1" : "=f" (a) : "f"(a)); - break; - case RC_CHOP: - asm("rnddz %0, %1" : "=f" (a) : "f"(a)); - break; - } -#else - a = rint(a); -#endif - ST0 = a; -} - -void helper_fscale(void) -{ - CPU86_LDouble fpsrcop, fptemp; - - fpsrcop = 2.0; - fptemp = pow(fpsrcop,ST1); - ST0 *= fptemp; -} - -void helper_fsin(void) -{ - CPU86_LDouble fptemp; - - fptemp = ST0; - if ((fptemp > MAXTAN)||(fptemp < -MAXTAN)) { - env->fpus |= 0x400; - } else { - ST0 = sin(fptemp); - env->fpus &= (~0x400); /* C2 <-- 0 */ - /* the above code is for |arg| < 2**53 only */ - } -} - -void helper_fcos(void) -{ - CPU86_LDouble fptemp; - - fptemp = ST0; - if((fptemp > MAXTAN)||(fptemp < -MAXTAN)) { - env->fpus |= 0x400; - } else { - ST0 = cos(fptemp); - env->fpus &= (~0x400); /* C2 <-- 0 */ - /* the above code is for |arg5 < 2**63 only */ - } -} - -void helper_fxam_ST0(void) -{ - CPU86_LDoubleU temp; - int expdif; - - temp.d = ST0; - - env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */ - if (SIGND(temp)) - env->fpus |= 0x200; /* C1 <-- 1 */ - - expdif = EXPD(temp); - if (expdif == MAXEXPD) { - if (MANTD(temp) == 0) - env->fpus |= 0x500 /*Infinity*/; - else - env->fpus |= 0x100 /*NaN*/; - } else if (expdif == 0) { - if (MANTD(temp) == 0) - env->fpus |= 0x4000 /*Zero*/; - else - env->fpus |= 0x4400 /*Denormal*/; - } else { - env->fpus |= 0x400; - } -} - -void helper_fstenv(uint8_t *ptr, int data32) -{ - int fpus, fptag, exp, i; - uint64_t mant; - CPU86_LDoubleU tmp; - - fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11; - fptag = 0; - for (i=7; i>=0; i--) { - fptag <<= 2; - if (env->fptags[i]) { - fptag |= 3; - } else { - tmp.d = env->fpregs[i]; - exp = EXPD(tmp); - mant = MANTD(tmp); - if (exp == 0 && mant == 0) { - /* zero */ - fptag |= 1; - } else if (exp == 0 || exp == MAXEXPD -#ifdef USE_X86LDOUBLE - || (mant & (1LL << 63)) == 0 -#endif - ) { - /* NaNs, infinity, denormal */ - fptag |= 2; - } - } - } - if (data32) { - /* 32 bit */ - stl(ptr, env->fpuc); - stl(ptr + 4, fpus); - stl(ptr + 8, fptag); - stl(ptr + 12, 0); - stl(ptr + 16, 0); - stl(ptr + 20, 0); - stl(ptr + 24, 0); - } else { - /* 16 bit */ - stw(ptr, env->fpuc); - stw(ptr + 2, fpus); - stw(ptr + 4, fptag); - stw(ptr + 6, 0); - stw(ptr + 8, 0); - stw(ptr + 10, 0); - stw(ptr + 12, 0); - } -} - -void helper_fldenv(uint8_t *ptr, int data32) -{ - int i, fpus, fptag; - - if (data32) { - env->fpuc = lduw(ptr); - fpus = lduw(ptr + 4); - fptag = lduw(ptr + 8); - } - else { - env->fpuc = lduw(ptr); - fpus = lduw(ptr + 2); - fptag = lduw(ptr + 4); - } - env->fpstt = (fpus >> 11) & 7; - env->fpus = fpus & ~0x3800; - for(i = 0;i < 7; i++) { - env->fptags[i] = ((fptag & 3) == 3); - fptag >>= 2; - } -} - -void helper_fsave(uint8_t *ptr, int data32) -{ - CPU86_LDouble tmp; - int i; - - helper_fstenv(ptr, data32); - - ptr += (14 << data32); - for(i = 0;i < 8; i++) { - tmp = ST(i); -#ifdef USE_X86LDOUBLE - *(long double *)ptr = tmp; -#else - helper_fstt(tmp, ptr); -#endif - ptr += 10; - } - - /* fninit */ - env->fpus = 0; - env->fpstt = 0; - env->fpuc = 0x37f; - env->fptags[0] = 1; - env->fptags[1] = 1; - env->fptags[2] = 1; - env->fptags[3] = 1; - env->fptags[4] = 1; - env->fptags[5] = 1; - env->fptags[6] = 1; - env->fptags[7] = 1; -} - -void helper_frstor(uint8_t *ptr, int data32) -{ - CPU86_LDouble tmp; - int i; - - helper_fldenv(ptr, data32); - ptr += (14 << data32); - - for(i = 0;i < 8; i++) { -#ifdef USE_X86LDOUBLE - tmp = *(long double *)ptr; -#else - tmp = helper_fldt(ptr); -#endif - ST(i) = tmp; - ptr += 10; - } -} - -#define SHIFT 0 -#include "softmmu_template.h" - -#define SHIFT 1 -#include "softmmu_template.h" - -#define SHIFT 2 -#include "softmmu_template.h" - -#define SHIFT 3 -#include "softmmu_template.h" - -/* try to fill the TLB and return an exception if error */ -void tlb_fill(unsigned long addr, int is_write, void *retaddr) -{ - TranslationBlock *tb; - int ret; - unsigned long pc; - ret = cpu_x86_handle_mmu_fault(env, addr, is_write); - if (ret) { - /* now we have a real cpu fault */ - pc = (unsigned long)retaddr; - tb = tb_find_pc(pc); - if (tb) { - /* the PC is inside the translated code. It means that we have - a virtual CPU fault */ - cpu_restore_state(tb, env, pc); - } - raise_exception_err(EXCP0E_PAGE, env->error_code); - } -} |