Statistics
| Branch: | Revision:

root / cpu-exec.c @ 93a40ea9

History | View | Annotate | Download (18.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 "config.h"
21
#include "exec.h"
22
#include "disas.h"
23

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

    
27
#if defined(TARGET_ARM) || defined(TARGET_SPARC)
28
/* XXX: unify with i386 target */
29
void cpu_loop_exit(void)
30
{
31
    longjmp(env->jmp_env, 1);
32
}
33
#endif
34

    
35
/* main execution loop */
36

    
37
int cpu_exec(CPUState *env1)
38
{
39
    int saved_T0, saved_T1, saved_T2;
40
    CPUState *saved_env;
41
#ifdef reg_EAX
42
    int saved_EAX;
43
#endif
44
#ifdef reg_ECX
45
    int saved_ECX;
46
#endif
47
#ifdef reg_EDX
48
    int saved_EDX;
49
#endif
50
#ifdef reg_EBX
51
    int saved_EBX;
52
#endif
53
#ifdef reg_ESP
54
    int saved_ESP;
55
#endif
56
#ifdef reg_EBP
57
    int saved_EBP;
58
#endif
59
#ifdef reg_ESI
60
    int saved_ESI;
61
#endif
62
#ifdef reg_EDI
63
    int saved_EDI;
64
#endif
65
#ifdef __sparc__
66
    int saved_i7, tmp_T0;
67
#endif
68
    int code_gen_size, ret, interrupt_request;
69
    void (*gen_func)(void);
70
    TranslationBlock *tb, **ptb;
71
    uint8_t *tc_ptr, *cs_base, *pc;
72
    unsigned int flags;
73

    
74
    /* first we save global registers */
75
    saved_T0 = T0;
76
    saved_T1 = T1;
77
    saved_T2 = T2;
78
    saved_env = env;
79
    env = env1;
80
#ifdef __sparc__
81
    /* we also save i7 because longjmp may not restore it */
82
    asm volatile ("mov %%i7, %0" : "=r" (saved_i7));
83
#endif
84

    
85
#if defined(TARGET_I386)
86
#ifdef reg_EAX
87
    saved_EAX = EAX;
88
    EAX = env->regs[R_EAX];
89
#endif
90
#ifdef reg_ECX
91
    saved_ECX = ECX;
92
    ECX = env->regs[R_ECX];
93
#endif
94
#ifdef reg_EDX
95
    saved_EDX = EDX;
96
    EDX = env->regs[R_EDX];
97
#endif
98
#ifdef reg_EBX
99
    saved_EBX = EBX;
100
    EBX = env->regs[R_EBX];
101
#endif
102
#ifdef reg_ESP
103
    saved_ESP = ESP;
104
    ESP = env->regs[R_ESP];
105
#endif
106
#ifdef reg_EBP
107
    saved_EBP = EBP;
108
    EBP = env->regs[R_EBP];
109
#endif
110
#ifdef reg_ESI
111
    saved_ESI = ESI;
112
    ESI = env->regs[R_ESI];
113
#endif
114
#ifdef reg_EDI
115
    saved_EDI = EDI;
116
    EDI = env->regs[R_EDI];
117
#endif
118
    
119
    /* put eflags in CPU temporary format */
120
    CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
121
    DF = 1 - (2 * ((env->eflags >> 10) & 1));
122
    CC_OP = CC_OP_EFLAGS;
123
    env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
124
#elif defined(TARGET_ARM)
125
    {
126
        unsigned int psr;
127
        psr = env->cpsr;
128
        env->CF = (psr >> 29) & 1;
129
        env->NZF = (psr & 0xc0000000) ^ 0x40000000;
130
        env->VF = (psr << 3) & 0x80000000;
131
        env->cpsr = psr & ~0xf0000000;
132
    }
133
#elif defined(TARGET_SPARC)
134
#else
135
#error unsupported target CPU
136
#endif
137
    env->exception_index = -1;
138

    
139
    /* prepare setjmp context for exception handling */
140
    for(;;) {
141
        if (setjmp(env->jmp_env) == 0) {
142
            /* if an exception is pending, we execute it here */
143
            if (env->exception_index >= 0) {
144
                if (env->exception_index >= EXCP_INTERRUPT) {
145
                    /* exit request from the cpu execution loop */
146
                    ret = env->exception_index;
147
                    break;
148
                } else if (env->user_mode_only) {
149
                    /* if user mode only, we simulate a fake exception
150
                       which will be hanlded outside the cpu execution
151
                       loop */
152
#if defined(TARGET_I386)
153
                    do_interrupt_user(env->exception_index, 
154
                                      env->exception_is_int, 
155
                                      env->error_code, 
156
                                      env->exception_next_eip);
157
#endif
158
                    ret = env->exception_index;
159
                    break;
160
                } else {
161
#if defined(TARGET_I386)
162
                    /* simulate a real cpu exception. On i386, it can
163
                       trigger new exceptions, but we do not handle
164
                       double or triple faults yet. */
165
                    do_interrupt(env->exception_index, 
166
                                 env->exception_is_int, 
167
                                 env->error_code, 
168
                                 env->exception_next_eip, 0);
169
#endif
170
                }
171
                env->exception_index = -1;
172
            }
173
            T0 = 0; /* force lookup of first TB */
174
            for(;;) {
175
#ifdef __sparc__
176
                /* g1 can be modified by some libc? functions */ 
177
                tmp_T0 = T0;
178
#endif            
179
                interrupt_request = env->interrupt_request;
180
                if (__builtin_expect(interrupt_request, 0)) {
181
#if defined(TARGET_I386)
182
                    /* if hardware interrupt pending, we execute it */
183
                    if ((interrupt_request & CPU_INTERRUPT_HARD) &&
184
                        (env->eflags & IF_MASK) && 
185
                        !(env->hflags & HF_INHIBIT_IRQ_MASK)) {
186
                        int intno;
187
                        intno = cpu_x86_get_pic_interrupt(env);
188
                        if (loglevel) {
189
                            fprintf(logfile, "Servicing hardware INT=0x%02x\n", intno);
190
                        }
191
                        do_interrupt(intno, 0, 0, 0, 1);
192
                        env->interrupt_request &= ~CPU_INTERRUPT_HARD;
193
                        /* ensure that no TB jump will be modified as
194
                           the program flow was changed */
195
#ifdef __sparc__
196
                        tmp_T0 = 0;
197
#else
198
                        T0 = 0;
199
#endif
200
                    }
201
#endif
202
                    if (interrupt_request & CPU_INTERRUPT_EXIT) {
203
                        env->interrupt_request &= ~CPU_INTERRUPT_EXIT;
204
                        env->exception_index = EXCP_INTERRUPT;
205
                        cpu_loop_exit();
206
                    }
207
                }
208
#ifdef DEBUG_EXEC
209
                if (loglevel) {
210
#if defined(TARGET_I386)
211
                    /* restore flags in standard format */
212
                    env->regs[R_EAX] = EAX;
213
                    env->regs[R_EBX] = EBX;
214
                    env->regs[R_ECX] = ECX;
215
                    env->regs[R_EDX] = EDX;
216
                    env->regs[R_ESI] = ESI;
217
                    env->regs[R_EDI] = EDI;
218
                    env->regs[R_EBP] = EBP;
219
                    env->regs[R_ESP] = ESP;
220
                    env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
221
                    cpu_x86_dump_state(env, logfile, X86_DUMP_CCOP);
222
                    env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
223
#elif defined(TARGET_ARM)
224
                    env->cpsr = compute_cpsr();
225
                    cpu_arm_dump_state(env, logfile, 0);
226
                    env->cpsr &= ~0xf0000000;
227
#elif defined(TARGET_SPARC)
228
                    cpu_sparc_dump_state (env, logfile, 0);
229
#else
230
#error unsupported target CPU 
231
#endif
232
                }
233
#endif
234
                /* we record a subset of the CPU state. It will
235
                   always be the same before a given translated block
236
                   is executed. */
237
#if defined(TARGET_I386)
238
                flags = env->hflags;
239
                flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK));
240
                cs_base = env->segs[R_CS].base;
241
                pc = cs_base + env->eip;
242
#elif defined(TARGET_ARM)
243
                flags = 0;
244
                cs_base = 0;
245
                pc = (uint8_t *)env->regs[15];
246
#elif defined(TARGET_SPARC)
247
                                flags = 0;
248
                                cs_base = 0;
249
                                if (env->npc) {
250
                                        env->pc = env->npc;
251
                                        env->npc = 0;
252
                                }
253
                                pc = (uint8_t *) env->pc;
254
#else
255
#error unsupported CPU
256
#endif
257
                tb = tb_find(&ptb, (unsigned long)pc, (unsigned long)cs_base, 
258
                             flags);
259
                if (!tb) {
260
                    spin_lock(&tb_lock);
261
                    /* if no translated code available, then translate it now */
262
                    tb = tb_alloc((unsigned long)pc);
263
                    if (!tb) {
264
                        /* flush must be done */
265
                        tb_flush();
266
                        /* cannot fail at this point */
267
                        tb = tb_alloc((unsigned long)pc);
268
                        /* don't forget to invalidate previous TB info */
269
                        ptb = &tb_hash[tb_hash_func((unsigned long)pc)];
270
                        T0 = 0;
271
                    }
272
                    tc_ptr = code_gen_ptr;
273
                    tb->tc_ptr = tc_ptr;
274
                    tb->cs_base = (unsigned long)cs_base;
275
                    tb->flags = flags;
276
                    /* XXX: an MMU exception can occur here */
277
                    cpu_gen_code(env, tb, CODE_GEN_MAX_SIZE, &code_gen_size);
278
                    *ptb = tb;
279
                    tb->hash_next = NULL;
280
                    tb_link(tb);
281
                    code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1));
282
                    spin_unlock(&tb_lock);
283
                }
284
#ifdef DEBUG_EXEC
285
                if (loglevel) {
286
                    fprintf(logfile, "Trace 0x%08lx [0x%08lx] %s\n",
287
                            (long)tb->tc_ptr, (long)tb->pc,
288
                            lookup_symbol((void *)tb->pc));
289
                }
290
#endif
291
#ifdef __sparc__
292
                T0 = tmp_T0;
293
#endif            
294
                /* see if we can patch the calling TB. */
295
                if (T0 != 0) {
296
                    spin_lock(&tb_lock);
297
                    tb_add_jump((TranslationBlock *)(T0 & ~3), T0 & 3, tb);
298
                    spin_unlock(&tb_lock);
299
                }
300
                tc_ptr = tb->tc_ptr;
301
                env->current_tb = tb;
302
                /* execute the generated code */
303
                gen_func = (void *)tc_ptr;
304
#if defined(__sparc__)
305
                __asm__ __volatile__("call        %0\n\t"
306
                                     "mov        %%o7,%%i0"
307
                                     : /* no outputs */
308
                                     : "r" (gen_func) 
309
                                     : "i0", "i1", "i2", "i3", "i4", "i5");
310
#elif defined(__arm__)
311
                asm volatile ("mov pc, %0\n\t"
312
                              ".global exec_loop\n\t"
313
                              "exec_loop:\n\t"
314
                              : /* no outputs */
315
                              : "r" (gen_func)
316
                              : "r1", "r2", "r3", "r8", "r9", "r10", "r12", "r14");
317
#else
318
                gen_func();
319
#endif
320
                env->current_tb = NULL;
321
                /* reset soft MMU for next block (it can currently
322
                   only be set by a memory fault) */
323
#if defined(TARGET_I386) && !defined(CONFIG_SOFTMMU)
324
                if (env->hflags & HF_SOFTMMU_MASK) {
325
                    env->hflags &= ~HF_SOFTMMU_MASK;
326
                    /* do not allow linking to another block */
327
                    T0 = 0;
328
                }
329
#endif
330
            }
331
        } else {
332
        }
333
    } /* for(;;) */
334

    
335

    
336
#if defined(TARGET_I386)
337
    /* restore flags in standard format */
338
    env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
339

    
340
    /* restore global registers */
341
#ifdef reg_EAX
342
    EAX = saved_EAX;
343
#endif
344
#ifdef reg_ECX
345
    ECX = saved_ECX;
346
#endif
347
#ifdef reg_EDX
348
    EDX = saved_EDX;
349
#endif
350
#ifdef reg_EBX
351
    EBX = saved_EBX;
352
#endif
353
#ifdef reg_ESP
354
    ESP = saved_ESP;
355
#endif
356
#ifdef reg_EBP
357
    EBP = saved_EBP;
358
#endif
359
#ifdef reg_ESI
360
    ESI = saved_ESI;
361
#endif
362
#ifdef reg_EDI
363
    EDI = saved_EDI;
364
#endif
365
#elif defined(TARGET_ARM)
366
    env->cpsr = compute_cpsr();
367
#elif defined(TARGET_SPARC)
368
#else
369
#error unsupported target CPU
370
#endif
371
#ifdef __sparc__
372
    asm volatile ("mov %0, %%i7" : : "r" (saved_i7));
373
#endif
374
    T0 = saved_T0;
375
    T1 = saved_T1;
376
    T2 = saved_T2;
377
    env = saved_env;
378
    return ret;
379
}
380

    
381
#if defined(TARGET_I386)
382

    
383
void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector)
384
{
385
    CPUX86State *saved_env;
386

    
387
    saved_env = env;
388
    env = s;
389
    if (!(env->cr[0] & CR0_PE_MASK) || (env->eflags & VM_MASK)) {
390
        selector &= 0xffff;
391
        cpu_x86_load_seg_cache(env, seg_reg, selector, 
392
                               (uint8_t *)(selector << 4), 0xffff, 0);
393
    } else {
394
        load_seg(seg_reg, selector, 0);
395
    }
396
    env = saved_env;
397
}
398

    
399
void cpu_x86_fsave(CPUX86State *s, uint8_t *ptr, int data32)
400
{
401
    CPUX86State *saved_env;
402

    
403
    saved_env = env;
404
    env = s;
405
    
406
    helper_fsave(ptr, data32);
407

    
408
    env = saved_env;
409
}
410

    
411
void cpu_x86_frstor(CPUX86State *s, uint8_t *ptr, int data32)
412
{
413
    CPUX86State *saved_env;
414

    
415
    saved_env = env;
416
    env = s;
417
    
418
    helper_frstor(ptr, data32);
419

    
420
    env = saved_env;
421
}
422

    
423
#endif /* TARGET_I386 */
424

    
425
#undef EAX
426
#undef ECX
427
#undef EDX
428
#undef EBX
429
#undef ESP
430
#undef EBP
431
#undef ESI
432
#undef EDI
433
#undef EIP
434
#include <signal.h>
435
#include <sys/ucontext.h>
436

    
437
#if defined(TARGET_I386)
438

    
439
/* 'pc' is the host PC at which the exception was raised. 'address' is
440
   the effective address of the memory exception. 'is_write' is 1 if a
441
   write caused the exception and otherwise 0'. 'old_set' is the
442
   signal set which should be restored */
443
static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
444
                                    int is_write, sigset_t *old_set)
445
{
446
    TranslationBlock *tb;
447
    int ret;
448

    
449
    if (cpu_single_env)
450
        env = cpu_single_env; /* XXX: find a correct solution for multithread */
451
#if defined(DEBUG_SIGNAL)
452
    printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n", 
453
           pc, address, is_write, *(unsigned long *)old_set);
454
#endif
455
    /* XXX: locking issue */
456
    if (is_write && page_unprotect(address)) {
457
        return 1;
458
    }
459
    /* see if it is an MMU fault */
460
    ret = cpu_x86_handle_mmu_fault(env, address, is_write, 
461
                                   ((env->hflags & HF_CPL_MASK) == 3), 0);
462
    if (ret < 0)
463
        return 0; /* not an MMU fault */
464
    if (ret == 0)
465
        return 1; /* the MMU fault was handled without causing real CPU fault */
466
    /* now we have a real cpu fault */
467
    tb = tb_find_pc(pc);
468
    if (tb) {
469
        /* the PC is inside the translated code. It means that we have
470
           a virtual CPU fault */
471
        cpu_restore_state(tb, env, pc);
472
    }
473
    if (ret == 1) {
474
#if 0
475
        printf("PF exception: EIP=0x%08x CR2=0x%08x error=0x%x\n", 
476
               env->eip, env->cr[2], env->error_code);
477
#endif
478
        /* we restore the process signal mask as the sigreturn should
479
           do it (XXX: use sigsetjmp) */
480
        sigprocmask(SIG_SETMASK, old_set, NULL);
481
        raise_exception_err(EXCP0E_PAGE, env->error_code);
482
    } else {
483
        /* activate soft MMU for this block */
484
        env->hflags |= HF_SOFTMMU_MASK;
485
        sigprocmask(SIG_SETMASK, old_set, NULL);
486
        cpu_loop_exit();
487
    }
488
    /* never comes here */
489
    return 1;
490
}
491

    
492
#elif defined(TARGET_ARM)
493
static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
494
                                    int is_write, sigset_t *old_set)
495
{
496
    /* XXX: do more */
497
    return 0;
498
}
499
#elif defined(TARGET_SPARC)
500
static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
501
                                    int is_write, sigset_t *old_set)
502
{
503
        return 0;
504
}
505
#else
506
#error unsupported target CPU
507
#endif
508

    
509
#if defined(__i386__)
510

    
511
int cpu_signal_handler(int host_signum, struct siginfo *info, 
512
                       void *puc)
513
{
514
    struct ucontext *uc = puc;
515
    unsigned long pc;
516
    
517
#ifndef REG_EIP
518
/* for glibc 2.1 */
519
#define REG_EIP    EIP
520
#define REG_ERR    ERR
521
#define REG_TRAPNO TRAPNO
522
#endif
523
    pc = uc->uc_mcontext.gregs[REG_EIP];
524
    return handle_cpu_signal(pc, (unsigned long)info->si_addr, 
525
                             uc->uc_mcontext.gregs[REG_TRAPNO] == 0xe ? 
526
                             (uc->uc_mcontext.gregs[REG_ERR] >> 1) & 1 : 0,
527
                             &uc->uc_sigmask);
528
}
529

    
530
#elif defined(__powerpc)
531

    
532
int cpu_signal_handler(int host_signum, struct siginfo *info, 
533
                       void *puc)
534
{
535
    struct ucontext *uc = puc;
536
    struct pt_regs *regs = uc->uc_mcontext.regs;
537
    unsigned long pc;
538
    int is_write;
539

    
540
    pc = regs->nip;
541
    is_write = 0;
542
#if 0
543
    /* ppc 4xx case */
544
    if (regs->dsisr & 0x00800000)
545
        is_write = 1;
546
#else
547
    if (regs->trap != 0x400 && (regs->dsisr & 0x02000000))
548
        is_write = 1;
549
#endif
550
    return handle_cpu_signal(pc, (unsigned long)info->si_addr, 
551
                             is_write, &uc->uc_sigmask);
552
}
553

    
554
#elif defined(__alpha__)
555

    
556
int cpu_signal_handler(int host_signum, struct siginfo *info, 
557
                           void *puc)
558
{
559
    struct ucontext *uc = puc;
560
    uint32_t *pc = uc->uc_mcontext.sc_pc;
561
    uint32_t insn = *pc;
562
    int is_write = 0;
563

    
564
    /* XXX: need kernel patch to get write flag faster */
565
    switch (insn >> 26) {
566
    case 0x0d: // stw
567
    case 0x0e: // stb
568
    case 0x0f: // stq_u
569
    case 0x24: // stf
570
    case 0x25: // stg
571
    case 0x26: // sts
572
    case 0x27: // stt
573
    case 0x2c: // stl
574
    case 0x2d: // stq
575
    case 0x2e: // stl_c
576
    case 0x2f: // stq_c
577
        is_write = 1;
578
    }
579

    
580
    return handle_cpu_signal(pc, (unsigned long)info->si_addr, 
581
                             is_write, &uc->uc_sigmask);
582
}
583
#elif defined(__sparc__)
584

    
585
int cpu_signal_handler(int host_signum, struct siginfo *info, 
586
                       void *puc)
587
{
588
    uint32_t *regs = (uint32_t *)(info + 1);
589
    void *sigmask = (regs + 20);
590
    unsigned long pc;
591
    int is_write;
592
    uint32_t insn;
593
    
594
    /* XXX: is there a standard glibc define ? */
595
    pc = regs[1];
596
    /* XXX: need kernel patch to get write flag faster */
597
    is_write = 0;
598
    insn = *(uint32_t *)pc;
599
    if ((insn >> 30) == 3) {
600
      switch((insn >> 19) & 0x3f) {
601
      case 0x05: // stb
602
      case 0x06: // sth
603
      case 0x04: // st
604
      case 0x07: // std
605
      case 0x24: // stf
606
      case 0x27: // stdf
607
      case 0x25: // stfsr
608
        is_write = 1;
609
        break;
610
      }
611
    }
612
    return handle_cpu_signal(pc, (unsigned long)info->si_addr, 
613
                             is_write, sigmask);
614
}
615

    
616
#elif defined(__arm__)
617

    
618
int cpu_signal_handler(int host_signum, struct siginfo *info, 
619
                       void *puc)
620
{
621
    struct ucontext *uc = puc;
622
    unsigned long pc;
623
    int is_write;
624
    
625
    pc = uc->uc_mcontext.gregs[R15];
626
    /* XXX: compute is_write */
627
    is_write = 0;
628
    return handle_cpu_signal(pc, (unsigned long)info->si_addr, 
629
                             is_write,
630
                             &uc->uc_sigmask);
631
}
632

    
633
#elif defined(__mc68000)
634

    
635
int cpu_signal_handler(int host_signum, struct siginfo *info, 
636
                       void *puc)
637
{
638
    struct ucontext *uc = puc;
639
    unsigned long pc;
640
    int is_write;
641
    
642
    pc = uc->uc_mcontext.gregs[16];
643
    /* XXX: compute is_write */
644
    is_write = 0;
645
    return handle_cpu_signal(pc, (unsigned long)info->si_addr, 
646
                             is_write,
647
                             &uc->uc_sigmask);
648
}
649

    
650
#else
651

    
652
#error host CPU specific signal handler needed
653

    
654
#endif