Statistics
| Branch: | Revision:

root / exec-i386.c @ e026db58

History | View | Annotate | Download (13.7 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
int global_cpu_lock = 0;
125

    
126
void cpu_lock(void)
127
{
128
    while (testandset(&global_cpu_lock));
129
}
130

    
131
void cpu_unlock(void)
132
{
133
    global_cpu_lock = 0;
134
}
135

    
136
/* exception support */
137
/* NOTE: not static to force relocation generation by GCC */
138
void raise_exception(int exception_index)
139
{
140
    /* NOTE: the register at this point must be saved by hand because
141
       longjmp restore them */
142
#ifdef reg_EAX
143
    env->regs[R_EAX] = EAX;
144
#endif
145
#ifdef reg_ECX
146
    env->regs[R_ECX] = ECX;
147
#endif
148
#ifdef reg_EDX
149
    env->regs[R_EDX] = EDX;
150
#endif
151
#ifdef reg_EBX
152
    env->regs[R_EBX] = EBX;
153
#endif
154
#ifdef reg_ESP
155
    env->regs[R_ESP] = ESP;
156
#endif
157
#ifdef reg_EBP
158
    env->regs[R_EBP] = EBP;
159
#endif
160
#ifdef reg_ESI
161
    env->regs[R_ESI] = ESI;
162
#endif
163
#ifdef reg_EDI
164
    env->regs[R_EDI] = EDI;
165
#endif
166
    env->exception_index = exception_index;
167
    longjmp(env->jmp_env, 1);
168
}
169

    
170
#if defined(DEBUG_EXEC)
171
static const char *cc_op_str[] = {
172
    "DYNAMIC",
173
    "EFLAGS",
174
    "MUL",
175
    "ADDB",
176
    "ADDW",
177
    "ADDL",
178
    "ADCB",
179
    "ADCW",
180
    "ADCL",
181
    "SUBB",
182
    "SUBW",
183
    "SUBL",
184
    "SBBB",
185
    "SBBW",
186
    "SBBL",
187
    "LOGICB",
188
    "LOGICW",
189
    "LOGICL",
190
    "INCB",
191
    "INCW",
192
    "INCL",
193
    "DECB",
194
    "DECW",
195
    "DECL",
196
    "SHLB",
197
    "SHLW",
198
    "SHLL",
199
    "SARB",
200
    "SARW",
201
    "SARL",
202
};
203

    
204
static void cpu_x86_dump_state(FILE *f)
205
{
206
    int eflags;
207
    eflags = cc_table[CC_OP].compute_all();
208
    eflags |= (DF & DF_MASK);
209
    fprintf(f, 
210
            "EAX=%08x EBX=%08X ECX=%08x EDX=%08x\n"
211
            "ESI=%08x EDI=%08X EBP=%08x ESP=%08x\n"
212
            "CCS=%08x CCD=%08x CCO=%-8s EFL=%c%c%c%c%c%c%c\n"
213
            "EIP=%08x\n",
214
            env->regs[R_EAX], env->regs[R_EBX], env->regs[R_ECX], env->regs[R_EDX], 
215
            env->regs[R_ESI], env->regs[R_EDI], env->regs[R_EBP], env->regs[R_ESP], 
216
            env->cc_src, env->cc_dst, cc_op_str[env->cc_op],
217
            eflags & DF_MASK ? 'D' : '-',
218
            eflags & CC_O ? 'O' : '-',
219
            eflags & CC_S ? 'S' : '-',
220
            eflags & CC_Z ? 'Z' : '-',
221
            eflags & CC_A ? 'A' : '-',
222
            eflags & CC_P ? 'P' : '-',
223
            eflags & CC_C ? 'C' : '-',
224
            env->eip);
225
#if 1
226
    fprintf(f, "ST0=%f ST1=%f ST2=%f ST3=%f\n", 
227
            (double)ST0, (double)ST1, (double)ST(2), (double)ST(3));
228
#endif
229
}
230

    
231
#endif
232

    
233
void cpu_x86_tblocks_init(void)
234
{
235
    if (!code_gen_ptr) {
236
        code_gen_ptr = code_gen_buffer;
237
    }
238
}
239

    
240
/* flush all the translation blocks */
241
static void tb_flush(void)
242
{
243
    int i;
244
#ifdef DEBUG_FLUSH
245
    printf("gemu: flush code_size=%d nb_tbs=%d avg_tb_size=%d\n", 
246
           code_gen_ptr - code_gen_buffer, 
247
           nb_tbs, 
248
           (code_gen_ptr - code_gen_buffer) / nb_tbs);
249
#endif
250
    nb_tbs = 0;
251
    for(i = 0;i < CODE_GEN_HASH_SIZE; i++)
252
        tb_hash[i] = NULL;
253
    code_gen_ptr = code_gen_buffer;
254
    /* XXX: flush processor icache at this point */
255
}
256

    
257
/* find a translation block in the translation cache. If not found,
258
   return NULL and the pointer to the last element of the list in pptb */
259
static inline TranslationBlock *tb_find(TranslationBlock ***pptb,
260
                                        unsigned long pc, 
261
                                        unsigned long cs_base,
262
                                        unsigned int flags)
263
{
264
    TranslationBlock **ptb, *tb;
265
    unsigned int h;
266
 
267
    h = pc & (CODE_GEN_HASH_SIZE - 1);
268
    ptb = &tb_hash[h];
269
    for(;;) {
270
        tb = *ptb;
271
        if (!tb)
272
            break;
273
        if (tb->pc == pc && tb->cs_base == cs_base && tb->flags == flags)
274
            return tb;
275
        ptb = &tb->hash_next;
276
    }
277
    *pptb = ptb;
278
    return NULL;
279
}
280

    
281
/* allocate a new translation block. flush the translation buffer if
282
   too many translation blocks or too much generated code */
283
static inline TranslationBlock *tb_alloc(void)
284
{
285
    TranslationBlock *tb;
286
    if (nb_tbs >= CODE_GEN_MAX_BLOCKS || 
287
        (code_gen_ptr - code_gen_buffer) >= CODE_GEN_BUFFER_MAX_SIZE)
288
        tb_flush();
289
    tb = &tbs[nb_tbs++];
290
    return tb;
291
}
292

    
293
int cpu_x86_exec(CPUX86State *env1)
294
{
295
    int saved_T0, saved_T1, saved_A0;
296
    CPUX86State *saved_env;
297
#ifdef reg_EAX
298
    int saved_EAX;
299
#endif
300
#ifdef reg_ECX
301
    int saved_ECX;
302
#endif
303
#ifdef reg_EDX
304
    int saved_EDX;
305
#endif
306
#ifdef reg_EBX
307
    int saved_EBX;
308
#endif
309
#ifdef reg_ESP
310
    int saved_ESP;
311
#endif
312
#ifdef reg_EBP
313
    int saved_EBP;
314
#endif
315
#ifdef reg_ESI
316
    int saved_ESI;
317
#endif
318
#ifdef reg_EDI
319
    int saved_EDI;
320
#endif
321
    int code_gen_size, ret;
322
    void (*gen_func)(void);
323
    TranslationBlock *tb, **ptb;
324
    uint8_t *tc_ptr, *cs_base, *pc;
325
    unsigned int flags;
326

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

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

    
437
    /* restore global registers */
438
#ifdef reg_EAX
439
    EAX = saved_EAX;
440
#endif
441
#ifdef reg_ECX
442
    ECX = saved_ECX;
443
#endif
444
#ifdef reg_EDX
445
    EDX = saved_EDX;
446
#endif
447
#ifdef reg_EBX
448
    EBX = saved_EBX;
449
#endif
450
#ifdef reg_ESP
451
    ESP = saved_ESP;
452
#endif
453
#ifdef reg_EBP
454
    EBP = saved_EBP;
455
#endif
456
#ifdef reg_ESI
457
    ESI = saved_ESI;
458
#endif
459
#ifdef reg_EDI
460
    EDI = saved_EDI;
461
#endif
462
    T0 = saved_T0;
463
    T1 = saved_T1;
464
    A0 = saved_A0;
465
    env = saved_env;
466
    return ret;
467
}
468

    
469
void cpu_x86_interrupt(CPUX86State *s)
470
{
471
    s->interrupt_request = 1;
472
}
473

    
474

    
475
void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector)
476
{
477
    CPUX86State *saved_env;
478

    
479
    saved_env = env;
480
    env = s;
481
    load_seg(seg_reg, selector);
482
    env = saved_env;
483
}
484

    
485
#undef EAX
486
#undef ECX
487
#undef EDX
488
#undef EBX
489
#undef ESP
490
#undef EBP
491
#undef ESI
492
#undef EDI
493
#undef EIP
494
#include <signal.h>
495
#include <sys/ucontext.h>
496

    
497
static inline int handle_cpu_signal(unsigned long pc,
498
                                    sigset_t *old_set)
499
{
500
#ifdef DEBUG_SIGNAL
501
    printf("gemu: SIGSEGV pc=0x%08lx oldset=0x%08lx\n", 
502
           pc, *(unsigned long *)old_set);
503
#endif
504
    if (pc >= (unsigned long)code_gen_buffer &&
505
        pc < (unsigned long)code_gen_buffer + CODE_GEN_BUFFER_SIZE) {
506
        /* the PC is inside the translated code. It means that we have
507
           a virtual CPU fault */
508
        /* we restore the process signal mask as the sigreturn should
509
           do it */
510
        sigprocmask(SIG_SETMASK, old_set, NULL);
511
        /* XXX: need to compute virtual pc position by retranslating
512
           code. The rest of the CPU state should be correct. */
513
        raise_exception(EXCP0D_GPF);
514
        /* never comes here */
515
        return 1;
516
    } else {
517
        return 0;
518
    }
519
}
520

    
521
int cpu_x86_signal_handler(int host_signum, struct siginfo *info, 
522
                           void *puc)
523
{
524
#if defined(__i386__)
525
    struct ucontext *uc = puc;
526
    unsigned long pc;
527
    sigset_t *pold_set;
528
    
529
#ifndef REG_EIP
530
/* for glibc 2.1 */
531
#define REG_EIP EIP
532
#endif
533
    pc = uc->uc_mcontext.gregs[REG_EIP];
534
    pold_set = &uc->uc_sigmask;
535
    return handle_cpu_signal(pc, pold_set);
536
#else
537
#warning No CPU specific signal handler: cannot handle target SIGSEGV events
538
    return 0;
539
#endif
540
}