Statistics
| Branch: | Revision:

root / exec-i386.c @ a69d83b6

History | View | Annotate | Download (13.9 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
#ifdef __alpha__
106
int testandset (int *p)
107
{
108
    int ret;
109
    unsigned long one;
110

    
111
    __asm__ __volatile__ ("0:        mov 1,%2\n"
112
                          "        ldl_l %0,%1\n"
113
                          "        stl_c %2,%1\n"
114
                          "        beq %2,1f\n"
115
                          ".subsection 2\n"
116
                          "1:        br 0b\n"
117
                          ".previous"
118
                          : "=r" (ret), "=m" (*p), "=r" (one)
119
                          : "m" (*p));
120
    return ret;
121
}
122
#endif
123

    
124
#ifdef __sparc__
125
static inline int testandset (int *p)
126
{
127
        int ret;
128

    
129
        __asm__ __volatile__("ldstub        [%1], %0"
130
                             : "=r" (ret)
131
                             : "r" (p)
132
                             : "memory");
133

    
134
        return (ret ? 1 : 0);
135
}
136
#endif
137

    
138
int global_cpu_lock = 0;
139

    
140
void cpu_lock(void)
141
{
142
    while (testandset(&global_cpu_lock));
143
}
144

    
145
void cpu_unlock(void)
146
{
147
    global_cpu_lock = 0;
148
}
149

    
150
/* exception support */
151
/* NOTE: not static to force relocation generation by GCC */
152
void raise_exception(int exception_index)
153
{
154
    /* NOTE: the register at this point must be saved by hand because
155
       longjmp restore them */
156
#ifdef reg_EAX
157
    env->regs[R_EAX] = EAX;
158
#endif
159
#ifdef reg_ECX
160
    env->regs[R_ECX] = ECX;
161
#endif
162
#ifdef reg_EDX
163
    env->regs[R_EDX] = EDX;
164
#endif
165
#ifdef reg_EBX
166
    env->regs[R_EBX] = EBX;
167
#endif
168
#ifdef reg_ESP
169
    env->regs[R_ESP] = ESP;
170
#endif
171
#ifdef reg_EBP
172
    env->regs[R_EBP] = EBP;
173
#endif
174
#ifdef reg_ESI
175
    env->regs[R_ESI] = ESI;
176
#endif
177
#ifdef reg_EDI
178
    env->regs[R_EDI] = EDI;
179
#endif
180
    env->exception_index = exception_index;
181
    longjmp(env->jmp_env, 1);
182
}
183

    
184
#if defined(DEBUG_EXEC)
185
static const char *cc_op_str[] = {
186
    "DYNAMIC",
187
    "EFLAGS",
188
    "MUL",
189
    "ADDB",
190
    "ADDW",
191
    "ADDL",
192
    "ADCB",
193
    "ADCW",
194
    "ADCL",
195
    "SUBB",
196
    "SUBW",
197
    "SUBL",
198
    "SBBB",
199
    "SBBW",
200
    "SBBL",
201
    "LOGICB",
202
    "LOGICW",
203
    "LOGICL",
204
    "INCB",
205
    "INCW",
206
    "INCL",
207
    "DECB",
208
    "DECW",
209
    "DECL",
210
    "SHLB",
211
    "SHLW",
212
    "SHLL",
213
    "SARB",
214
    "SARW",
215
    "SARL",
216
};
217

    
218
static void cpu_x86_dump_state(FILE *f)
219
{
220
    int eflags;
221
    eflags = cc_table[CC_OP].compute_all();
222
    eflags |= (DF & DF_MASK);
223
    fprintf(f, 
224
            "EAX=%08x EBX=%08X ECX=%08x EDX=%08x\n"
225
            "ESI=%08x EDI=%08X EBP=%08x ESP=%08x\n"
226
            "CCS=%08x CCD=%08x CCO=%-8s EFL=%c%c%c%c%c%c%c\n"
227
            "EIP=%08x\n",
228
            env->regs[R_EAX], env->regs[R_EBX], env->regs[R_ECX], env->regs[R_EDX], 
229
            env->regs[R_ESI], env->regs[R_EDI], env->regs[R_EBP], env->regs[R_ESP], 
230
            env->cc_src, env->cc_dst, cc_op_str[env->cc_op],
231
            eflags & DF_MASK ? 'D' : '-',
232
            eflags & CC_O ? 'O' : '-',
233
            eflags & CC_S ? 'S' : '-',
234
            eflags & CC_Z ? 'Z' : '-',
235
            eflags & CC_A ? 'A' : '-',
236
            eflags & CC_P ? 'P' : '-',
237
            eflags & CC_C ? 'C' : '-',
238
            env->eip);
239
#if 1
240
    fprintf(f, "ST0=%f ST1=%f ST2=%f ST3=%f\n", 
241
            (double)ST0, (double)ST1, (double)ST(2), (double)ST(3));
242
#endif
243
}
244

    
245
#endif
246

    
247
void cpu_x86_tblocks_init(void)
248
{
249
    if (!code_gen_ptr) {
250
        code_gen_ptr = code_gen_buffer;
251
    }
252
}
253

    
254
/* flush all the translation blocks */
255
static void tb_flush(void)
256
{
257
    int i;
258
#ifdef DEBUG_FLUSH
259
    printf("gemu: flush code_size=%d nb_tbs=%d avg_tb_size=%d\n", 
260
           code_gen_ptr - code_gen_buffer, 
261
           nb_tbs, 
262
           (code_gen_ptr - code_gen_buffer) / nb_tbs);
263
#endif
264
    nb_tbs = 0;
265
    for(i = 0;i < CODE_GEN_HASH_SIZE; i++)
266
        tb_hash[i] = NULL;
267
    code_gen_ptr = code_gen_buffer;
268
    /* XXX: flush processor icache at this point */
269
}
270

    
271
/* find a translation block in the translation cache. If not found,
272
   return NULL and the pointer to the last element of the list in pptb */
273
static inline TranslationBlock *tb_find(TranslationBlock ***pptb,
274
                                        unsigned long pc, 
275
                                        unsigned long cs_base,
276
                                        unsigned int flags)
277
{
278
    TranslationBlock **ptb, *tb;
279
    unsigned int h;
280
 
281
    h = pc & (CODE_GEN_HASH_SIZE - 1);
282
    ptb = &tb_hash[h];
283
    for(;;) {
284
        tb = *ptb;
285
        if (!tb)
286
            break;
287
        if (tb->pc == pc && tb->cs_base == cs_base && tb->flags == flags)
288
            return tb;
289
        ptb = &tb->hash_next;
290
    }
291
    *pptb = ptb;
292
    return NULL;
293
}
294

    
295
/* allocate a new translation block. flush the translation buffer if
296
   too many translation blocks or too much generated code */
297
static inline TranslationBlock *tb_alloc(void)
298
{
299
    TranslationBlock *tb;
300
    if (nb_tbs >= CODE_GEN_MAX_BLOCKS || 
301
        (code_gen_ptr - code_gen_buffer) >= CODE_GEN_BUFFER_MAX_SIZE)
302
        tb_flush();
303
    tb = &tbs[nb_tbs++];
304
    return tb;
305
}
306

    
307
int cpu_x86_exec(CPUX86State *env1)
308
{
309
    int saved_T0, saved_T1, saved_A0;
310
    CPUX86State *saved_env;
311
#ifdef reg_EAX
312
    int saved_EAX;
313
#endif
314
#ifdef reg_ECX
315
    int saved_ECX;
316
#endif
317
#ifdef reg_EDX
318
    int saved_EDX;
319
#endif
320
#ifdef reg_EBX
321
    int saved_EBX;
322
#endif
323
#ifdef reg_ESP
324
    int saved_ESP;
325
#endif
326
#ifdef reg_EBP
327
    int saved_EBP;
328
#endif
329
#ifdef reg_ESI
330
    int saved_ESI;
331
#endif
332
#ifdef reg_EDI
333
    int saved_EDI;
334
#endif
335
    int code_gen_size, ret;
336
    void (*gen_func)(void);
337
    TranslationBlock *tb, **ptb;
338
    uint8_t *tc_ptr, *cs_base, *pc;
339
    unsigned int flags;
340

    
341
    /* first we save global registers */
342
    saved_T0 = T0;
343
    saved_T1 = T1;
344
    saved_A0 = A0;
345
    saved_env = env;
346
    env = env1;
347
#ifdef reg_EAX
348
    saved_EAX = EAX;
349
    EAX = env->regs[R_EAX];
350
#endif
351
#ifdef reg_ECX
352
    saved_ECX = ECX;
353
    ECX = env->regs[R_ECX];
354
#endif
355
#ifdef reg_EDX
356
    saved_EDX = EDX;
357
    EDX = env->regs[R_EDX];
358
#endif
359
#ifdef reg_EBX
360
    saved_EBX = EBX;
361
    EBX = env->regs[R_EBX];
362
#endif
363
#ifdef reg_ESP
364
    saved_ESP = ESP;
365
    ESP = env->regs[R_ESP];
366
#endif
367
#ifdef reg_EBP
368
    saved_EBP = EBP;
369
    EBP = env->regs[R_EBP];
370
#endif
371
#ifdef reg_ESI
372
    saved_ESI = ESI;
373
    ESI = env->regs[R_ESI];
374
#endif
375
#ifdef reg_EDI
376
    saved_EDI = EDI;
377
    EDI = env->regs[R_EDI];
378
#endif
379
    
380
    /* put eflags in CPU temporary format */
381
    CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
382
    DF = 1 - (2 * ((env->eflags >> 10) & 1));
383
    CC_OP = CC_OP_EFLAGS;
384
    env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
385
    env->interrupt_request = 0;
386
    
387
    /* prepare setjmp context for exception handling */
388
    if (setjmp(env->jmp_env) == 0) {
389
        for(;;) {
390
            if (env->interrupt_request) {
391
                raise_exception(EXCP_INTERRUPT);
392
            }
393
#ifdef DEBUG_EXEC
394
            if (loglevel) {
395
                cpu_x86_dump_state(logfile);
396
            }
397
#endif
398
            /* we compute the CPU state. We assume it will not
399
               change during the whole generated block. */
400
            flags = env->seg_cache[R_CS].seg_32bit << GEN_FLAG_CODE32_SHIFT;
401
            flags |= env->seg_cache[R_SS].seg_32bit << GEN_FLAG_SS32_SHIFT;
402
            flags |= (((unsigned long)env->seg_cache[R_DS].base | 
403
                       (unsigned long)env->seg_cache[R_ES].base |
404
                       (unsigned long)env->seg_cache[R_SS].base) != 0) << 
405
                GEN_FLAG_ADDSEG_SHIFT;
406
            flags |= (env->eflags & VM_MASK) >> (17 - GEN_FLAG_VM_SHIFT);
407
            cs_base = env->seg_cache[R_CS].base;
408
            pc = cs_base + env->eip;
409
            tb = tb_find(&ptb, (unsigned long)pc, (unsigned long)cs_base, 
410
                         flags);
411
            if (!tb) {
412
                /* if no translated code available, then translate it now */
413
                /* XXX: very inefficient: we lock all the cpus when
414
                   generating code */
415
                cpu_lock();
416
                tc_ptr = code_gen_ptr;
417
                ret = cpu_x86_gen_code(code_gen_ptr, CODE_GEN_MAX_SIZE, 
418
                                       &code_gen_size, pc, cs_base, flags);
419
                /* if invalid instruction, signal it */
420
                if (ret != 0) {
421
                    cpu_unlock();
422
                    raise_exception(EXCP06_ILLOP);
423
                }
424
                tb = tb_alloc();
425
                *ptb = tb;
426
                tb->pc = (unsigned long)pc;
427
                tb->cs_base = (unsigned long)cs_base;
428
                tb->flags = flags;
429
                tb->tc_ptr = tc_ptr;
430
                tb->hash_next = NULL;
431
                code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1));
432
                cpu_unlock();
433
            }
434
            if (loglevel) {
435
                fprintf(logfile, "Trace 0x%08lx [0x%08lx] %s\n",
436
                        (long)tb->tc_ptr, (long)tb->pc,
437
                        lookup_symbol((void *)tb->pc));
438
                fflush(logfile);
439
            }
440
            /* execute the generated code */
441
            tc_ptr = tb->tc_ptr;
442
            gen_func = (void *)tc_ptr;
443
            gen_func();
444
        }
445
    }
446
    ret = env->exception_index;
447

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

    
451
    /* restore global registers */
452
#ifdef reg_EAX
453
    EAX = saved_EAX;
454
#endif
455
#ifdef reg_ECX
456
    ECX = saved_ECX;
457
#endif
458
#ifdef reg_EDX
459
    EDX = saved_EDX;
460
#endif
461
#ifdef reg_EBX
462
    EBX = saved_EBX;
463
#endif
464
#ifdef reg_ESP
465
    ESP = saved_ESP;
466
#endif
467
#ifdef reg_EBP
468
    EBP = saved_EBP;
469
#endif
470
#ifdef reg_ESI
471
    ESI = saved_ESI;
472
#endif
473
#ifdef reg_EDI
474
    EDI = saved_EDI;
475
#endif
476
    T0 = saved_T0;
477
    T1 = saved_T1;
478
    A0 = saved_A0;
479
    env = saved_env;
480
    return ret;
481
}
482

    
483
void cpu_x86_interrupt(CPUX86State *s)
484
{
485
    s->interrupt_request = 1;
486
}
487

    
488

    
489
void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector)
490
{
491
    CPUX86State *saved_env;
492

    
493
    saved_env = env;
494
    env = s;
495
    load_seg(seg_reg, selector);
496
    env = saved_env;
497
}
498

    
499
#undef EAX
500
#undef ECX
501
#undef EDX
502
#undef EBX
503
#undef ESP
504
#undef EBP
505
#undef ESI
506
#undef EDI
507
#undef EIP
508
#include <signal.h>
509
#include <sys/ucontext.h>
510

    
511
static inline int handle_cpu_signal(unsigned long pc,
512
                                    sigset_t *old_set)
513
{
514
#ifdef DEBUG_SIGNAL
515
    printf("gemu: SIGSEGV pc=0x%08lx oldset=0x%08lx\n", 
516
           pc, *(unsigned long *)old_set);
517
#endif
518
    if (pc >= (unsigned long)code_gen_buffer &&
519
        pc < (unsigned long)code_gen_buffer + CODE_GEN_BUFFER_SIZE) {
520
        /* the PC is inside the translated code. It means that we have
521
           a virtual CPU fault */
522
        /* we restore the process signal mask as the sigreturn should
523
           do it */
524
        sigprocmask(SIG_SETMASK, old_set, NULL);
525
        /* XXX: need to compute virtual pc position by retranslating
526
           code. The rest of the CPU state should be correct. */
527
        raise_exception(EXCP0D_GPF);
528
        /* never comes here */
529
        return 1;
530
    } else {
531
        return 0;
532
    }
533
}
534

    
535
int cpu_x86_signal_handler(int host_signum, struct siginfo *info, 
536
                           void *puc)
537
{
538
#if defined(__i386__)
539
    struct ucontext *uc = puc;
540
    unsigned long pc;
541
    sigset_t *pold_set;
542
    
543
#ifndef REG_EIP
544
/* for glibc 2.1 */
545
#define REG_EIP EIP
546
#endif
547
    pc = uc->uc_mcontext.gregs[REG_EIP];
548
    pold_set = &uc->uc_sigmask;
549
    return handle_cpu_signal(pc, pold_set);
550
#else
551
#warning No CPU specific signal handler: cannot handle target SIGSEGV events
552
    return 0;
553
#endif
554
}