Statistics
| Branch: | Revision:

root / exec-i386.c @ cabb4d61

History | View | Annotate | Download (14.1 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
void cpu_x86_tblocks_init(void)
192
{
193
    if (!code_gen_ptr) {
194
        code_gen_ptr = code_gen_buffer;
195
    }
196
}
197

    
198
/* flush all the translation blocks */
199
static void tb_flush(void)
200
{
201
    int i;
202
#ifdef DEBUG_FLUSH
203
    printf("gemu: flush code_size=%d nb_tbs=%d avg_tb_size=%d\n", 
204
           code_gen_ptr - code_gen_buffer, 
205
           nb_tbs, 
206
           (code_gen_ptr - code_gen_buffer) / nb_tbs);
207
#endif
208
    nb_tbs = 0;
209
    for(i = 0;i < CODE_GEN_HASH_SIZE; i++)
210
        tb_hash[i] = NULL;
211
    code_gen_ptr = code_gen_buffer;
212
    /* XXX: flush processor icache at this point */
213
}
214

    
215
/* find a translation block in the translation cache. If not found,
216
   return NULL and the pointer to the last element of the list in pptb */
217
static inline TranslationBlock *tb_find(TranslationBlock ***pptb,
218
                                        unsigned long pc, 
219
                                        unsigned long cs_base,
220
                                        unsigned int flags)
221
{
222
    TranslationBlock **ptb, *tb;
223
    unsigned int h;
224
 
225
    h = pc & (CODE_GEN_HASH_SIZE - 1);
226
    ptb = &tb_hash[h];
227
#if 0
228
    /* XXX: hack to handle 16 bit modyfing code */
229
    if (flags & (1 << GEN_FLAG_CODE32_SHIFT))
230
#endif
231
        for(;;) {
232
            tb = *ptb;
233
            if (!tb)
234
                break;
235
            if (tb->pc == pc && tb->cs_base == cs_base && tb->flags == flags)
236
            return tb;
237
            ptb = &tb->hash_next;
238
        }
239
    *pptb = ptb;
240
    return NULL;
241
}
242

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

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

    
289
    /* first we save global registers */
290
    saved_T0 = T0;
291
    saved_T1 = T1;
292
    saved_A0 = A0;
293
    saved_env = env;
294
    env = env1;
295
#ifdef reg_EAX
296
    saved_EAX = EAX;
297
    EAX = env->regs[R_EAX];
298
#endif
299
#ifdef reg_ECX
300
    saved_ECX = ECX;
301
    ECX = env->regs[R_ECX];
302
#endif
303
#ifdef reg_EDX
304
    saved_EDX = EDX;
305
    EDX = env->regs[R_EDX];
306
#endif
307
#ifdef reg_EBX
308
    saved_EBX = EBX;
309
    EBX = env->regs[R_EBX];
310
#endif
311
#ifdef reg_ESP
312
    saved_ESP = ESP;
313
    ESP = env->regs[R_ESP];
314
#endif
315
#ifdef reg_EBP
316
    saved_EBP = EBP;
317
    EBP = env->regs[R_EBP];
318
#endif
319
#ifdef reg_ESI
320
    saved_ESI = ESI;
321
    ESI = env->regs[R_ESI];
322
#endif
323
#ifdef reg_EDI
324
    saved_EDI = EDI;
325
    EDI = env->regs[R_EDI];
326
#endif
327
    
328
    /* put eflags in CPU temporary format */
329
    CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
330
    DF = 1 - (2 * ((env->eflags >> 10) & 1));
331
    CC_OP = CC_OP_EFLAGS;
332
    env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
333
    env->interrupt_request = 0;
334

    
335
    /* prepare setjmp context for exception handling */
336
    if (setjmp(env->jmp_env) == 0) {
337
        for(;;) {
338
            if (env->interrupt_request) {
339
                raise_exception(EXCP_INTERRUPT);
340
            }
341
#ifdef DEBUG_EXEC
342
            if (loglevel) {
343
                /* XXX: save all volatile state in cpu state */
344
                /* restore flags in standard format */
345
                env->regs[R_EAX] = EAX;
346
                env->regs[R_EBX] = EBX;
347
                env->regs[R_ECX] = ECX;
348
                env->regs[R_EDX] = EDX;
349
                env->regs[R_ESI] = ESI;
350
                env->regs[R_EDI] = EDI;
351
                env->regs[R_EBP] = EBP;
352
                env->regs[R_ESP] = ESP;
353
                env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
354
                cpu_x86_dump_state(env, logfile, 0);
355
                env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
356
            }
357
#endif
358
            /* we compute the CPU state. We assume it will not
359
               change during the whole generated block. */
360
            flags = env->seg_cache[R_CS].seg_32bit << GEN_FLAG_CODE32_SHIFT;
361
            flags |= env->seg_cache[R_SS].seg_32bit << GEN_FLAG_SS32_SHIFT;
362
            flags |= (((unsigned long)env->seg_cache[R_DS].base | 
363
                       (unsigned long)env->seg_cache[R_ES].base |
364
                       (unsigned long)env->seg_cache[R_SS].base) != 0) << 
365
                GEN_FLAG_ADDSEG_SHIFT;
366
            if (!(env->eflags & VM_MASK)) {
367
                flags |= (env->segs[R_CS] & 3) << GEN_FLAG_CPL_SHIFT;
368
            } else {
369
                /* NOTE: a dummy CPL is kept */
370
                flags |= (1 << GEN_FLAG_VM_SHIFT);
371
                flags |= (3 << GEN_FLAG_CPL_SHIFT);
372
            }
373
            flags |= (env->eflags & IOPL_MASK) >> (12 - GEN_FLAG_IOPL_SHIFT);
374
            flags |= (env->eflags & TF_MASK) << (GEN_FLAG_TF_SHIFT - 8);
375
            cs_base = env->seg_cache[R_CS].base;
376
            pc = cs_base + env->eip;
377
            tb = tb_find(&ptb, (unsigned long)pc, (unsigned long)cs_base, 
378
                         flags);
379
            if (!tb) {
380
                /* if no translated code available, then translate it now */
381
                /* XXX: very inefficient: we lock all the cpus when
382
                   generating code */
383
                cpu_lock();
384
                tc_ptr = code_gen_ptr;
385
                ret = cpu_x86_gen_code(code_gen_ptr, CODE_GEN_MAX_SIZE, 
386
                                       &code_gen_size, pc, cs_base, flags);
387
                /* if invalid instruction, signal it */
388
                if (ret != 0) {
389
                    cpu_unlock();
390
                    raise_exception(EXCP06_ILLOP);
391
                }
392
                tb = tb_alloc();
393
                *ptb = tb;
394
                tb->pc = (unsigned long)pc;
395
                tb->cs_base = (unsigned long)cs_base;
396
                tb->flags = flags;
397
                tb->tc_ptr = tc_ptr;
398
                tb->hash_next = NULL;
399
                code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1));
400
                cpu_unlock();
401
            }
402
#ifdef DEBUG_EXEC
403
            if (loglevel) {
404
                fprintf(logfile, "Trace 0x%08lx [0x%08lx] %s\n",
405
                        (long)tb->tc_ptr, (long)tb->pc,
406
                        lookup_symbol((void *)tb->pc));
407
            }
408
#endif
409
            /* execute the generated code */
410
            tc_ptr = tb->tc_ptr;
411
            gen_func = (void *)tc_ptr;
412
            gen_func();
413
        }
414
    }
415
    ret = env->exception_index;
416

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

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

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

    
457

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

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

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

    
480
/* 'pc' is the host PC at which the exception was raised. 'address' is
481
   the effective address of the memory exception */
482
static inline int handle_cpu_signal(unsigned long pc,
483
                                    unsigned long address,
484
                                    sigset_t *old_set)
485
{
486
#ifdef DEBUG_SIGNAL
487
    printf("gemu: SIGSEGV pc=0x%08lx oldset=0x%08lx\n", 
488
           pc, *(unsigned long *)old_set);
489
#endif
490
    if (pc >= (unsigned long)code_gen_buffer &&
491
        pc < (unsigned long)code_gen_buffer + CODE_GEN_BUFFER_SIZE) {
492
        /* the PC is inside the translated code. It means that we have
493
           a virtual CPU fault */
494
        /* we restore the process signal mask as the sigreturn should
495
           do it */
496
        sigprocmask(SIG_SETMASK, old_set, NULL);
497
        /* XXX: need to compute virtual pc position by retranslating
498
           code. The rest of the CPU state should be correct. */
499
        env->cr2 = address;
500
        /* XXX: more precise exception code */
501
        raise_exception_err(EXCP0E_PAGE, 4);
502
        /* never comes here */
503
        return 1;
504
    } else {
505
        return 0;
506
    }
507
}
508

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