Statistics
| Branch: | Revision:

root / exec-i386.c @ ae48a073

History | View | Annotate | Download (13.4 kB)

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

    
23
//#define DEBUG_EXEC
24
#define DEBUG_FLUSH
25
//#define DEBUG_SIGNAL
26

    
27
/* main execution loop */
28

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

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

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

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

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

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

    
57
/* thread support */
58

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

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

    
91
#ifdef __s390__
92
static inline int testandset (int *p)
93
{
94
    int ret;
95

    
96
    __asm__ __volatile__ ("0: cs    %0,%1,0(%2)\n"
97
                          "   jl    0b"
98
                          : "=&d" (ret)
99
                          : "r" (1), "a" (p), "0" (*p) 
100
                          : "cc", "memory" );
101
    return ret;
102
}
103
#endif
104

    
105
int global_cpu_lock = 0;
106

    
107
void cpu_lock(void)
108
{
109
    while (testandset(&global_cpu_lock));
110
}
111

    
112
void cpu_unlock(void)
113
{
114
    global_cpu_lock = 0;
115
}
116

    
117
/* exception support */
118
/* NOTE: not static to force relocation generation by GCC */
119
void raise_exception(int exception_index)
120
{
121
    /* NOTE: the register at this point must be saved by hand because
122
       longjmp restore them */
123
#ifdef reg_EAX
124
    env->regs[R_EAX] = EAX;
125
#endif
126
#ifdef reg_ECX
127
    env->regs[R_ECX] = ECX;
128
#endif
129
#ifdef reg_EDX
130
    env->regs[R_EDX] = EDX;
131
#endif
132
#ifdef reg_EBX
133
    env->regs[R_EBX] = EBX;
134
#endif
135
#ifdef reg_ESP
136
    env->regs[R_ESP] = ESP;
137
#endif
138
#ifdef reg_EBP
139
    env->regs[R_EBP] = EBP;
140
#endif
141
#ifdef reg_ESI
142
    env->regs[R_ESI] = ESI;
143
#endif
144
#ifdef reg_EDI
145
    env->regs[R_EDI] = EDI;
146
#endif
147
    env->exception_index = exception_index;
148
    longjmp(env->jmp_env, 1);
149
}
150

    
151
#if defined(DEBUG_EXEC)
152
static const char *cc_op_str[] = {
153
    "DYNAMIC",
154
    "EFLAGS",
155
    "MUL",
156
    "ADDB",
157
    "ADDW",
158
    "ADDL",
159
    "ADCB",
160
    "ADCW",
161
    "ADCL",
162
    "SUBB",
163
    "SUBW",
164
    "SUBL",
165
    "SBBB",
166
    "SBBW",
167
    "SBBL",
168
    "LOGICB",
169
    "LOGICW",
170
    "LOGICL",
171
    "INCB",
172
    "INCW",
173
    "INCL",
174
    "DECB",
175
    "DECW",
176
    "DECL",
177
    "SHLB",
178
    "SHLW",
179
    "SHLL",
180
    "SARB",
181
    "SARW",
182
    "SARL",
183
};
184

    
185
static void cpu_x86_dump_state(FILE *f)
186
{
187
    int eflags;
188
    eflags = cc_table[CC_OP].compute_all();
189
    eflags |= (DF & DF_MASK);
190
    fprintf(f, 
191
            "EAX=%08x EBX=%08X ECX=%08x EDX=%08x\n"
192
            "ESI=%08x EDI=%08X EBP=%08x ESP=%08x\n"
193
            "CCS=%08x CCD=%08x CCO=%-8s EFL=%c%c%c%c%c%c%c\n"
194
            "EIP=%08x\n",
195
            env->regs[R_EAX], env->regs[R_EBX], env->regs[R_ECX], env->regs[R_EDX], 
196
            env->regs[R_ESI], env->regs[R_EDI], env->regs[R_EBP], env->regs[R_ESP], 
197
            env->cc_src, env->cc_dst, cc_op_str[env->cc_op],
198
            eflags & DF_MASK ? 'D' : '-',
199
            eflags & CC_O ? 'O' : '-',
200
            eflags & CC_S ? 'S' : '-',
201
            eflags & CC_Z ? 'Z' : '-',
202
            eflags & CC_A ? 'A' : '-',
203
            eflags & CC_P ? 'P' : '-',
204
            eflags & CC_C ? 'C' : '-',
205
            env->eip);
206
#if 1
207
    fprintf(f, "ST0=%f ST1=%f ST2=%f ST3=%f\n", 
208
            (double)ST0, (double)ST1, (double)ST(2), (double)ST(3));
209
#endif
210
}
211

    
212
#endif
213

    
214
void cpu_x86_tblocks_init(void)
215
{
216
    if (!code_gen_ptr) {
217
        code_gen_ptr = code_gen_buffer;
218
    }
219
}
220

    
221
/* flush all the translation blocks */
222
static void tb_flush(void)
223
{
224
    int i;
225
#ifdef DEBUG_FLUSH
226
    printf("gemu: flush code_size=%d nb_tbs=%d avg_tb_size=%d\n", 
227
           code_gen_ptr - code_gen_buffer, 
228
           nb_tbs, 
229
           (code_gen_ptr - code_gen_buffer) / nb_tbs);
230
#endif
231
    nb_tbs = 0;
232
    for(i = 0;i < CODE_GEN_HASH_SIZE; i++)
233
        tb_hash[i] = NULL;
234
    code_gen_ptr = code_gen_buffer;
235
    /* XXX: flush processor icache at this point */
236
}
237

    
238
/* find a translation block in the translation cache. If not found,
239
   return NULL and the pointer to the last element of the list in pptb */
240
static inline TranslationBlock *tb_find(TranslationBlock ***pptb,
241
                                        unsigned long pc, 
242
                                        unsigned long cs_base,
243
                                        unsigned int flags)
244
{
245
    TranslationBlock **ptb, *tb;
246
    unsigned int h;
247
 
248
    h = pc & (CODE_GEN_HASH_SIZE - 1);
249
    ptb = &tb_hash[h];
250
    for(;;) {
251
        tb = *ptb;
252
        if (!tb)
253
            break;
254
        if (tb->pc == pc && tb->cs_base == cs_base && tb->flags == flags)
255
            return tb;
256
        ptb = &tb->hash_next;
257
    }
258
    *pptb = ptb;
259
    return NULL;
260
}
261

    
262
/* allocate a new translation block. flush the translation buffer if
263
   too many translation blocks or too much generated code */
264
static inline TranslationBlock *tb_alloc(void)
265
{
266
    TranslationBlock *tb;
267
    if (nb_tbs >= CODE_GEN_MAX_BLOCKS || 
268
        (code_gen_ptr - code_gen_buffer) >= CODE_GEN_BUFFER_MAX_SIZE)
269
        tb_flush();
270
    tb = &tbs[nb_tbs++];
271
    return tb;
272
}
273

    
274
int cpu_x86_exec(CPUX86State *env1)
275
{
276
    int saved_T0, saved_T1, saved_A0;
277
    CPUX86State *saved_env;
278
#ifdef reg_EAX
279
    int saved_EAX;
280
#endif
281
#ifdef reg_ECX
282
    int saved_ECX;
283
#endif
284
#ifdef reg_EDX
285
    int saved_EDX;
286
#endif
287
#ifdef reg_EBX
288
    int saved_EBX;
289
#endif
290
#ifdef reg_ESP
291
    int saved_ESP;
292
#endif
293
#ifdef reg_EBP
294
    int saved_EBP;
295
#endif
296
#ifdef reg_ESI
297
    int saved_ESI;
298
#endif
299
#ifdef reg_EDI
300
    int saved_EDI;
301
#endif
302
    int code_gen_size, ret;
303
    void (*gen_func)(void);
304
    TranslationBlock *tb, **ptb;
305
    uint8_t *tc_ptr, *cs_base, *pc;
306
    unsigned int flags;
307

    
308
    /* first we save global registers */
309
    saved_T0 = T0;
310
    saved_T1 = T1;
311
    saved_A0 = A0;
312
    saved_env = env;
313
    env = env1;
314
#ifdef reg_EAX
315
    saved_EAX = EAX;
316
    EAX = env->regs[R_EAX];
317
#endif
318
#ifdef reg_ECX
319
    saved_ECX = ECX;
320
    ECX = env->regs[R_ECX];
321
#endif
322
#ifdef reg_EDX
323
    saved_EDX = EDX;
324
    EDX = env->regs[R_EDX];
325
#endif
326
#ifdef reg_EBX
327
    saved_EBX = EBX;
328
    EBX = env->regs[R_EBX];
329
#endif
330
#ifdef reg_ESP
331
    saved_ESP = ESP;
332
    ESP = env->regs[R_ESP];
333
#endif
334
#ifdef reg_EBP
335
    saved_EBP = EBP;
336
    EBP = env->regs[R_EBP];
337
#endif
338
#ifdef reg_ESI
339
    saved_ESI = ESI;
340
    ESI = env->regs[R_ESI];
341
#endif
342
#ifdef reg_EDI
343
    saved_EDI = EDI;
344
    EDI = env->regs[R_EDI];
345
#endif
346
    
347
    /* put eflags in CPU temporary format */
348
    CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
349
    DF = 1 - (2 * ((env->eflags >> 10) & 1));
350
    CC_OP = CC_OP_EFLAGS;
351
    env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
352
    env->interrupt_request = 0;
353
    
354
    /* prepare setjmp context for exception handling */
355
    if (setjmp(env->jmp_env) == 0) {
356
        for(;;) {
357
            if (env->interrupt_request) {
358
                raise_exception(EXCP_INTERRUPT);
359
            }
360
#ifdef DEBUG_EXEC
361
            if (loglevel) {
362
                cpu_x86_dump_state(logfile);
363
            }
364
#endif
365
            /* we compute the CPU state. We assume it will not
366
               change during the whole generated block. */
367
            flags = env->seg_cache[R_CS].seg_32bit << GEN_FLAG_CODE32_SHIFT;
368
            flags |= env->seg_cache[R_SS].seg_32bit << GEN_FLAG_SS32_SHIFT;
369
            flags |= (((unsigned long)env->seg_cache[R_DS].base | 
370
                       (unsigned long)env->seg_cache[R_ES].base |
371
                       (unsigned long)env->seg_cache[R_SS].base) != 0) << 
372
                GEN_FLAG_ADDSEG_SHIFT;
373
            flags |= (env->eflags & VM_MASK) >> (17 - GEN_FLAG_VM_SHIFT);
374
            cs_base = env->seg_cache[R_CS].base;
375
            pc = cs_base + env->eip;
376
            tb = tb_find(&ptb, (unsigned long)pc, (unsigned long)cs_base, 
377
                         flags);
378
            if (!tb) {
379
                /* if no translated code available, then translate it now */
380
                /* XXX: very inefficient: we lock all the cpus when
381
                   generating code */
382
                cpu_lock();
383
                tc_ptr = code_gen_ptr;
384
                ret = cpu_x86_gen_code(code_gen_ptr, CODE_GEN_MAX_SIZE, 
385
                                       &code_gen_size, pc, cs_base, flags);
386
                /* if invalid instruction, signal it */
387
                if (ret != 0) {
388
                    cpu_unlock();
389
                    raise_exception(EXCP06_ILLOP);
390
                }
391
                tb = tb_alloc();
392
                *ptb = tb;
393
                tb->pc = (unsigned long)pc;
394
                tb->cs_base = (unsigned long)cs_base;
395
                tb->flags = flags;
396
                tb->tc_ptr = tc_ptr;
397
                tb->hash_next = NULL;
398
                code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1));
399
                cpu_unlock();
400
            }
401
            if (loglevel) {
402
                fprintf(logfile, "Trace 0x%08lx [0x%08lx] %s\n",
403
                        (long)tb->tc_ptr, (long)tb->pc,
404
                        lookup_symbol((void *)tb->pc));
405
                fflush(logfile);
406
            }
407
            /* execute the generated code */
408
            tc_ptr = tb->tc_ptr;
409
            gen_func = (void *)tc_ptr;
410
            gen_func();
411
        }
412
    }
413
    ret = env->exception_index;
414

    
415
    /* restore flags in standard format */
416
    env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
417

    
418
    /* restore global registers */
419
#ifdef reg_EAX
420
    EAX = saved_EAX;
421
#endif
422
#ifdef reg_ECX
423
    ECX = saved_ECX;
424
#endif
425
#ifdef reg_EDX
426
    EDX = saved_EDX;
427
#endif
428
#ifdef reg_EBX
429
    EBX = saved_EBX;
430
#endif
431
#ifdef reg_ESP
432
    ESP = saved_ESP;
433
#endif
434
#ifdef reg_EBP
435
    EBP = saved_EBP;
436
#endif
437
#ifdef reg_ESI
438
    ESI = saved_ESI;
439
#endif
440
#ifdef reg_EDI
441
    EDI = saved_EDI;
442
#endif
443
    T0 = saved_T0;
444
    T1 = saved_T1;
445
    A0 = saved_A0;
446
    env = saved_env;
447
    return ret;
448
}
449

    
450
void cpu_x86_interrupt(CPUX86State *s)
451
{
452
    s->interrupt_request = 1;
453
}
454

    
455

    
456
void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector)
457
{
458
    CPUX86State *saved_env;
459

    
460
    saved_env = env;
461
    env = s;
462
    load_seg(seg_reg, selector);
463
    env = saved_env;
464
}
465

    
466
#undef EAX
467
#undef ECX
468
#undef EDX
469
#undef EBX
470
#undef ESP
471
#undef EBP
472
#undef ESI
473
#undef EDI
474
#undef EIP
475
#include <signal.h>
476
#include <sys/ucontext.h>
477

    
478
static inline int handle_cpu_signal(unsigned long pc,
479
                                    sigset_t *old_set)
480
{
481
#ifdef DEBUG_SIGNAL
482
    printf("gemu: SIGSEGV pc=0x%08lx oldset=0x%08lx\n", 
483
           pc, *(unsigned long *)old_set);
484
#endif
485
    if (pc >= (unsigned long)code_gen_buffer &&
486
        pc < (unsigned long)code_gen_buffer + CODE_GEN_BUFFER_SIZE) {
487
        /* the PC is inside the translated code. It means that we have
488
           a virtual CPU fault */
489
        /* we restore the process signal mask as the sigreturn should
490
           do it */
491
        sigprocmask(SIG_SETMASK, old_set, NULL);
492
        /* XXX: need to compute virtual pc position by retranslating
493
           code. The rest of the CPU state should be correct. */
494
        raise_exception(EXCP0D_GPF);
495
        /* never comes here */
496
        return 1;
497
    } else {
498
        return 0;
499
    }
500
}
501

    
502
int cpu_x86_signal_handler(int host_signum, struct siginfo *info, 
503
                           void *puc)
504
{
505
#if defined(__i386__)
506
    struct ucontext *uc = puc;
507
    unsigned long pc;
508
    sigset_t *pold_set;
509
    
510
#ifndef REG_EIP
511
/* for glibc 2.1 */
512
#define REG_EIP EIP
513
#endif
514
    pc = uc->uc_mcontext.gregs[REG_EIP];
515
    pold_set = &uc->uc_sigmask;
516
    return handle_cpu_signal(pc, pold_set);
517
#else
518
#warning No CPU specific signal handler: cannot handle target SIGSEGV events
519
    return 0;
520
#endif
521
}