*/
#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);
+}
+
#if 0
/* full interrupt support (only useful for real CPU emulation, not
finished) - I won't do it any time soon, finish it if you want ! */
break;
}
dpl = (e2 >> DESC_DPL_SHIFT) & 3;
- cpl = env->segs[R_CS] & 3;
+ cpl = env->segs[R_CS].selector & 3;
/* check privledge if software int */
if (is_int && dpl < cpl)
raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
void raise_interrupt(int intno, int is_int, int error_code,
unsigned int next_eip)
{
- SegmentDescriptorTable *dt;
+ SegmentCache *dt;
uint8_t *ptr;
int dpl, cpl;
uint32_t e2;
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)
}
}
+static inline void load_seg_cache(SegmentCache *sc, uint32_t e1, uint32_t e2)
+{
+ sc->base = (void *)((e1 >> 16) | ((e2 & 0xff) << 16) | (e2 & 0xff000000));
+ sc->limit = (e1 & 0xffff) | (e2 & 0x000f0000);
+ if (e2 & (1 << 23))
+ sc->limit = (sc->limit << 12) | 0xfff;
+ sc->seg_32bit = (e2 >> 22) & 1;
+}
+
+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(&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) {
+ /* XXX: NULL selector case: invalid LDT */
+ env->tr.base = NULL;
+ env->tr.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);
+ 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(&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 */
-void load_seg(int seg_reg, int selector, unsigned cur_eip)
+void load_seg(int seg_reg, int selector, unsigned int cur_eip)
{
SegmentCache *sc;
- SegmentDescriptorTable *dt;
+ SegmentCache *dt;
int index;
uint32_t e1, e2;
uint8_t *ptr;
-
- sc = &env->seg_cache[seg_reg];
+
+ sc = &env->segs[seg_reg];
if ((selector & 0xfffc) == 0) {
/* null selector case */
if (seg_reg == R_SS) {
EIP = cur_eip;
- raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
+ raise_exception_err(EXCP0D_GPF, 0);
} else {
/* XXX: each access should trigger an exception */
sc->base = NULL;
else
raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
}
-
- sc->base = (void *)((e1 >> 16) | ((e2 & 0xff) << 16) | (e2 & 0xff000000));
- sc->limit = (e1 & 0xffff) | (e2 & 0x000f0000);
- if (e2 & (1 << 23))
- sc->limit = (sc->limit << 12) | 0xfff;
- sc->seg_32bit = (e2 >> 22) & 1;
+ load_seg_cache(sc, e1, e2);
#if 0
fprintf(logfile, "load_seg: sel=0x%04x base=0x%08lx limit=0x%08lx seg_32bit=%d\n",
selector, (unsigned long)sc->base, sc->limit, sc->seg_32bit);
#endif
}
- env->segs[seg_reg] = selector;
+ sc->selector = selector;
+}
+
+/* protected mode jump */
+void jmp_seg(int selector, unsigned int new_eip)
+{
+ SegmentCache sc1;
+ SegmentCache *dt;
+ int index;
+ uint32_t e1, e2, cpl, dpl, rpl;
+ uint8_t *ptr;
+
+ if ((selector & 0xfffc) == 0) {
+ raise_exception_err(EXCP0D_GPF, 0);
+ }
+
+ if (selector & 0x4)
+ dt = &env->ldt;
+ else
+ 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);
+ cpl = env->segs[R_CS].selector & 3;
+ if (e2 & DESC_S_MASK) {
+ if (!(e2 & DESC_CS_MASK))
+ raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
+ dpl = (e2 >> DESC_DPL_SHIFT) & 3;
+ if (e2 & DESC_CS_MASK) {
+ /* conforming code segment */
+ if (dpl > cpl)
+ raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
+ } else {
+ /* non conforming code segment */
+ rpl = selector & 3;
+ if (rpl > cpl)
+ raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
+ if (dpl != cpl)
+ raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
+ }
+ if (!(e2 & DESC_P_MASK))
+ raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
+ load_seg_cache(&sc1, e1, e2);
+ if (new_eip > sc1.limit)
+ raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
+ env->segs[R_CS] = sc1;
+ env->segs[R_CS].selector = (selector & 0xfffc) | cpl;
+ EIP = new_eip;
+ } else {
+ cpu_abort(env, "jmp to call/task gate not supported 0x%04x:0x%08x",
+ selector, new_eip);
+ }
+}
+
+/* XXX: do more */
+void helper_movl_crN_T0(int reg)
+{
+ switch(reg) {
+ case 0:
+ default:
+ env->cr[0] = reg;
+ break;
+ case 2:
+ env->cr[2] = reg;
+ break;
+ case 3:
+ env->cr[3] = reg;
+ break;
+ case 4:
+ env->cr[4] = reg;
+ break;
+ }
+}
+
+/* XXX: do more */
+void helper_movl_drN_T0(int reg)
+{
+ env->dr[reg] = T0;
+}
+
+/* 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_lsl(void)
{
unsigned int selector, limit;
- SegmentDescriptorTable *dt;
+ SegmentCache *dt;
int index;
uint32_t e1, e2;
uint8_t *ptr;
void helper_lar(void)
{
unsigned int selector;
- SegmentDescriptorTable *dt;
+ SegmentCache *dt;
int index;
uint32_t e2;
uint8_t *ptr;
void helper_frndint(void)
{
- ST0 = rint(ST0);
+ 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)