Statistics
| Branch: | Revision:

root / exec-i386.c @ b56dad1c

History | View | Annotate | Download (14.8 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_err(int exception_index, int error_code)
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
    env->error_code = error_code;
182
    longjmp(env->jmp_env, 1);
183
}
184

    
185
/* short cut if error_code is 0 or not present */
186
void raise_exception(int exception_index)
187
{
188
    raise_exception_err(exception_index, 0);
189
}
190

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

    
225
static void cpu_x86_dump_state(FILE *f)
226
{
227
    int eflags;
228
    char cc_op_name[32];
229
    eflags = cc_table[CC_OP].compute_all();
230
    eflags |= (DF & DF_MASK);
231
    if ((unsigned)env->cc_op < CC_OP_NB)
232
        strcpy(cc_op_name, cc_op_str[env->cc_op]);
233
    else
234
        snprintf(cc_op_name, sizeof(cc_op_name), "[%d]", env->cc_op);
235
    fprintf(f, 
236
            "EAX=%08x EBX=%08X ECX=%08x EDX=%08x\n"
237
            "ESI=%08x EDI=%08X EBP=%08x ESP=%08x\n"
238
            "CCS=%08x CCD=%08x CCO=%-8s EFL=%c%c%c%c%c%c%c\n"
239
            "EIP=%08x\n",
240
            env->regs[R_EAX], env->regs[R_EBX], env->regs[R_ECX], env->regs[R_EDX], 
241
            env->regs[R_ESI], env->regs[R_EDI], env->regs[R_EBP], env->regs[R_ESP], 
242
            env->cc_src, env->cc_dst, cc_op_name,
243
            eflags & DF_MASK ? 'D' : '-',
244
            eflags & CC_O ? 'O' : '-',
245
            eflags & CC_S ? 'S' : '-',
246
            eflags & CC_Z ? 'Z' : '-',
247
            eflags & CC_A ? 'A' : '-',
248
            eflags & CC_P ? 'P' : '-',
249
            eflags & CC_C ? 'C' : '-',
250
            env->eip);
251
#if 1
252
    fprintf(f, "ST0=%f ST1=%f ST2=%f ST3=%f\n", 
253
            (double)ST0, (double)ST1, (double)ST(2), (double)ST(3));
254
#endif
255
}
256

    
257
#endif
258

    
259
void cpu_x86_tblocks_init(void)
260
{
261
    if (!code_gen_ptr) {
262
        code_gen_ptr = code_gen_buffer;
263
    }
264
}
265

    
266
/* flush all the translation blocks */
267
static void tb_flush(void)
268
{
269
    int i;
270
#ifdef DEBUG_FLUSH
271
    printf("gemu: flush code_size=%d nb_tbs=%d avg_tb_size=%d\n", 
272
           code_gen_ptr - code_gen_buffer, 
273
           nb_tbs, 
274
           (code_gen_ptr - code_gen_buffer) / nb_tbs);
275
#endif
276
    nb_tbs = 0;
277
    for(i = 0;i < CODE_GEN_HASH_SIZE; i++)
278
        tb_hash[i] = NULL;
279
    code_gen_ptr = code_gen_buffer;
280
    /* XXX: flush processor icache at this point */
281
}
282

    
283
/* find a translation block in the translation cache. If not found,
284
   return NULL and the pointer to the last element of the list in pptb */
285
static inline TranslationBlock *tb_find(TranslationBlock ***pptb,
286
                                        unsigned long pc, 
287
                                        unsigned long cs_base,
288
                                        unsigned int flags)
289
{
290
    TranslationBlock **ptb, *tb;
291
    unsigned int h;
292
 
293
    h = pc & (CODE_GEN_HASH_SIZE - 1);
294
    ptb = &tb_hash[h];
295
#if 0
296
    /* XXX: hack to handle 16 bit modyfing code */
297
    if (flags & (1 << GEN_FLAG_CODE32_SHIFT))
298
#endif
299
        for(;;) {
300
            tb = *ptb;
301
            if (!tb)
302
                break;
303
            if (tb->pc == pc && tb->cs_base == cs_base && tb->flags == flags)
304
            return tb;
305
            ptb = &tb->hash_next;
306
        }
307
    *pptb = ptb;
308
    return NULL;
309
}
310

    
311
/* allocate a new translation block. flush the translation buffer if
312
   too many translation blocks or too much generated code */
313
static inline TranslationBlock *tb_alloc(void)
314
{
315
    TranslationBlock *tb;
316
    if (nb_tbs >= CODE_GEN_MAX_BLOCKS || 
317
        (code_gen_ptr - code_gen_buffer) >= CODE_GEN_BUFFER_MAX_SIZE)
318
        tb_flush();
319
    tb = &tbs[nb_tbs++];
320
    return tb;
321
}
322

    
323
int cpu_x86_exec(CPUX86State *env1)
324
{
325
    int saved_T0, saved_T1, saved_A0;
326
    CPUX86State *saved_env;
327
#ifdef reg_EAX
328
    int saved_EAX;
329
#endif
330
#ifdef reg_ECX
331
    int saved_ECX;
332
#endif
333
#ifdef reg_EDX
334
    int saved_EDX;
335
#endif
336
#ifdef reg_EBX
337
    int saved_EBX;
338
#endif
339
#ifdef reg_ESP
340
    int saved_ESP;
341
#endif
342
#ifdef reg_EBP
343
    int saved_EBP;
344
#endif
345
#ifdef reg_ESI
346
    int saved_ESI;
347
#endif
348
#ifdef reg_EDI
349
    int saved_EDI;
350
#endif
351
    int code_gen_size, ret;
352
    void (*gen_func)(void);
353
    TranslationBlock *tb, **ptb;
354
    uint8_t *tc_ptr, *cs_base, *pc;
355
    unsigned int flags;
356

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

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

    
469
    /* restore global registers */
470
#ifdef reg_EAX
471
    EAX = saved_EAX;
472
#endif
473
#ifdef reg_ECX
474
    ECX = saved_ECX;
475
#endif
476
#ifdef reg_EDX
477
    EDX = saved_EDX;
478
#endif
479
#ifdef reg_EBX
480
    EBX = saved_EBX;
481
#endif
482
#ifdef reg_ESP
483
    ESP = saved_ESP;
484
#endif
485
#ifdef reg_EBP
486
    EBP = saved_EBP;
487
#endif
488
#ifdef reg_ESI
489
    ESI = saved_ESI;
490
#endif
491
#ifdef reg_EDI
492
    EDI = saved_EDI;
493
#endif
494
    T0 = saved_T0;
495
    T1 = saved_T1;
496
    A0 = saved_A0;
497
    env = saved_env;
498
    return ret;
499
}
500

    
501
void cpu_x86_interrupt(CPUX86State *s)
502
{
503
    s->interrupt_request = 1;
504
}
505

    
506

    
507
void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector)
508
{
509
    CPUX86State *saved_env;
510

    
511
    saved_env = env;
512
    env = s;
513
    load_seg(seg_reg, selector);
514
    env = saved_env;
515
}
516

    
517
#undef EAX
518
#undef ECX
519
#undef EDX
520
#undef EBX
521
#undef ESP
522
#undef EBP
523
#undef ESI
524
#undef EDI
525
#undef EIP
526
#include <signal.h>
527
#include <sys/ucontext.h>
528

    
529
/* 'pc' is the host PC at which the exception was raised. 'address' is
530
   the effective address of the memory exception */
531
static inline int handle_cpu_signal(unsigned long pc,
532
                                    unsigned long address,
533
                                    sigset_t *old_set)
534
{
535
#ifdef DEBUG_SIGNAL
536
    printf("gemu: SIGSEGV pc=0x%08lx oldset=0x%08lx\n", 
537
           pc, *(unsigned long *)old_set);
538
#endif
539
    if (pc >= (unsigned long)code_gen_buffer &&
540
        pc < (unsigned long)code_gen_buffer + CODE_GEN_BUFFER_SIZE) {
541
        /* the PC is inside the translated code. It means that we have
542
           a virtual CPU fault */
543
        /* we restore the process signal mask as the sigreturn should
544
           do it */
545
        sigprocmask(SIG_SETMASK, old_set, NULL);
546
        /* XXX: need to compute virtual pc position by retranslating
547
           code. The rest of the CPU state should be correct. */
548
        env->cr2 = address;
549
        /* XXX: more precise exception code */
550
        raise_exception_err(EXCP0E_PAGE, 4);
551
        /* never comes here */
552
        return 1;
553
    } else {
554
        return 0;
555
    }
556
}
557

    
558
int cpu_x86_signal_handler(int host_signum, struct siginfo *info, 
559
                           void *puc)
560
{
561
#if defined(__i386__)
562
    struct ucontext *uc = puc;
563
    unsigned long pc;
564
    sigset_t *pold_set;
565
    
566
#ifndef REG_EIP
567
/* for glibc 2.1 */
568
#define REG_EIP EIP
569
#endif
570
    pc = uc->uc_mcontext.gregs[REG_EIP];
571
    pold_set = &uc->uc_sigmask;
572
    return handle_cpu_signal(pc, (unsigned long)info->si_addr, pold_set);
573
#else
574
#warning No CPU specific signal handler: cannot handle target SIGSEGV events
575
    return 0;
576
#endif
577
}