Statistics
| Branch: | Revision:

root / exec-i386.c @ 9de5e440

History | View | Annotate | Download (12.7 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
//#define DEBUG_SIGNAL
25

    
26
/* main execution loop */
27

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

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

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

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

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

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

    
56
/* thread support */
57

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

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

    
90
int global_cpu_lock = 0;
91

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

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

    
102
/* exception support */
103
/* NOTE: not static to force relocation generation by GCC */
104
void raise_exception(int exception_index)
105
{
106
    /* NOTE: the register at this point must be saved by hand because
107
       longjmp restore them */
108
#ifdef reg_EAX
109
    env->regs[R_EAX] = EAX;
110
#endif
111
#ifdef reg_ECX
112
    env->regs[R_ECX] = ECX;
113
#endif
114
#ifdef reg_EDX
115
    env->regs[R_EDX] = EDX;
116
#endif
117
#ifdef reg_EBX
118
    env->regs[R_EBX] = EBX;
119
#endif
120
#ifdef reg_ESP
121
    env->regs[R_ESP] = ESP;
122
#endif
123
#ifdef reg_EBP
124
    env->regs[R_EBP] = EBP;
125
#endif
126
#ifdef reg_ESI
127
    env->regs[R_ESI] = ESI;
128
#endif
129
#ifdef reg_EDI
130
    env->regs[R_EDI] = EDI;
131
#endif
132
    env->exception_index = exception_index;
133
    longjmp(env->jmp_env, 1);
134
}
135

    
136
#if defined(DEBUG_EXEC)
137
static const char *cc_op_str[] = {
138
    "DYNAMIC",
139
    "EFLAGS",
140
    "MUL",
141
    "ADDB",
142
    "ADDW",
143
    "ADDL",
144
    "ADCB",
145
    "ADCW",
146
    "ADCL",
147
    "SUBB",
148
    "SUBW",
149
    "SUBL",
150
    "SBBB",
151
    "SBBW",
152
    "SBBL",
153
    "LOGICB",
154
    "LOGICW",
155
    "LOGICL",
156
    "INCB",
157
    "INCW",
158
    "INCL",
159
    "DECB",
160
    "DECW",
161
    "DECL",
162
    "SHLB",
163
    "SHLW",
164
    "SHLL",
165
    "SARB",
166
    "SARW",
167
    "SARL",
168
};
169

    
170
static void cpu_x86_dump_state(FILE *f)
171
{
172
    int eflags;
173
    eflags = cc_table[CC_OP].compute_all();
174
    eflags |= (DF & DIRECTION_FLAG);
175
    fprintf(f, 
176
            "EAX=%08x EBX=%08X ECX=%08x EDX=%08x\n"
177
            "ESI=%08x EDI=%08X EBP=%08x ESP=%08x\n"
178
            "CCS=%08x CCD=%08x CCO=%-8s EFL=%c%c%c%c%c%c%c\n"
179
            "EIP=%08x\n",
180
            env->regs[R_EAX], env->regs[R_EBX], env->regs[R_ECX], env->regs[R_EDX], 
181
            env->regs[R_ESI], env->regs[R_EDI], env->regs[R_EBP], env->regs[R_ESP], 
182
            env->cc_src, env->cc_dst, cc_op_str[env->cc_op],
183
            eflags & DIRECTION_FLAG ? 'D' : '-',
184
            eflags & CC_O ? 'O' : '-',
185
            eflags & CC_S ? 'S' : '-',
186
            eflags & CC_Z ? 'Z' : '-',
187
            eflags & CC_A ? 'A' : '-',
188
            eflags & CC_P ? 'P' : '-',
189
            eflags & CC_C ? 'C' : '-',
190
            env->eip);
191
#if 1
192
    fprintf(f, "ST0=%f ST1=%f ST2=%f ST3=%f\n", 
193
            (double)ST0, (double)ST1, (double)ST(2), (double)ST(3));
194
#endif
195
}
196

    
197
#endif
198

    
199
void cpu_x86_tblocks_init(void)
200
{
201
    if (!code_gen_ptr) {
202
        code_gen_ptr = code_gen_buffer;
203
    }
204
}
205

    
206
/* flush all the translation blocks */
207
static void tb_flush(void)
208
{
209
    int i;
210
#ifdef DEBUG_FLUSH
211
    printf("gemu: flush code_size=%d nb_tbs=%d avg_tb_size=%d\n", 
212
           code_gen_ptr - code_gen_buffer, 
213
           nb_tbs, 
214
           (code_gen_ptr - code_gen_buffer) / nb_tbs);
215
#endif
216
    nb_tbs = 0;
217
    for(i = 0;i < CODE_GEN_HASH_SIZE; i++)
218
        tb_hash[i] = NULL;
219
    code_gen_ptr = code_gen_buffer;
220
    /* XXX: flush processor icache at this point */
221
}
222

    
223
/* find a translation block in the translation cache. If not found,
224
   return NULL and the pointer to the last element of the list in pptb */
225
static inline TranslationBlock *tb_find(TranslationBlock ***pptb,
226
                                        unsigned long pc, 
227
                                        unsigned long cs_base,
228
                                        unsigned int flags)
229
{
230
    TranslationBlock **ptb, *tb;
231
    unsigned int h;
232
 
233
    h = pc & (CODE_GEN_HASH_SIZE - 1);
234
    ptb = &tb_hash[h];
235
    for(;;) {
236
        tb = *ptb;
237
        if (!tb)
238
            break;
239
        if (tb->pc == pc && tb->cs_base == cs_base && tb->flags == flags)
240
            return tb;
241
        ptb = &tb->hash_next;
242
    }
243
    *pptb = ptb;
244
    return NULL;
245
}
246

    
247
/* allocate a new translation block. flush the translation buffer if
248
   too many translation blocks or too much generated code */
249
static inline TranslationBlock *tb_alloc(void)
250
{
251
    TranslationBlock *tb;
252
    if (nb_tbs >= CODE_GEN_MAX_BLOCKS || 
253
        (code_gen_ptr - code_gen_buffer) >= CODE_GEN_BUFFER_MAX_SIZE)
254
        tb_flush();
255
    tb = &tbs[nb_tbs++];
256
    return tb;
257
}
258

    
259
int cpu_x86_exec(CPUX86State *env1)
260
{
261
    int saved_T0, saved_T1, saved_A0;
262
    CPUX86State *saved_env;
263
#ifdef reg_EAX
264
    int saved_EAX;
265
#endif
266
#ifdef reg_ECX
267
    int saved_ECX;
268
#endif
269
#ifdef reg_EDX
270
    int saved_EDX;
271
#endif
272
#ifdef reg_EBX
273
    int saved_EBX;
274
#endif
275
#ifdef reg_ESP
276
    int saved_ESP;
277
#endif
278
#ifdef reg_EBP
279
    int saved_EBP;
280
#endif
281
#ifdef reg_ESI
282
    int saved_ESI;
283
#endif
284
#ifdef reg_EDI
285
    int saved_EDI;
286
#endif
287
    int code_gen_size, ret;
288
    void (*gen_func)(void);
289
    TranslationBlock *tb, **ptb;
290
    uint8_t *tc_ptr, *cs_base, *pc;
291
    unsigned int flags;
292

    
293
    /* first we save global registers */
294
    saved_T0 = T0;
295
    saved_T1 = T1;
296
    saved_A0 = A0;
297
    saved_env = env;
298
    env = env1;
299
#ifdef reg_EAX
300
    saved_EAX = EAX;
301
    EAX = env->regs[R_EAX];
302
#endif
303
#ifdef reg_ECX
304
    saved_ECX = ECX;
305
    ECX = env->regs[R_ECX];
306
#endif
307
#ifdef reg_EDX
308
    saved_EDX = EDX;
309
    EDX = env->regs[R_EDX];
310
#endif
311
#ifdef reg_EBX
312
    saved_EBX = EBX;
313
    EBX = env->regs[R_EBX];
314
#endif
315
#ifdef reg_ESP
316
    saved_ESP = ESP;
317
    ESP = env->regs[R_ESP];
318
#endif
319
#ifdef reg_EBP
320
    saved_EBP = EBP;
321
    EBP = env->regs[R_EBP];
322
#endif
323
#ifdef reg_ESI
324
    saved_ESI = ESI;
325
    ESI = env->regs[R_ESI];
326
#endif
327
#ifdef reg_EDI
328
    saved_EDI = EDI;
329
    EDI = env->regs[R_EDI];
330
#endif
331
    
332
    /* put eflags in CPU temporary format */
333
    T0 = env->eflags;
334
    op_movl_eflags_T0();
335
    CC_OP = CC_OP_EFLAGS;
336
    env->interrupt_request = 0;
337
    
338
    /* prepare setjmp context for exception handling */
339
    if (setjmp(env->jmp_env) == 0) {
340
        for(;;) {
341
            if (env->interrupt_request) {
342
                raise_exception(EXCP_INTERRUPT);
343
            }
344
#ifdef DEBUG_EXEC
345
            if (loglevel) {
346
                cpu_x86_dump_state(logfile);
347
            }
348
#endif
349
            /* we compute the CPU state. We assume it will not
350
               change during the whole generated block. */
351
            flags = env->seg_cache[R_CS].seg_32bit << GEN_FLAG_CODE32_SHIFT;
352
            flags |= env->seg_cache[R_SS].seg_32bit << GEN_FLAG_SS32_SHIFT;
353
            flags |= (((unsigned long)env->seg_cache[R_DS].base | 
354
                       (unsigned long)env->seg_cache[R_ES].base |
355
                       (unsigned long)env->seg_cache[R_SS].base) != 0) << 
356
                GEN_FLAG_ADDSEG_SHIFT;
357
            cs_base = env->seg_cache[R_CS].base;
358
            pc = cs_base + env->eip;
359
            tb = tb_find(&ptb, (unsigned long)pc, (unsigned long)cs_base, 
360
                         flags);
361
            if (!tb) {
362
                /* if no translated code available, then translate it now */
363
                /* XXX: very inefficient: we lock all the cpus when
364
                   generating code */
365
                cpu_lock();
366
                tc_ptr = code_gen_ptr;
367
                ret = cpu_x86_gen_code(code_gen_ptr, CODE_GEN_MAX_SIZE, 
368
                                       &code_gen_size, pc, cs_base, flags);
369
                /* if invalid instruction, signal it */
370
                if (ret != 0) {
371
                    cpu_unlock();
372
                    raise_exception(EXCP06_ILLOP);
373
                }
374
                tb = tb_alloc();
375
                *ptb = tb;
376
                tb->pc = (unsigned long)pc;
377
                tb->cs_base = (unsigned long)cs_base;
378
                tb->flags = flags;
379
                tb->tc_ptr = tc_ptr;
380
                tb->hash_next = NULL;
381
                code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1));
382
                cpu_unlock();
383
            }
384
            /* execute the generated code */
385
            tc_ptr = tb->tc_ptr;
386
            gen_func = (void *)tc_ptr;
387
            gen_func();
388
        }
389
    }
390
    ret = env->exception_index;
391

    
392
    /* restore flags in standard format */
393
    op_movl_T0_eflags();
394
    env->eflags = T0;
395

    
396
    /* restore global registers */
397
#ifdef reg_EAX
398
    EAX = saved_EAX;
399
#endif
400
#ifdef reg_ECX
401
    ECX = saved_ECX;
402
#endif
403
#ifdef reg_EDX
404
    EDX = saved_EDX;
405
#endif
406
#ifdef reg_EBX
407
    EBX = saved_EBX;
408
#endif
409
#ifdef reg_ESP
410
    ESP = saved_ESP;
411
#endif
412
#ifdef reg_EBP
413
    EBP = saved_EBP;
414
#endif
415
#ifdef reg_ESI
416
    ESI = saved_ESI;
417
#endif
418
#ifdef reg_EDI
419
    EDI = saved_EDI;
420
#endif
421
    T0 = saved_T0;
422
    T1 = saved_T1;
423
    A0 = saved_A0;
424
    env = saved_env;
425
    return ret;
426
}
427

    
428
void cpu_x86_interrupt(CPUX86State *s)
429
{
430
    s->interrupt_request = 1;
431
}
432

    
433

    
434
void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector)
435
{
436
    CPUX86State *saved_env;
437

    
438
    saved_env = env;
439
    env = s;
440
    load_seg(seg_reg, selector);
441
    env = saved_env;
442
}
443

    
444
#undef EAX
445
#undef ECX
446
#undef EDX
447
#undef EBX
448
#undef ESP
449
#undef EBP
450
#undef ESI
451
#undef EDI
452
#undef EIP
453
#include <signal.h>
454
#include <sys/ucontext.h>
455

    
456
static inline int handle_cpu_signal(unsigned long pc,
457
                                    sigset_t *old_set)
458
{
459
#ifdef DEBUG_SIGNAL
460
    printf("gemu: SIGSEGV pc=0x%08lx oldset=0x%08lx\n", 
461
           pc, *(unsigned long *)old_set);
462
#endif
463
    if (pc >= (unsigned long)code_gen_buffer &&
464
        pc < (unsigned long)code_gen_buffer + CODE_GEN_BUFFER_SIZE) {
465
        /* the PC is inside the translated code. It means that we have
466
           a virtual CPU fault */
467
        /* we restore the process signal mask as the sigreturn should
468
           do it */
469
        sigprocmask(SIG_SETMASK, old_set, NULL);
470
        /* XXX: need to compute virtual pc position by retranslating
471
           code. The rest of the CPU state should be correct. */
472
        raise_exception(EXCP0D_GPF);
473
        /* never comes here */
474
        return 1;
475
    } else {
476
        return 0;
477
    }
478
}
479

    
480
int cpu_x86_signal_handler(int host_signum, struct siginfo *info, 
481
                           void *puc)
482
{
483
#if defined(__i386__)
484
    struct ucontext *uc = puc;
485
    unsigned long pc;
486
    sigset_t *pold_set;
487
    
488
    pc = uc->uc_mcontext.gregs[EIP];
489
    pold_set = &uc->uc_sigmask;
490
    return handle_cpu_signal(pc, pold_set);
491
#else
492
#warning No CPU specific signal handler: cannot handle target SIGSEGV events
493
    return 0;
494
#endif
495
}