]> git.proxmox.com Git - qemu.git/blobdiff - cpu-i386.h
update
[qemu.git] / cpu-i386.h
index dbe18519bc6fdc11bef622a589867de01be602f1..008ff8cd2b77d22563957cb68fe7cea12d4f77f9 100644 (file)
@@ -1,5 +1,21 @@
-/* NOTE: this header is included in op-i386.c where global register
-   variable are used. Care must be used when including glibc headers.
+/*
+ * i386 virtual CPU header
+ * 
+ *  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
  */
 #ifndef CPU_I386_H
 #define CPU_I386_H
@@ -32,6 +48,7 @@
 #define R_FS 4
 #define R_GS 5
 
+/* eflags masks */
 #define CC_C           0x0001
 #define CC_P   0x0004
 #define CC_A   0x0010
 #define CC_S    0x0080
 #define CC_O    0x0800
 
-#define TRAP_FLAG              0x0100
-#define INTERRUPT_FLAG         0x0200
-#define DIRECTION_FLAG         0x0400
-#define IOPL_FLAG_MASK         0x3000
-#define NESTED_FLAG            0x4000
-#define BYTE_FL                        0x8000  /* Intel reserved! */
-#define RF_FLAG                        0x10000
-#define VM_FLAG                        0x20000
-/* AC                          0x40000 */
-
-#define EXCP00_DIVZ    1
-#define EXCP01_SSTP    2
-#define EXCP02_NMI     3
-#define EXCP03_INT3    4
-#define EXCP04_INTO    5
-#define EXCP05_BOUND   6
-#define EXCP06_ILLOP   7
-#define EXCP07_PREX    8
-#define EXCP08_DBLE    9
-#define EXCP09_XERR    10
-#define EXCP0A_TSS     11
-#define EXCP0B_NOSEG   12
-#define EXCP0C_STACK   13
-#define EXCP0D_GPF     14
-#define EXCP0E_PAGE    15
-#define EXCP10_COPR    17
-#define EXCP11_ALGN    18
-#define EXCP12_MCHK    19
+#define TF_MASK                0x00000100
+#define IF_MASK                0x00000200
+#define DF_MASK                0x00000400
+#define IOPL_MASK              0x00003000
+#define NT_MASK                        0x00004000
+#define RF_MASK                        0x00010000
+#define VM_MASK                        0x00020000
+#define AC_MASK                        0x00040000 
+#define VIF_MASK                0x00080000
+#define VIP_MASK                0x00100000
+#define ID_MASK                 0x00200000
+
+#define EXCP00_DIVZ    0
+#define EXCP01_SSTP    1
+#define EXCP02_NMI     2
+#define EXCP03_INT3    3
+#define EXCP04_INTO    4
+#define EXCP05_BOUND   5
+#define EXCP06_ILLOP   6
+#define EXCP07_PREX    7
+#define EXCP08_DBLE    8
+#define EXCP09_XERR    9
+#define EXCP0A_TSS     10
+#define EXCP0B_NOSEG   11
+#define EXCP0C_STACK   12
+#define EXCP0D_GPF     13
+#define EXCP0E_PAGE    14
+#define EXCP10_COPR    16
+#define EXCP11_ALGN    17
+#define EXCP12_MCHK    18
 
 #define EXCP_INTERRUPT         256 /* async interruption */
 
@@ -142,7 +161,9 @@ typedef struct CPUX86State {
     /* standard registers */
     uint32_t regs[8];
     uint32_t eip;
-    uint32_t eflags;
+    uint32_t 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;
@@ -159,6 +180,12 @@ typedef struct CPUX86State {
 
     /* emulator internal variables */
     CPU86_LDouble ft0;
+    union {
+       float f;
+        double d;
+       int i32;
+        int64_t i64;
+    } fp_convert;
     
     /* segments */
     uint32_t segs[6]; /* selector values */
@@ -167,13 +194,15 @@ typedef struct CPUX86State {
     SegmentDescriptorTable ldt;
     SegmentDescriptorTable idt;
     
-    /* various CPU modes */
-    int vm86;
-
     /* exception/interrupt handling */
     jmp_buf jmp_env;
     int exception_index;
+    int error_code;
+    uint32_t cr2;
     int interrupt_request;
+
+    /* user data */
+    void *opaque;
 } CPUX86State;
 
 /* all CPU memory access use these macros */
@@ -374,12 +403,12 @@ static inline void stfq(void *ptr, double v)
 #endif
 
 #ifndef IN_OP_I386
-void cpu_x86_outb(int addr, int val);
-void cpu_x86_outw(int addr, int val);
-void cpu_x86_outl(int addr, int val);
-int cpu_x86_inb(int addr);
-int cpu_x86_inw(int addr);
-int cpu_x86_inl(int addr);
+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);
@@ -390,23 +419,227 @@ void cpu_x86_close(CPUX86State *s);
 /* needed to load some predefinied segment registers */
 void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector);
 
-/* you can call these signal handler from you SIGBUS and SIGSEGV
+/* you can call this signal handler from your SIGBUS and SIGSEGV
    signal handlers to inform the virtual CPU of exceptions. non zero
    is returned if the signal was handled by the virtual CPU.  */
 struct siginfo;
 int cpu_x86_signal_handler(int host_signum, struct siginfo *info, 
                            void *puc);
 
+/* used to debug */
+#define X86_DUMP_FPU  0x0001 /* dump FPU state too */
+#define X86_DUMP_CCOP 0x0002 /* dump qemu flag cache */
+void cpu_x86_dump_state(CPUX86State *env, FILE *f, int flags);
+
+/* page related stuff */
+#define TARGET_PAGE_BITS 12
+#define TARGET_PAGE_SIZE (1 << TARGET_PAGE_BITS)
+#define TARGET_PAGE_MASK ~(TARGET_PAGE_SIZE - 1)
+#define TARGET_PAGE_ALIGN(addr) (((addr) + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK)
+
+extern unsigned long real_host_page_size;
+extern unsigned long host_page_bits;
+extern unsigned long host_page_size;
+extern unsigned long host_page_mask;
+
+#define HOST_PAGE_ALIGN(addr) (((addr) + host_page_size - 1) & host_page_mask)
+
+/* same as PROT_xxx */
+#define PAGE_READ      0x0001
+#define PAGE_WRITE     0x0002
+#define PAGE_EXEC      0x0004
+#define PAGE_BITS      (PAGE_READ | PAGE_WRITE | PAGE_EXEC)
+#define PAGE_VALID     0x0008
+/* original state of the write flag (used when tracking self-modifying
+   code */
+#define PAGE_WRITE_ORG 0x0010 
+
+void page_dump(FILE *f);
+int page_get_flags(unsigned long address);
+void page_set_flags(unsigned long start, unsigned long end, int flags);
+void page_unprotect_range(uint8_t *data, unsigned long data_size);
+
+/***************************************************/
 /* internal functions */
 
 #define GEN_FLAG_CODE32_SHIFT 0
 #define GEN_FLAG_ADDSEG_SHIFT 1
 #define GEN_FLAG_SS32_SHIFT   2
-#define GEN_FLAG_ST_SHIFT     3
+#define GEN_FLAG_VM_SHIFT     3
+#define GEN_FLAG_ST_SHIFT     4
+#define GEN_FLAG_CPL_SHIFT    7
+#define GEN_FLAG_IOPL_SHIFT   9
+#define GEN_FLAG_TF_SHIFT     11
 
 int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size, 
                      int *gen_code_size_ptr,
-                     uint8_t *pc_start,  uint8_t *cs_base, int flags);
+                     uint8_t *pc_start,  uint8_t *cs_base, int flags,
+                     int *code_size_ptr);
 void cpu_x86_tblocks_init(void);
+void page_init(void);
+int page_unprotect(unsigned long address);
+
+#define CODE_GEN_MAX_SIZE        65536
+#define CODE_GEN_ALIGN           16 /* must be >= of the size of a icache line */
+
+#define CODE_GEN_HASH_BITS     15
+#define CODE_GEN_HASH_SIZE     (1 << CODE_GEN_HASH_BITS)
+
+/* maximum total translate dcode allocated */
+#define CODE_GEN_BUFFER_SIZE     (2048 * 1024)
+//#define CODE_GEN_BUFFER_SIZE     (128 * 1024)
+
+typedef struct TranslationBlock {
+    unsigned long pc;   /* simulated PC corresponding to this block (EIP + CS base) */
+    unsigned long cs_base; /* CS base for this block */
+    unsigned int flags; /* flags defining in which context the code was generated */
+    uint16_t size;      /* size of target code for this block (1 <=
+                           size <= TARGET_PAGE_SIZE) */
+    uint8_t *tc_ptr;    /* pointer to the translated code */
+    struct TranslationBlock *hash_next; /* next matching block */
+    struct TranslationBlock *page_next[2]; /* next blocks in even/odd page */
+} TranslationBlock;
+
+static inline unsigned int tb_hash_func(unsigned long pc)
+{
+    return pc & (CODE_GEN_HASH_SIZE - 1);
+}
+
+void tb_flush(void);
+TranslationBlock *tb_alloc(unsigned long pc, 
+                           unsigned long size);
+
+extern TranslationBlock *tb_hash[CODE_GEN_HASH_SIZE];
+
+extern uint8_t code_gen_buffer[CODE_GEN_BUFFER_SIZE];
+extern uint8_t *code_gen_ptr;
+
+/* find a translation block in the translation cache. If not found,
+   return NULL and the pointer to the last element of the list in pptb */
+static inline TranslationBlock *tb_find(TranslationBlock ***pptb,
+                                        unsigned long pc, 
+                                        unsigned long cs_base,
+                                        unsigned int flags)
+{
+    TranslationBlock **ptb, *tb;
+    unsigned int h;
+    h = tb_hash_func(pc);
+    ptb = &tb_hash[h];
+    for(;;) {
+        tb = *ptb;
+        if (!tb)
+            break;
+        if (tb->pc == pc && tb->cs_base == cs_base && tb->flags == flags)
+            return tb;
+        ptb = &tb->hash_next;
+    }
+    *pptb = ptb;
+    return NULL;
+}
+
+#ifndef offsetof
+#define offsetof(type, field) ((size_t) &((type *)0)->field)
+#endif
+
+#ifdef __powerpc__
+static inline int testandset (int *p)
+{
+    int ret;
+    __asm__ __volatile__ (
+                          "0:    lwarx %0,0,%1 ;"
+                          "      xor. %0,%3,%0;"
+                          "      bne 1f;"
+                          "      stwcx. %2,0,%1;"
+                          "      bne- 0b;"
+                          "1:    "
+                          : "=&r" (ret)
+                          : "r" (p), "r" (1), "r" (0)
+                          : "cr0", "memory");
+    return ret;
+}
+#endif
+
+#ifdef __i386__
+static inline int testandset (int *p)
+{
+    char ret;
+    long int readval;
+    
+    __asm__ __volatile__ ("lock; cmpxchgl %3, %1; sete %0"
+                          : "=q" (ret), "=m" (*p), "=a" (readval)
+                          : "r" (1), "m" (*p), "a" (0)
+                          : "memory");
+    return ret;
+}
+#endif
+
+#ifdef __s390__
+static inline int testandset (int *p)
+{
+    int ret;
+
+    __asm__ __volatile__ ("0: cs    %0,%1,0(%2)\n"
+                         "   jl    0b"
+                         : "=&d" (ret)
+                         : "r" (1), "a" (p), "0" (*p) 
+                         : "cc", "memory" );
+    return ret;
+}
+#endif
+
+#ifdef __alpha__
+int testandset (int *p)
+{
+    int ret;
+    unsigned long one;
+
+    __asm__ __volatile__ ("0:  mov 1,%2\n"
+                         "     ldl_l %0,%1\n"
+                         "     stl_c %2,%1\n"
+                         "     beq %2,1f\n"
+                         ".subsection 2\n"
+                         "1:   br 0b\n"
+                         ".previous"
+                         : "=r" (ret), "=m" (*p), "=r" (one)
+                         : "m" (*p));
+    return ret;
+}
+#endif
+
+#ifdef __sparc__
+static inline int testandset (int *p)
+{
+       int ret;
+
+       __asm__ __volatile__("ldstub    [%1], %0"
+                            : "=r" (ret)
+                            : "r" (p)
+                            : "memory");
+
+       return (ret ? 1 : 0);
+}
+#endif
+
+typedef int spinlock_t;
+
+#define SPIN_LOCK_UNLOCKED 0
+
+static inline void spin_lock(spinlock_t *lock)
+{
+    while (testandset(lock));
+}
+
+static inline void spin_unlock(spinlock_t *lock)
+{
+    *lock = 0;
+}
+
+static inline int spin_trylock(spinlock_t *lock)
+{
+    return !testandset(lock);
+}
+
+extern spinlock_t tb_lock;
 
 #endif /* CPU_I386_H */