ide PCI ident fix, aka FreeBSD/amd64 bug fix (Jung-uk Kim)
[qemu] / target-i386 / cpu.h
index 2b189ec..f8373a1 100644 (file)
 #ifndef CPU_I386_H
 #define CPU_I386_H
 
+#include "config.h"
+
+#ifdef TARGET_X86_64
+#define TARGET_LONG_BITS 64
+#else
 #define TARGET_LONG_BITS 32
+#endif
 
 /* target supports implicit self modifying code */
 #define TARGET_HAS_SMC
    close to the modifying instruction */
 #define TARGET_HAS_PRECISE_SMC
 
+#define TARGET_HAS_ICE 1
+
 #include "cpu-defs.h"
 
+#include "softfloat.h"
+
 #if defined(__i386__) && !defined(CONFIG_SOFTMMU)
 #define USE_CODE_COPY
 #endif
@@ -63,6 +73,8 @@
 #define DESC_G_MASK     (1 << 23)
 #define DESC_B_SHIFT    22
 #define DESC_B_MASK     (1 << DESC_B_SHIFT)
+#define DESC_L_SHIFT    21 /* x86_64 only : 64 bit code segment */
+#define DESC_L_MASK     (1 << DESC_L_SHIFT)
 #define DESC_AVL_MASK   (1 << 20)
 #define DESC_P_MASK     (1 << 15)
 #define DESC_DPL_SHIFT  13
 #define HF_EM_SHIFT         10
 #define HF_TS_SHIFT         11
 #define HF_IOPL_SHIFT       12 /* must be same as eflags */
+#define HF_LMA_SHIFT        14 /* only used on x86_64: long mode active */
+#define HF_CS64_SHIFT       15 /* only used on x86_64: 64 bit code segment  */
+#define HF_OSFXSR_SHIFT     16 /* CR4.OSFXSR */
 #define HF_VM_SHIFT         17 /* must be same as eflags */
 
 #define HF_CPL_MASK          (3 << HF_CPL_SHIFT)
 #define HF_MP_MASK           (1 << HF_MP_SHIFT)
 #define HF_EM_MASK           (1 << HF_EM_SHIFT)
 #define HF_TS_MASK           (1 << HF_TS_SHIFT)
+#define HF_LMA_MASK          (1 << HF_LMA_SHIFT)
+#define HF_CS64_MASK         (1 << HF_CS64_SHIFT)
+#define HF_OSFXSR_MASK       (1 << HF_OSFXSR_SHIFT)
 
 #define CR0_PE_MASK  (1 << 0)
 #define CR0_MP_MASK  (1 << 1)
 #define CR4_PSE_MASK  (1 << 4)
 #define CR4_PAE_MASK  (1 << 5)
 #define CR4_PGE_MASK  (1 << 7)
+#define CR4_PCE_MASK  (1 << 8)
+#define CR4_OSFXSR_MASK (1 << 9)
+#define CR4_OSXMMEXCPT_MASK  (1 << 10)
 
 #define PG_PRESENT_BIT 0
 #define PG_RW_BIT      1
 #define MSR_IA32_SYSENTER_ESP           0x175
 #define MSR_IA32_SYSENTER_EIP           0x176
 
+#define MSR_MCG_CAP                     0x179
+#define MSR_MCG_STATUS                  0x17a
+#define MSR_MCG_CTL                     0x17b
+
+#define MSR_PAT                         0x277
+
+#define MSR_EFER                        0xc0000080
+
+#define MSR_EFER_SCE   (1 << 0)
+#define MSR_EFER_LME   (1 << 8)
+#define MSR_EFER_LMA   (1 << 10)
+#define MSR_EFER_NXE   (1 << 11)
+#define MSR_EFER_FFXSR (1 << 14)
+
+#define MSR_STAR                        0xc0000081
+#define MSR_LSTAR                       0xc0000082
+#define MSR_CSTAR                       0xc0000083
+#define MSR_FMASK                       0xc0000084
+#define MSR_FSBASE                      0xc0000100
+#define MSR_GSBASE                      0xc0000101
+#define MSR_KERNELGSBASE                0xc0000102
+
+/* cpuid_features bits */
+#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_PAT  (1 << 16)
+#define CPUID_CLFLUSH (1 << 19)
+/* ... */
+#define CPUID_MMX  (1 << 23)
+#define CPUID_FXSR (1 << 24)
+#define CPUID_SSE  (1 << 25)
+#define CPUID_SSE2 (1 << 26)
+
+#define CPUID_EXT_SS3      (1 << 0)
+#define CPUID_EXT_MONITOR  (1 << 3)
+#define CPUID_EXT_CX16     (1 << 13)
+
+#define CPUID_EXT2_SYSCALL (1 << 11)
+#define CPUID_EXT2_NX      (1 << 20)
+#define CPUID_EXT2_FFXSR   (1 << 25)
+#define CPUID_EXT2_LM      (1 << 29)
+
 #define EXCP00_DIVZ    0
 #define EXCP01_SSTP    1
 #define EXCP02_NMI     2
@@ -219,86 +295,166 @@ enum {
     CC_OP_MULB, /* modify all flags, C, O = (CC_SRC != 0) */
     CC_OP_MULW,
     CC_OP_MULL,
+    CC_OP_MULQ,
 
     CC_OP_ADDB, /* modify all flags, CC_DST = res, CC_SRC = src1 */
     CC_OP_ADDW,
     CC_OP_ADDL,
+    CC_OP_ADDQ,
 
     CC_OP_ADCB, /* modify all flags, CC_DST = res, CC_SRC = src1 */
     CC_OP_ADCW,
     CC_OP_ADCL,
+    CC_OP_ADCQ,
 
     CC_OP_SUBB, /* modify all flags, CC_DST = res, CC_SRC = src1 */
     CC_OP_SUBW,
     CC_OP_SUBL,
+    CC_OP_SUBQ,
 
     CC_OP_SBBB, /* modify all flags, CC_DST = res, CC_SRC = src1 */
     CC_OP_SBBW,
     CC_OP_SBBL,
+    CC_OP_SBBQ,
 
     CC_OP_LOGICB, /* modify all flags, CC_DST = res */
     CC_OP_LOGICW,
     CC_OP_LOGICL,
+    CC_OP_LOGICQ,
 
     CC_OP_INCB, /* modify all flags except, CC_DST = res, CC_SRC = C */
     CC_OP_INCW,
     CC_OP_INCL,
+    CC_OP_INCQ,
 
     CC_OP_DECB, /* modify all flags except, CC_DST = res, CC_SRC = C  */
     CC_OP_DECW,
     CC_OP_DECL,
+    CC_OP_DECQ,
 
     CC_OP_SHLB, /* modify all flags, CC_DST = res, CC_SRC.msb = C */
     CC_OP_SHLW,
     CC_OP_SHLL,
+    CC_OP_SHLQ,
 
     CC_OP_SARB, /* modify all flags, CC_DST = res, CC_SRC.lsb = C */
     CC_OP_SARW,
     CC_OP_SARL,
+    CC_OP_SARQ,
 
     CC_OP_NB,
 };
 
-#if (defined(__i386__) || defined(__x86_64__)) && !defined(_BSD)
+#ifdef FLOATX80
 #define USE_X86LDOUBLE
 #endif
 
 #ifdef USE_X86LDOUBLE
-typedef long double CPU86_LDouble;
+typedef floatx80 CPU86_LDouble;
 #else
-typedef double CPU86_LDouble;
+typedef float64 CPU86_LDouble;
 #endif
 
 typedef struct SegmentCache {
     uint32_t selector;
-    uint8_t *base;
+    target_ulong base;
     uint32_t limit;
     uint32_t flags;
 } SegmentCache;
 
+typedef union {
+    uint8_t _b[16];
+    uint16_t _w[8];
+    uint32_t _l[4];
+    uint64_t _q[2];
+    float32 _s[4];
+    float64 _d[2];
+} XMMReg;
+
+typedef union {
+    uint8_t _b[8];
+    uint16_t _w[2];
+    uint32_t _l[1];
+    uint64_t q;
+} MMXReg;
+
+#ifdef WORDS_BIGENDIAN
+#define XMM_B(n) _b[15 - (n)]
+#define XMM_W(n) _w[7 - (n)]
+#define XMM_L(n) _l[3 - (n)]
+#define XMM_S(n) _s[3 - (n)]
+#define XMM_Q(n) _q[1 - (n)]
+#define XMM_D(n) _d[1 - (n)]
+
+#define MMX_B(n) _b[7 - (n)]
+#define MMX_W(n) _w[3 - (n)]
+#define MMX_L(n) _l[1 - (n)]
+#else
+#define XMM_B(n) _b[n]
+#define XMM_W(n) _w[n]
+#define XMM_L(n) _l[n]
+#define XMM_S(n) _s[n]
+#define XMM_Q(n) _q[n]
+#define XMM_D(n) _d[n]
+
+#define MMX_B(n) _b[n]
+#define MMX_W(n) _w[n]
+#define MMX_L(n) _l[n]
+#endif
+#define MMX_Q(n) q
+
+#ifdef TARGET_X86_64
+#define CPU_NB_REGS 16
+#else
+#define CPU_NB_REGS 8
+#endif
+
 typedef struct CPUX86State {
+#if TARGET_LONG_BITS > HOST_LONG_BITS
+    /* temporaries if we cannot store them in host registers */
+    target_ulong t0, t1, t2;
+#endif
+
     /* standard registers */
-    uint32_t regs[8];
-    uint32_t eip;
-    uint32_t eflags; /* eflags register. During CPU emulation, CC
+    target_ulong regs[CPU_NB_REGS];
+    target_ulong eip;
+    target_ulong eflags; /* eflags register. During CPU emulation, CC
                         flags and DF are set to zero because they are
                         stored elsewhere */
 
     /* emulator internal eflags handling */
-    uint32_t cc_src;
-    uint32_t cc_dst;
+    target_ulong cc_src;
+    target_ulong cc_dst;
     uint32_t cc_op;
     int32_t df; /* D flag : 1 if D = 0, -1 if D = 1 */
     uint32_t hflags; /* hidden flags, see HF_xxx constants */
 
+    /* segments */
+    SegmentCache segs[6]; /* selector values */
+    SegmentCache ldt;
+    SegmentCache tr;
+    SegmentCache gdt; /* only base and limit are used */
+    SegmentCache idt; /* only base and limit are used */
+
+    target_ulong cr[5]; /* NOTE: cr1 is unused */
+    uint32_t a20_mask;
+
     /* FPU state */
     unsigned int fpstt; /* top of stack index */
     unsigned int fpus;
     unsigned int fpuc;
     uint8_t fptags[8];   /* 0 = valid, 1 = empty */
-    CPU86_LDouble fpregs[8];
+    union {
+#ifdef USE_X86LDOUBLE
+        CPU86_LDouble d __attribute__((aligned(16)));
+#else
+        CPU86_LDouble d;
+#endif
+        MMXReg mmx;
+    } fpregs[8];
 
     /* emulator internal variables */
+    float_status fp_status;
     CPU86_LDouble ft0;
     union {
        float f;
@@ -307,17 +463,26 @@ typedef struct CPUX86State {
         int64_t i64;
     } fp_convert;
     
-    /* segments */
-    SegmentCache segs[6]; /* selector values */
-    SegmentCache ldt;
-    SegmentCache tr;
-    SegmentCache gdt; /* only base and limit are used */
-    SegmentCache idt; /* only base and limit are used */
-    
+    float_status sse_status;
+    uint32_t mxcsr;
+    XMMReg xmm_regs[CPU_NB_REGS];
+    XMMReg xmm_t0;
+    MMXReg mmx_t0;
+
     /* sysenter registers */
     uint32_t sysenter_cs;
     uint32_t sysenter_esp;
     uint32_t sysenter_eip;
+    uint64_t efer;
+    uint64_t star;
+#ifdef TARGET_X86_64
+    target_ulong lstar;
+    target_ulong cstar;
+    target_ulong fmask;
+    target_ulong kernelgsbase;
+#endif
+
+    uint64_t pat;
 
     /* temporary data for USE_CODE_COPY mode */
 #ifdef USE_CODE_COPY
@@ -331,46 +496,52 @@ typedef struct CPUX86State {
     int exception_index;
     int error_code;
     int exception_is_int;
-    int exception_next_eip;
+    target_ulong exception_next_eip;
     struct TranslationBlock *current_tb; /* currently executing TB */
-    uint32_t cr[5]; /* NOTE: cr1 is unused */
-    uint32_t dr[8]; /* debug registers */
+    target_ulong dr[8]; /* debug registers */
     int interrupt_request; 
     int user_mode_only; /* user mode only simulation */
 
-    uint32_t a20_mask;
-
     /* soft mmu support */
     /* in order to avoid passing too many arguments to the memory
        write helpers, we store some rarely used information in the CPU
        context) */
     unsigned long mem_write_pc; /* host pc at which the memory was
                                    written */
-    unsigned long mem_write_vaddr; /* target virtual addr at which the
-                                      memory was written */
+    target_ulong mem_write_vaddr; /* target virtual addr at which the
+                                     memory was written */
     /* 0 = kernel, 1 = user */
     CPUTLBEntry tlb_read[2][CPU_TLB_SIZE];
     CPUTLBEntry tlb_write[2][CPU_TLB_SIZE];
     
     /* from this point: preserved by CPU reset */
     /* ice debug support */
-    uint32_t breakpoints[MAX_BREAKPOINTS];
+    target_ulong breakpoints[MAX_BREAKPOINTS];
     int nb_breakpoints;
     int singlestep_enabled;
 
+    /* processor features (e.g. for CPUID insn) */
+    uint32_t cpuid_level;
+    uint32_t cpuid_vendor1;
+    uint32_t cpuid_vendor2;
+    uint32_t cpuid_vendor3;
+    uint32_t cpuid_version;
+    uint32_t cpuid_features;
+    uint32_t cpuid_ext_features;
+    uint32_t cpuid_xlevel;
+    uint32_t cpuid_model[12];
+    uint32_t cpuid_ext2_features;
+    
+#ifdef USE_KQEMU
+    int kqemu_enabled;
+#endif
+    /* in order to simplify APIC support, we leave this pointer to the
+       user */
+    struct APICState *apic_state;
     /* user data */
     void *opaque;
 } CPUX86State;
 
-#ifndef IN_OP_I386
-void cpu_x86_outb(CPUX86State *env, int addr, int val);
-void cpu_x86_outw(CPUX86State *env, int addr, int val);
-void cpu_x86_outl(CPUX86State *env, int addr, int val);
-int cpu_x86_inb(CPUX86State *env, int addr);
-int cpu_x86_inw(CPUX86State *env, int addr);
-int cpu_x86_inl(CPUX86State *env, int addr);
-#endif
-
 CPUX86State *cpu_x86_init(void);
 int cpu_x86_exec(CPUX86State *s);
 void cpu_x86_close(CPUX86State *s);
@@ -382,7 +553,7 @@ void cpu_set_ferr(CPUX86State *s);
    cache: it synchronizes the hflags with the segment cache values */
 static inline void cpu_x86_load_seg_cache(CPUX86State *env, 
                                           int seg_reg, unsigned int selector,
-                                          uint8_t *base, unsigned int limit, 
+                                          uint32_t base, unsigned int limit, 
                                           unsigned int flags)
 {
     SegmentCache *sc;
@@ -395,27 +566,45 @@ static inline void cpu_x86_load_seg_cache(CPUX86State *env,
     sc->flags = flags;
 
     /* update the hidden flags */
-    new_hflags = (env->segs[R_CS].flags & DESC_B_MASK)
-        >> (DESC_B_SHIFT - HF_CS32_SHIFT);
-    new_hflags |= (env->segs[R_SS].flags & DESC_B_MASK)
-        >> (DESC_B_SHIFT - HF_SS32_SHIFT);
-    if (!(env->cr[0] & CR0_PE_MASK) || 
-        (env->eflags & VM_MASK) ||
-        !(new_hflags & HF_CS32_MASK)) {
-        /* XXX: try to avoid this test. The problem comes from the
-           fact that is real mode or vm86 mode we only modify the
-           'base' and 'selector' fields of the segment cache to go
-           faster. A solution may be to force addseg to one in
-           translate-i386.c. */
-        new_hflags |= HF_ADDSEG_MASK;
-    } else {
-        new_hflags |= (((unsigned long)env->segs[R_DS].base | 
-                        (unsigned long)env->segs[R_ES].base |
-                        (unsigned long)env->segs[R_SS].base) != 0) << 
-            HF_ADDSEG_SHIFT;
+    {
+        if (seg_reg == R_CS) {
+#ifdef TARGET_X86_64
+            if ((env->hflags & HF_LMA_MASK) && (flags & DESC_L_MASK)) {
+                /* long mode */
+                env->hflags |= HF_CS32_MASK | HF_SS32_MASK | HF_CS64_MASK;
+                env->hflags &= ~(HF_ADDSEG_MASK);
+            } else 
+#endif
+            {
+                /* legacy / compatibility case */
+                new_hflags = (env->segs[R_CS].flags & DESC_B_MASK)
+                    >> (DESC_B_SHIFT - HF_CS32_SHIFT);
+                env->hflags = (env->hflags & ~(HF_CS32_MASK | HF_CS64_MASK)) |
+                    new_hflags;
+            }
+        }
+        new_hflags = (env->segs[R_SS].flags & DESC_B_MASK)
+            >> (DESC_B_SHIFT - HF_SS32_SHIFT);
+        if (env->hflags & HF_CS64_MASK) {
+            /* zero base assumed for DS, ES and SS in long mode */
+        } else if (!(env->cr[0] & CR0_PE_MASK) || 
+                   (env->eflags & VM_MASK) ||
+                   !(env->hflags & HF_CS32_MASK)) {
+            /* XXX: try to avoid this test. The problem comes from the
+               fact that is real mode or vm86 mode we only modify the
+               'base' and 'selector' fields of the segment cache to go
+               faster. A solution may be to force addseg to one in
+               translate-i386.c. */
+            new_hflags |= HF_ADDSEG_MASK;
+        } else {
+            new_hflags |= ((env->segs[R_DS].base | 
+                            env->segs[R_ES].base |
+                            env->segs[R_SS].base) != 0) << 
+                HF_ADDSEG_SHIFT;
+        }
+        env->hflags = (env->hflags & 
+                       ~(HF_SS32_MASK | HF_ADDSEG_MASK)) | new_hflags;
     }
-    env->hflags = (env->hflags & 
-                   ~(HF_CS32_MASK | HF_SS32_MASK | HF_ADDSEG_MASK)) | new_hflags;
 }
 
 /* wrapper, just in case memory mappings must be changed */
@@ -448,6 +637,13 @@ void cpu_x86_set_a20(CPUX86State *env, int a20_state);
 
 uint64_t cpu_get_tsc(CPUX86State *env);
 
+void cpu_set_apic_base(CPUX86State *env, uint64_t val);
+uint64_t cpu_get_apic_base(CPUX86State *env);
+void cpu_set_apic_tpr(CPUX86State *env, uint8_t val);
+#ifndef NO_CPU_IO_DEFS
+uint8_t cpu_get_apic_tpr(CPUX86State *env);
+#endif
+
 /* will be suppressed */
 void cpu_x86_update_cr0(CPUX86State *env, uint32_t new_cr0);