Statistics
| Branch: | Revision:

root / exec-i386.c @ 1b6b029e

History | View | Annotate | Download (9.5 kB)

1
/*
2
 *  i386 emulator main execution loop
3
 * 
4
 *  Copyright (c) 2003 Fabrice Bellard
5
 *
6
 *  This program is free software; you can redistribute it and/or modify
7
 *  it under the terms of the GNU General Public License as published by
8
 *  the Free Software Foundation; either version 2 of the License, or
9
 *  (at your option) any later version.
10
 *
11
 *  This program 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
14
 *  GNU General Public License for more details.
15
 *
16
 *  You should have received a copy of the GNU General Public License
17
 *  along with this program; if not, write to the Free Software
18
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19
 */
20
#include "exec-i386.h"
21

    
22
//#define DEBUG_EXEC
23
#define DEBUG_FLUSH
24

    
25
/* main execution loop */
26

    
27
/* maximum total translate dcode allocated */
28
#define CODE_GEN_BUFFER_SIZE     (2048 * 1024)
29
//#define CODE_GEN_BUFFER_SIZE     (128 * 1024)
30
#define CODE_GEN_MAX_SIZE        65536
31
#define CODE_GEN_ALIGN           16 /* must be >= of the size of a icache line */
32

    
33
/* threshold to flush the translated code buffer */
34
#define CODE_GEN_BUFFER_MAX_SIZE (CODE_GEN_BUFFER_SIZE - CODE_GEN_MAX_SIZE)
35

    
36
#define CODE_GEN_MAX_BLOCKS    (CODE_GEN_BUFFER_SIZE / 64)
37
#define CODE_GEN_HASH_BITS     15
38
#define CODE_GEN_HASH_SIZE     (1 << CODE_GEN_HASH_BITS)
39

    
40
typedef struct TranslationBlock {
41
    unsigned long pc;   /* simulated PC corresponding to this block (EIP + CS base) */
42
    unsigned long cs_base; /* CS base for this block */
43
    unsigned int flags; /* flags defining in which context the code was generated */
44
    uint8_t *tc_ptr;    /* pointer to the translated code */
45
    struct TranslationBlock *hash_next; /* next matching block */
46
} TranslationBlock;
47

    
48
TranslationBlock tbs[CODE_GEN_MAX_BLOCKS];
49
TranslationBlock *tb_hash[CODE_GEN_HASH_SIZE];
50
int nb_tbs;
51

    
52
uint8_t code_gen_buffer[CODE_GEN_BUFFER_SIZE];
53
uint8_t *code_gen_ptr;
54

    
55
/* thread support */
56

    
57
#ifdef __powerpc__
58
static inline int testandset (int *p)
59
{
60
    int ret;
61
    __asm__ __volatile__ (
62
                          "0:    lwarx %0,0,%1 ;"
63
                          "      xor. %0,%3,%0;"
64
                          "      bne 1f;"
65
                          "      stwcx. %2,0,%1;"
66
                          "      bne- 0b;"
67
                          "1:    "
68
                          : "=&r" (ret)
69
                          : "r" (p), "r" (1), "r" (0)
70
                          : "cr0", "memory");
71
    return ret;
72
}
73
#endif
74

    
75
#ifdef __i386__
76
static inline int testandset (int *p)
77
{
78
    char ret;
79
    long int readval;
80
    
81
    __asm__ __volatile__ ("lock; cmpxchgl %3, %1; sete %0"
82
                          : "=q" (ret), "=m" (*p), "=a" (readval)
83
                          : "r" (1), "m" (*p), "a" (0)
84
                          : "memory");
85
    return ret;
86
}
87
#endif
88

    
89
int global_cpu_lock = 0;
90

    
91
void cpu_lock(void)
92
{
93
    while (testandset(&global_cpu_lock));
94
}
95

    
96
void cpu_unlock(void)
97
{
98
    global_cpu_lock = 0;
99
}
100

    
101
#ifdef DEBUG_EXEC
102
static const char *cc_op_str[] = {
103
    "DYNAMIC",
104
    "EFLAGS",
105
    "MUL",
106
    "ADDB",
107
    "ADDW",
108
    "ADDL",
109
    "ADCB",
110
    "ADCW",
111
    "ADCL",
112
    "SUBB",
113
    "SUBW",
114
    "SUBL",
115
    "SBBB",
116
    "SBBW",
117
    "SBBL",
118
    "LOGICB",
119
    "LOGICW",
120
    "LOGICL",
121
    "INCB",
122
    "INCW",
123
    "INCL",
124
    "DECB",
125
    "DECW",
126
    "DECL",
127
    "SHLB",
128
    "SHLW",
129
    "SHLL",
130
    "SARB",
131
    "SARW",
132
    "SARL",
133
};
134

    
135
static void cpu_x86_dump_state(void)
136
{
137
    int eflags;
138
    eflags = cc_table[CC_OP].compute_all();
139
    eflags |= (DF & DIRECTION_FLAG);
140
    fprintf(logfile, 
141
            "EAX=%08x EBX=%08X ECX=%08x EDX=%08x\n"
142
            "ESI=%08x EDI=%08X EBP=%08x ESP=%08x\n"
143
            "CCS=%08x CCD=%08x CCO=%-8s EFL=%c%c%c%c%c%c%c\n",
144
            env->regs[R_EAX], env->regs[R_EBX], env->regs[R_ECX], env->regs[R_EDX], 
145
            env->regs[R_ESI], env->regs[R_EDI], env->regs[R_EBP], env->regs[R_ESP], 
146
            env->cc_src, env->cc_dst, cc_op_str[env->cc_op],
147
            eflags & DIRECTION_FLAG ? 'D' : '-',
148
            eflags & CC_O ? 'O' : '-',
149
            eflags & CC_S ? 'S' : '-',
150
            eflags & CC_Z ? 'Z' : '-',
151
            eflags & CC_A ? 'A' : '-',
152
            eflags & CC_P ? 'P' : '-',
153
            eflags & CC_C ? 'C' : '-'
154
            );
155
#if 1
156
    fprintf(logfile, "ST0=%f ST1=%f ST2=%f ST3=%f\n", 
157
            (double)ST0, (double)ST1, (double)ST(2), (double)ST(3));
158
#endif
159
}
160

    
161
#endif
162

    
163
void cpu_x86_tblocks_init(void)
164
{
165
    if (!code_gen_ptr) {
166
        code_gen_ptr = code_gen_buffer;
167
    }
168
}
169

    
170
/* flush all the translation blocks */
171
static void tb_flush(void)
172
{
173
    int i;
174
#ifdef DEBUG_FLUSH
175
    printf("gemu: flush code_size=%d nb_tbs=%d avg_tb_size=%d\n", 
176
           code_gen_ptr - code_gen_buffer, 
177
           nb_tbs, 
178
           (code_gen_ptr - code_gen_buffer) / nb_tbs);
179
#endif
180
    nb_tbs = 0;
181
    for(i = 0;i < CODE_GEN_HASH_SIZE; i++)
182
        tb_hash[i] = NULL;
183
    code_gen_ptr = code_gen_buffer;
184
    /* XXX: flush processor icache at this point */
185
}
186

    
187
/* find a translation block in the translation cache. If not found,
188
   allocate a new one */
189
static inline TranslationBlock *tb_find_and_alloc(unsigned long pc, 
190
                                                  unsigned long cs_base,
191
                                                  unsigned int flags)
192
{
193
    TranslationBlock **ptb, *tb;
194
    unsigned int h;
195
 
196
    h = pc & (CODE_GEN_HASH_SIZE - 1);
197
    ptb = &tb_hash[h];
198
    for(;;) {
199
        tb = *ptb;
200
        if (!tb)
201
            break;
202
        if (tb->pc == pc && tb->cs_base == cs_base && tb->flags == flags)
203
            return tb;
204
        ptb = &tb->hash_next;
205
    }
206
    if (nb_tbs >= CODE_GEN_MAX_BLOCKS || 
207
        (code_gen_ptr - code_gen_buffer) >= CODE_GEN_BUFFER_MAX_SIZE)
208
        tb_flush();
209
    tb = &tbs[nb_tbs++];
210
    *ptb = tb;
211
    tb->pc = pc;
212
    tb->cs_base = cs_base;
213
    tb->flags = flags;
214
    tb->tc_ptr = NULL;
215
    tb->hash_next = NULL;
216
    return tb;
217
}
218

    
219
int cpu_x86_exec(CPUX86State *env1)
220
{
221
    int saved_T0, saved_T1, saved_A0;
222
    CPUX86State *saved_env;
223
#ifdef reg_EAX
224
    int saved_EAX;
225
#endif
226
#ifdef reg_ECX
227
    int saved_ECX;
228
#endif
229
#ifdef reg_EDX
230
    int saved_EDX;
231
#endif
232
#ifdef reg_EBX
233
    int saved_EBX;
234
#endif
235
#ifdef reg_ESP
236
    int saved_ESP;
237
#endif
238
#ifdef reg_EBP
239
    int saved_EBP;
240
#endif
241
#ifdef reg_ESI
242
    int saved_ESI;
243
#endif
244
#ifdef reg_EDI
245
    int saved_EDI;
246
#endif
247
    int code_gen_size, ret;
248
    void (*gen_func)(void);
249
    TranslationBlock *tb;
250
    uint8_t *tc_ptr, *cs_base, *pc;
251
    unsigned int flags;
252

    
253
    /* first we save global registers */
254
    saved_T0 = T0;
255
    saved_T1 = T1;
256
    saved_A0 = A0;
257
    saved_env = env;
258
    env = env1;
259
#ifdef reg_EAX
260
    saved_EAX = EAX;
261
    EAX = env->regs[R_EAX];
262
#endif
263
#ifdef reg_ECX
264
    saved_ECX = ECX;
265
    ECX = env->regs[R_ECX];
266
#endif
267
#ifdef reg_EDX
268
    saved_EDX = EDX;
269
    EDX = env->regs[R_EDX];
270
#endif
271
#ifdef reg_EBX
272
    saved_EBX = EBX;
273
    EBX = env->regs[R_EBX];
274
#endif
275
#ifdef reg_ESP
276
    saved_ESP = ESP;
277
    ESP = env->regs[R_ESP];
278
#endif
279
#ifdef reg_EBP
280
    saved_EBP = EBP;
281
    EBP = env->regs[R_EBP];
282
#endif
283
#ifdef reg_ESI
284
    saved_ESI = ESI;
285
    ESI = env->regs[R_ESI];
286
#endif
287
#ifdef reg_EDI
288
    saved_EDI = EDI;
289
    EDI = env->regs[R_EDI];
290
#endif
291
    
292
    /* prepare setjmp context for exception handling */
293
    if (setjmp(env->jmp_env) == 0) {
294
        for(;;) {
295
#ifdef DEBUG_EXEC
296
            if (loglevel) {
297
                cpu_x86_dump_state();
298
            }
299
#endif
300
            /* we compute the CPU state. We assume it will not
301
               change during the whole generated block. */
302
            flags = env->seg_cache[R_CS].seg_32bit << GEN_FLAG_CODE32_SHIFT;
303
            flags |= env->seg_cache[R_SS].seg_32bit << GEN_FLAG_SS32_SHIFT;
304
            flags |= (((unsigned long)env->seg_cache[R_DS].base | 
305
                       (unsigned long)env->seg_cache[R_ES].base |
306
                       (unsigned long)env->seg_cache[R_SS].base) != 0) << 
307
                GEN_FLAG_ADDSEG_SHIFT;
308
            cs_base = env->seg_cache[R_CS].base;
309
            pc = cs_base + env->eip;
310
            tb = tb_find_and_alloc((unsigned long)pc, (unsigned long)cs_base, 
311
                                   flags);
312
            tc_ptr = tb->tc_ptr;
313
            if (!tb->tc_ptr) {
314
                /* if no translated code available, then translate it now */
315
                /* XXX: very inefficient: we lock all the cpus when
316
                   generating code */
317
                cpu_lock();
318
                tc_ptr = code_gen_ptr;
319
                cpu_x86_gen_code(code_gen_ptr, CODE_GEN_MAX_SIZE, 
320
                                 &code_gen_size, pc, cs_base, flags);
321
                tb->tc_ptr = tc_ptr;
322
                code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1));
323
                cpu_unlock();
324
            }
325
            /* execute the generated code */
326
            gen_func = (void *)tc_ptr;
327
            gen_func();
328
        }
329
    }
330
    ret = env->exception_index;
331

    
332
    /* restore global registers */
333
#ifdef reg_EAX
334
    EAX = saved_EAX;
335
#endif
336
#ifdef reg_ECX
337
    ECX = saved_ECX;
338
#endif
339
#ifdef reg_EDX
340
    EDX = saved_EDX;
341
#endif
342
#ifdef reg_EBX
343
    EBX = saved_EBX;
344
#endif
345
#ifdef reg_ESP
346
    ESP = saved_ESP;
347
#endif
348
#ifdef reg_EBP
349
    EBP = saved_EBP;
350
#endif
351
#ifdef reg_ESI
352
    ESI = saved_ESI;
353
#endif
354
#ifdef reg_EDI
355
    EDI = saved_EDI;
356
#endif
357
    T0 = saved_T0;
358
    T1 = saved_T1;
359
    A0 = saved_A0;
360
    env = saved_env;
361
    return ret;
362
}
363

    
364
void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector)
365
{
366
    CPUX86State *saved_env;
367

    
368
    saved_env = env;
369
    env = s;
370
    load_seg(seg_reg, selector);
371
    env = saved_env;
372
}