Statistics
| Branch: | Revision:

root / cpu-exec.c @ 3e3f6754

History | View | Annotate | Download (49.2 kB)

1
/*
2
 *  i386 emulator main execution loop
3
 *
4
 *  Copyright (c) 2003-2005 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
#if !defined(CONFIG_SOFTMMU)
25
#undef EAX
26
#undef ECX
27
#undef EDX
28
#undef EBX
29
#undef ESP
30
#undef EBP
31
#undef ESI
32
#undef EDI
33
#undef EIP
34
#include <signal.h>
35
#include <sys/ucontext.h>
36
#endif
37

    
38
int tb_invalidated_flag;
39

    
40
//#define DEBUG_EXEC
41
//#define DEBUG_SIGNAL
42

    
43
void cpu_loop_exit(void)
44
{
45
    /* NOTE: the register at this point must be saved by hand because
46
       longjmp restore them */
47
    regs_to_env();
48
    longjmp(env->jmp_env, 1);
49
}
50

    
51
#if !(defined(TARGET_SPARC) || defined(TARGET_SH4) || defined(TARGET_M68K))
52
#define reg_T2
53
#endif
54

    
55
/* exit the current TB from a signal handler. The host registers are
56
   restored in a state compatible with the CPU emulator
57
 */
58
void cpu_resume_from_signal(CPUState *env1, void *puc)
59
{
60
#if !defined(CONFIG_SOFTMMU)
61
    struct ucontext *uc = puc;
62
#endif
63

    
64
    env = env1;
65

    
66
    /* XXX: restore cpu registers saved in host registers */
67

    
68
#if !defined(CONFIG_SOFTMMU)
69
    if (puc) {
70
        /* XXX: use siglongjmp ? */
71
        sigprocmask(SIG_SETMASK, &uc->uc_sigmask, NULL);
72
    }
73
#endif
74
    longjmp(env->jmp_env, 1);
75
}
76

    
77

    
78
static TranslationBlock *tb_find_slow(target_ulong pc,
79
                                      target_ulong cs_base,
80
                                      uint64_t flags)
81
{
82
    TranslationBlock *tb, **ptb1;
83
    int code_gen_size;
84
    unsigned int h;
85
    target_ulong phys_pc, phys_page1, phys_page2, virt_page2;
86
    uint8_t *tc_ptr;
87

    
88
    spin_lock(&tb_lock);
89

    
90
    tb_invalidated_flag = 0;
91

    
92
    regs_to_env(); /* XXX: do it just before cpu_gen_code() */
93

    
94
    /* find translated block using physical mappings */
95
    phys_pc = get_phys_addr_code(env, pc);
96
    phys_page1 = phys_pc & TARGET_PAGE_MASK;
97
    phys_page2 = -1;
98
    h = tb_phys_hash_func(phys_pc);
99
    ptb1 = &tb_phys_hash[h];
100
    for(;;) {
101
        tb = *ptb1;
102
        if (!tb)
103
            goto not_found;
104
        if (tb->pc == pc &&
105
            tb->page_addr[0] == phys_page1 &&
106
            tb->cs_base == cs_base &&
107
            tb->flags == flags) {
108
            /* check next page if needed */
109
            if (tb->page_addr[1] != -1) {
110
                virt_page2 = (pc & TARGET_PAGE_MASK) +
111
                    TARGET_PAGE_SIZE;
112
                phys_page2 = get_phys_addr_code(env, virt_page2);
113
                if (tb->page_addr[1] == phys_page2)
114
                    goto found;
115
            } else {
116
                goto found;
117
            }
118
        }
119
        ptb1 = &tb->phys_hash_next;
120
    }
121
 not_found:
122
    /* if no translated code available, then translate it now */
123
    tb = tb_alloc(pc);
124
    if (!tb) {
125
        /* flush must be done */
126
        tb_flush(env);
127
        /* cannot fail at this point */
128
        tb = tb_alloc(pc);
129
        /* don't forget to invalidate previous TB info */
130
        tb_invalidated_flag = 1;
131
    }
132
    tc_ptr = code_gen_ptr;
133
    tb->tc_ptr = tc_ptr;
134
    tb->cs_base = cs_base;
135
    tb->flags = flags;
136
    cpu_gen_code(env, tb, CODE_GEN_MAX_SIZE, &code_gen_size);
137
    code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1));
138

    
139
    /* check next page if needed */
140
    virt_page2 = (pc + tb->size - 1) & TARGET_PAGE_MASK;
141
    phys_page2 = -1;
142
    if ((pc & TARGET_PAGE_MASK) != virt_page2) {
143
        phys_page2 = get_phys_addr_code(env, virt_page2);
144
    }
145
    tb_link_phys(tb, phys_pc, phys_page2);
146

    
147
 found:
148
    /* we add the TB in the virtual pc hash table */
149
    env->tb_jmp_cache[tb_jmp_cache_hash_func(pc)] = tb;
150
    spin_unlock(&tb_lock);
151
    return tb;
152
}
153

    
154
static inline TranslationBlock *tb_find_fast(void)
155
{
156
    TranslationBlock *tb;
157
    target_ulong cs_base, pc;
158
    uint64_t flags;
159

    
160
    /* we record a subset of the CPU state. It will
161
       always be the same before a given translated block
162
       is executed. */
163
#if defined(TARGET_I386)
164
    flags = env->hflags;
165
    flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK));
166
    flags |= env->intercept;
167
    cs_base = env->segs[R_CS].base;
168
    pc = cs_base + env->eip;
169
#elif defined(TARGET_ARM)
170
    flags = env->thumb | (env->vfp.vec_len << 1)
171
            | (env->vfp.vec_stride << 4);
172
    if ((env->uncached_cpsr & CPSR_M) != ARM_CPU_MODE_USR)
173
        flags |= (1 << 6);
174
    if (env->vfp.xregs[ARM_VFP_FPEXC] & (1 << 30))
175
        flags |= (1 << 7);
176
    flags |= (env->condexec_bits << 8);
177
    cs_base = 0;
178
    pc = env->regs[15];
179
#elif defined(TARGET_SPARC)
180
#ifdef TARGET_SPARC64
181
    // Combined FPU enable bits . PRIV . DMMU enabled . IMMU enabled
182
    flags = (((env->pstate & PS_PEF) >> 1) | ((env->fprs & FPRS_FEF) << 2))
183
        | (env->pstate & PS_PRIV) | ((env->lsu & (DMMU_E | IMMU_E)) >> 2);
184
#else
185
    // FPU enable . Supervisor
186
    flags = (env->psref << 4) | env->psrs;
187
#endif
188
    cs_base = env->npc;
189
    pc = env->pc;
190
#elif defined(TARGET_PPC)
191
    flags = env->hflags;
192
    cs_base = 0;
193
    pc = env->nip;
194
#elif defined(TARGET_MIPS)
195
    flags = env->hflags & (MIPS_HFLAG_TMASK | MIPS_HFLAG_BMASK);
196
    cs_base = 0;
197
    pc = env->PC[env->current_tc];
198
#elif defined(TARGET_M68K)
199
    flags = (env->fpcr & M68K_FPCR_PREC)  /* Bit  6 */
200
            | (env->sr & SR_S)            /* Bit  13 */
201
            | ((env->macsr >> 4) & 0xf);  /* Bits 0-3 */
202
    cs_base = 0;
203
    pc = env->pc;
204
#elif defined(TARGET_SH4)
205
    flags = env->sr & (SR_MD | SR_RB);
206
    cs_base = 0;         /* XXXXX */
207
    pc = env->pc;
208
#elif defined(TARGET_ALPHA)
209
    flags = env->ps;
210
    cs_base = 0;
211
    pc = env->pc;
212
#elif defined(TARGET_CRIS)
213
    flags = 0;
214
    cs_base = 0;
215
    pc = env->pc;
216
#else
217
#error unsupported CPU
218
#endif
219
    tb = env->tb_jmp_cache[tb_jmp_cache_hash_func(pc)];
220
    if (__builtin_expect(!tb || tb->pc != pc || tb->cs_base != cs_base ||
221
                         tb->flags != flags, 0)) {
222
        tb = tb_find_slow(pc, cs_base, flags);
223
        /* Note: we do it here to avoid a gcc bug on Mac OS X when
224
           doing it in tb_find_slow */
225
        if (tb_invalidated_flag) {
226
            /* as some TB could have been invalidated because
227
               of memory exceptions while generating the code, we
228
               must recompute the hash index here */
229
            T0 = 0;
230
        }
231
    }
232
    return tb;
233
}
234

    
235
#if defined(__sparc__) && !defined(HOST_SOLARIS)
236
#define BREAK_CHAIN tmp_T0 = 0
237
#else
238
#define BREAK_CHAIN T0 = 0
239
#endif
240

    
241
/* main execution loop */
242

    
243
int cpu_exec(CPUState *env1)
244
{
245
#define DECLARE_HOST_REGS 1
246
#include "hostregs_helper.h"
247
#if defined(TARGET_SPARC)
248
#if defined(reg_REGWPTR)
249
    uint32_t *saved_regwptr;
250
#endif
251
#endif
252
#if defined(__sparc__) && !defined(HOST_SOLARIS)
253
    int saved_i7;
254
    target_ulong tmp_T0;
255
#endif
256
    int ret, interrupt_request;
257
    void (*gen_func)(void);
258
    TranslationBlock *tb;
259
    uint8_t *tc_ptr;
260

    
261
    if (cpu_halted(env1) == EXCP_HALTED)
262
        return EXCP_HALTED;
263

    
264
    cpu_single_env = env1;
265

    
266
    /* first we save global registers */
267
#define SAVE_HOST_REGS 1
268
#include "hostregs_helper.h"
269
    env = env1;
270
#if defined(__sparc__) && !defined(HOST_SOLARIS)
271
    /* we also save i7 because longjmp may not restore it */
272
    asm volatile ("mov %%i7, %0" : "=r" (saved_i7));
273
#endif
274

    
275
    env_to_regs();
276
#if defined(TARGET_I386)
277
    /* put eflags in CPU temporary format */
278
    CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
279
    DF = 1 - (2 * ((env->eflags >> 10) & 1));
280
    CC_OP = CC_OP_EFLAGS;
281
    env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
282
#elif defined(TARGET_SPARC)
283
#if defined(reg_REGWPTR)
284
    saved_regwptr = REGWPTR;
285
#endif
286
#elif defined(TARGET_M68K)
287
    env->cc_op = CC_OP_FLAGS;
288
    env->cc_dest = env->sr & 0xf;
289
    env->cc_x = (env->sr >> 4) & 1;
290
#elif defined(TARGET_ALPHA)
291
#elif defined(TARGET_ARM)
292
#elif defined(TARGET_PPC)
293
#elif defined(TARGET_MIPS)
294
#elif defined(TARGET_SH4)
295
#elif defined(TARGET_CRIS)
296
    /* XXXXX */
297
#else
298
#error unsupported target CPU
299
#endif
300
    env->exception_index = -1;
301

    
302
    /* prepare setjmp context for exception handling */
303
    for(;;) {
304
        if (setjmp(env->jmp_env) == 0) {
305
            env->current_tb = NULL;
306
            /* if an exception is pending, we execute it here */
307
            if (env->exception_index >= 0) {
308
                if (env->exception_index >= EXCP_INTERRUPT) {
309
                    /* exit request from the cpu execution loop */
310
                    ret = env->exception_index;
311
                    break;
312
                } else if (env->user_mode_only) {
313
                    /* if user mode only, we simulate a fake exception
314
                       which will be handled outside the cpu execution
315
                       loop */
316
#if defined(TARGET_I386)
317
                    do_interrupt_user(env->exception_index,
318
                                      env->exception_is_int,
319
                                      env->error_code,
320
                                      env->exception_next_eip);
321
#endif
322
                    ret = env->exception_index;
323
                    break;
324
                } else {
325
#if defined(TARGET_I386)
326
                    /* simulate a real cpu exception. On i386, it can
327
                       trigger new exceptions, but we do not handle
328
                       double or triple faults yet. */
329
                    do_interrupt(env->exception_index,
330
                                 env->exception_is_int,
331
                                 env->error_code,
332
                                 env->exception_next_eip, 0);
333
                    /* successfully delivered */
334
                    env->old_exception = -1;
335
#elif defined(TARGET_PPC)
336
                    do_interrupt(env);
337
#elif defined(TARGET_MIPS)
338
                    do_interrupt(env);
339
#elif defined(TARGET_SPARC)
340
                    do_interrupt(env->exception_index);
341
#elif defined(TARGET_ARM)
342
                    do_interrupt(env);
343
#elif defined(TARGET_SH4)
344
                    do_interrupt(env);
345
#elif defined(TARGET_ALPHA)
346
                    do_interrupt(env);
347
#elif defined(TARGET_CRIS)
348
                    do_interrupt(env);
349
#elif defined(TARGET_M68K)
350
                    do_interrupt(0);
351
#endif
352
                }
353
                env->exception_index = -1;
354
            }
355
#ifdef USE_KQEMU
356
            if (kqemu_is_ok(env) && env->interrupt_request == 0) {
357
                int ret;
358
                env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
359
                ret = kqemu_cpu_exec(env);
360
                /* put eflags in CPU temporary format */
361
                CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
362
                DF = 1 - (2 * ((env->eflags >> 10) & 1));
363
                CC_OP = CC_OP_EFLAGS;
364
                env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
365
                if (ret == 1) {
366
                    /* exception */
367
                    longjmp(env->jmp_env, 1);
368
                } else if (ret == 2) {
369
                    /* softmmu execution needed */
370
                } else {
371
                    if (env->interrupt_request != 0) {
372
                        /* hardware interrupt will be executed just after */
373
                    } else {
374
                        /* otherwise, we restart */
375
                        longjmp(env->jmp_env, 1);
376
                    }
377
                }
378
            }
379
#endif
380

    
381
            T0 = 0; /* force lookup of first TB */
382
            for(;;) {
383
#if defined(__sparc__) && !defined(HOST_SOLARIS)
384
                /* g1 can be modified by some libc? functions */
385
                tmp_T0 = T0;
386
#endif
387
                interrupt_request = env->interrupt_request;
388
                if (__builtin_expect(interrupt_request, 0)
389
#if defined(TARGET_I386)
390
                        && env->hflags & HF_GIF_MASK
391
#endif
392
                                ) {
393
                    if (interrupt_request & CPU_INTERRUPT_DEBUG) {
394
                        env->interrupt_request &= ~CPU_INTERRUPT_DEBUG;
395
                        env->exception_index = EXCP_DEBUG;
396
                        cpu_loop_exit();
397
                    }
398
#if defined(TARGET_ARM) || defined(TARGET_SPARC) || defined(TARGET_MIPS) || \
399
    defined(TARGET_PPC) || defined(TARGET_ALPHA) || defined(TARGET_CRIS)
400
                    if (interrupt_request & CPU_INTERRUPT_HALT) {
401
                        env->interrupt_request &= ~CPU_INTERRUPT_HALT;
402
                        env->halted = 1;
403
                        env->exception_index = EXCP_HLT;
404
                        cpu_loop_exit();
405
                    }
406
#endif
407
#if defined(TARGET_I386)
408
                    if ((interrupt_request & CPU_INTERRUPT_SMI) &&
409
                        !(env->hflags & HF_SMM_MASK)) {
410
                        svm_check_intercept(SVM_EXIT_SMI);
411
                        env->interrupt_request &= ~CPU_INTERRUPT_SMI;
412
                        do_smm_enter();
413
                        BREAK_CHAIN;
414
                    } else if ((interrupt_request & CPU_INTERRUPT_HARD) &&
415
                        (env->eflags & IF_MASK || env->hflags & HF_HIF_MASK) &&
416
                        !(env->hflags & HF_INHIBIT_IRQ_MASK)) {
417
                        int intno;
418
                        svm_check_intercept(SVM_EXIT_INTR);
419
                        env->interrupt_request &= ~(CPU_INTERRUPT_HARD | CPU_INTERRUPT_VIRQ);
420
                        intno = cpu_get_pic_interrupt(env);
421
                        if (loglevel & CPU_LOG_TB_IN_ASM) {
422
                            fprintf(logfile, "Servicing hardware INT=0x%02x\n", intno);
423
                        }
424
                        do_interrupt(intno, 0, 0, 0, 1);
425
                        /* ensure that no TB jump will be modified as
426
                           the program flow was changed */
427
                        BREAK_CHAIN;
428
#if !defined(CONFIG_USER_ONLY)
429
                    } else if ((interrupt_request & CPU_INTERRUPT_VIRQ) &&
430
                        (env->eflags & IF_MASK) && !(env->hflags & HF_INHIBIT_IRQ_MASK)) {
431
                         int intno;
432
                         /* FIXME: this should respect TPR */
433
                         env->interrupt_request &= ~CPU_INTERRUPT_VIRQ;
434
                         svm_check_intercept(SVM_EXIT_VINTR);
435
                         intno = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_vector));
436
                         if (loglevel & CPU_LOG_TB_IN_ASM)
437
                             fprintf(logfile, "Servicing virtual hardware INT=0x%02x\n", intno);
438
                         do_interrupt(intno, 0, 0, -1, 1);
439
                         stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_ctl),
440
                                  ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_ctl)) & ~V_IRQ_MASK);
441
                        BREAK_CHAIN;
442
#endif
443
                    }
444
#elif defined(TARGET_PPC)
445
#if 0
446
                    if ((interrupt_request & CPU_INTERRUPT_RESET)) {
447
                        cpu_ppc_reset(env);
448
                    }
449
#endif
450
                    if (interrupt_request & CPU_INTERRUPT_HARD) {
451
                        ppc_hw_interrupt(env);
452
                        if (env->pending_interrupts == 0)
453
                            env->interrupt_request &= ~CPU_INTERRUPT_HARD;
454
                        BREAK_CHAIN;
455
                    }
456
#elif defined(TARGET_MIPS)
457
                    if ((interrupt_request & CPU_INTERRUPT_HARD) &&
458
                        (env->CP0_Status & env->CP0_Cause & CP0Ca_IP_mask) &&
459
                        (env->CP0_Status & (1 << CP0St_IE)) &&
460
                        !(env->CP0_Status & (1 << CP0St_EXL)) &&
461
                        !(env->CP0_Status & (1 << CP0St_ERL)) &&
462
                        !(env->hflags & MIPS_HFLAG_DM)) {
463
                        /* Raise it */
464
                        env->exception_index = EXCP_EXT_INTERRUPT;
465
                        env->error_code = 0;
466
                        do_interrupt(env);
467
                        BREAK_CHAIN;
468
                    }
469
#elif defined(TARGET_SPARC)
470
                    if ((interrupt_request & CPU_INTERRUPT_HARD) &&
471
                        (env->psret != 0)) {
472
                        int pil = env->interrupt_index & 15;
473
                        int type = env->interrupt_index & 0xf0;
474

    
475
                        if (((type == TT_EXTINT) &&
476
                             (pil == 15 || pil > env->psrpil)) ||
477
                            type != TT_EXTINT) {
478
                            env->interrupt_request &= ~CPU_INTERRUPT_HARD;
479
                            do_interrupt(env->interrupt_index);
480
                            env->interrupt_index = 0;
481
#if !defined(TARGET_SPARC64) && !defined(CONFIG_USER_ONLY)
482
                            cpu_check_irqs(env);
483
#endif
484
                        BREAK_CHAIN;
485
                        }
486
                    } else if (interrupt_request & CPU_INTERRUPT_TIMER) {
487
                        //do_interrupt(0, 0, 0, 0, 0);
488
                        env->interrupt_request &= ~CPU_INTERRUPT_TIMER;
489
                    }
490
#elif defined(TARGET_ARM)
491
                    if (interrupt_request & CPU_INTERRUPT_FIQ
492
                        && !(env->uncached_cpsr & CPSR_F)) {
493
                        env->exception_index = EXCP_FIQ;
494
                        do_interrupt(env);
495
                        BREAK_CHAIN;
496
                    }
497
                    /* ARMv7-M interrupt return works by loading a magic value
498
                       into the PC.  On real hardware the load causes the
499
                       return to occur.  The qemu implementation performs the
500
                       jump normally, then does the exception return when the
501
                       CPU tries to execute code at the magic address.
502
                       This will cause the magic PC value to be pushed to
503
                       the stack if an interrupt occured at the wrong time.
504
                       We avoid this by disabling interrupts when
505
                       pc contains a magic address.  */
506
                    if (interrupt_request & CPU_INTERRUPT_HARD
507
                        && ((IS_M(env) && env->regs[15] < 0xfffffff0)
508
                            || !(env->uncached_cpsr & CPSR_I))) {
509
                        env->exception_index = EXCP_IRQ;
510
                        do_interrupt(env);
511
                        BREAK_CHAIN;
512
                    }
513
#elif defined(TARGET_SH4)
514
                    /* XXXXX */
515
#elif defined(TARGET_ALPHA)
516
                    if (interrupt_request & CPU_INTERRUPT_HARD) {
517
                        do_interrupt(env);
518
                        BREAK_CHAIN;
519
                    }
520
#elif defined(TARGET_CRIS)
521
                    if (interrupt_request & CPU_INTERRUPT_HARD) {
522
                        do_interrupt(env);
523
                        env->interrupt_request &= ~CPU_INTERRUPT_HARD;
524
                        BREAK_CHAIN;
525
                    }
526
#elif defined(TARGET_M68K)
527
                    if (interrupt_request & CPU_INTERRUPT_HARD
528
                        && ((env->sr & SR_I) >> SR_I_SHIFT)
529
                            < env->pending_level) {
530
                        /* Real hardware gets the interrupt vector via an
531
                           IACK cycle at this point.  Current emulated
532
                           hardware doesn't rely on this, so we
533
                           provide/save the vector when the interrupt is
534
                           first signalled.  */
535
                        env->exception_index = env->pending_vector;
536
                        do_interrupt(1);
537
                        BREAK_CHAIN;
538
                    }
539
#endif
540
                   /* Don't use the cached interupt_request value,
541
                      do_interrupt may have updated the EXITTB flag. */
542
                    if (env->interrupt_request & CPU_INTERRUPT_EXITTB) {
543
                        env->interrupt_request &= ~CPU_INTERRUPT_EXITTB;
544
                        /* ensure that no TB jump will be modified as
545
                           the program flow was changed */
546
                        BREAK_CHAIN;
547
                    }
548
                    if (interrupt_request & CPU_INTERRUPT_EXIT) {
549
                        env->interrupt_request &= ~CPU_INTERRUPT_EXIT;
550
                        env->exception_index = EXCP_INTERRUPT;
551
                        cpu_loop_exit();
552
                    }
553
                }
554
#ifdef DEBUG_EXEC
555
                if ((loglevel & CPU_LOG_TB_CPU)) {
556
                    /* restore flags in standard format */
557
                    regs_to_env();
558
#if defined(TARGET_I386)
559
                    env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
560
                    cpu_dump_state(env, logfile, fprintf, X86_DUMP_CCOP);
561
                    env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
562
#elif defined(TARGET_ARM)
563
                    cpu_dump_state(env, logfile, fprintf, 0);
564
#elif defined(TARGET_SPARC)
565
                    REGWPTR = env->regbase + (env->cwp * 16);
566
                    env->regwptr = REGWPTR;
567
                    cpu_dump_state(env, logfile, fprintf, 0);
568
#elif defined(TARGET_PPC)
569
                    cpu_dump_state(env, logfile, fprintf, 0);
570
#elif defined(TARGET_M68K)
571
                    cpu_m68k_flush_flags(env, env->cc_op);
572
                    env->cc_op = CC_OP_FLAGS;
573
                    env->sr = (env->sr & 0xffe0)
574
                              | env->cc_dest | (env->cc_x << 4);
575
                    cpu_dump_state(env, logfile, fprintf, 0);
576
#elif defined(TARGET_MIPS)
577
                    cpu_dump_state(env, logfile, fprintf, 0);
578
#elif defined(TARGET_SH4)
579
                    cpu_dump_state(env, logfile, fprintf, 0);
580
#elif defined(TARGET_ALPHA)
581
                    cpu_dump_state(env, logfile, fprintf, 0);
582
#elif defined(TARGET_CRIS)
583
                    cpu_dump_state(env, logfile, fprintf, 0);
584
#else
585
#error unsupported target CPU
586
#endif
587
                }
588
#endif
589
                tb = tb_find_fast();
590
#ifdef DEBUG_EXEC
591
                if ((loglevel & CPU_LOG_EXEC)) {
592
                    fprintf(logfile, "Trace 0x%08lx [" TARGET_FMT_lx "] %s\n",
593
                            (long)tb->tc_ptr, tb->pc,
594
                            lookup_symbol(tb->pc));
595
                }
596
#endif
597
#if defined(__sparc__) && !defined(HOST_SOLARIS)
598
                T0 = tmp_T0;
599
#endif
600
                /* see if we can patch the calling TB. When the TB
601
                   spans two pages, we cannot safely do a direct
602
                   jump. */
603
                {
604
                    if (T0 != 0 &&
605
#if USE_KQEMU
606
                        (env->kqemu_enabled != 2) &&
607
#endif
608
                        tb->page_addr[1] == -1) {
609
                    spin_lock(&tb_lock);
610
                    tb_add_jump((TranslationBlock *)(long)(T0 & ~3), T0 & 3, tb);
611
                    spin_unlock(&tb_lock);
612
                }
613
                }
614
                tc_ptr = tb->tc_ptr;
615
                env->current_tb = tb;
616
                /* execute the generated code */
617
                gen_func = (void *)tc_ptr;
618
#if defined(__sparc__)
619
                __asm__ __volatile__("call        %0\n\t"
620
                                     "mov        %%o7,%%i0"
621
                                     : /* no outputs */
622
                                     : "r" (gen_func)
623
                                     : "i0", "i1", "i2", "i3", "i4", "i5",
624
                                       "o0", "o1", "o2", "o3", "o4", "o5",
625
                                       "l0", "l1", "l2", "l3", "l4", "l5",
626
                                       "l6", "l7");
627
#elif defined(__arm__)
628
                asm volatile ("mov pc, %0\n\t"
629
                              ".global exec_loop\n\t"
630
                              "exec_loop:\n\t"
631
                              : /* no outputs */
632
                              : "r" (gen_func)
633
                              : "r1", "r2", "r3", "r8", "r9", "r10", "r12", "r14");
634
#elif defined(__ia64)
635
                struct fptr {
636
                        void *ip;
637
                        void *gp;
638
                } fp;
639

    
640
                fp.ip = tc_ptr;
641
                fp.gp = code_gen_buffer + 2 * (1 << 20);
642
                (*(void (*)(void)) &fp)();
643
#else
644
                gen_func();
645
#endif
646
                env->current_tb = NULL;
647
                /* reset soft MMU for next block (it can currently
648
                   only be set by a memory fault) */
649
#if defined(TARGET_I386) && !defined(CONFIG_SOFTMMU)
650
                if (env->hflags & HF_SOFTMMU_MASK) {
651
                    env->hflags &= ~HF_SOFTMMU_MASK;
652
                    /* do not allow linking to another block */
653
                    T0 = 0;
654
                }
655
#endif
656
#if defined(USE_KQEMU)
657
#define MIN_CYCLE_BEFORE_SWITCH (100 * 1000)
658
                if (kqemu_is_ok(env) &&
659
                    (cpu_get_time_fast() - env->last_io_time) >= MIN_CYCLE_BEFORE_SWITCH) {
660
                    cpu_loop_exit();
661
                }
662
#endif
663
            } /* for(;;) */
664
        } else {
665
            env_to_regs();
666
        }
667
    } /* for(;;) */
668

    
669

    
670
#if defined(TARGET_I386)
671
    /* restore flags in standard format */
672
    env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
673
#elif defined(TARGET_ARM)
674
    /* XXX: Save/restore host fpu exception state?.  */
675
#elif defined(TARGET_SPARC)
676
#if defined(reg_REGWPTR)
677
    REGWPTR = saved_regwptr;
678
#endif
679
#elif defined(TARGET_PPC)
680
#elif defined(TARGET_M68K)
681
    cpu_m68k_flush_flags(env, env->cc_op);
682
    env->cc_op = CC_OP_FLAGS;
683
    env->sr = (env->sr & 0xffe0)
684
              | env->cc_dest | (env->cc_x << 4);
685
#elif defined(TARGET_MIPS)
686
#elif defined(TARGET_SH4)
687
#elif defined(TARGET_ALPHA)
688
#elif defined(TARGET_CRIS)
689
    /* XXXXX */
690
#else
691
#error unsupported target CPU
692
#endif
693

    
694
    /* restore global registers */
695
#if defined(__sparc__) && !defined(HOST_SOLARIS)
696
    asm volatile ("mov %0, %%i7" : : "r" (saved_i7));
697
#endif
698
#include "hostregs_helper.h"
699

    
700
    /* fail safe : never use cpu_single_env outside cpu_exec() */
701
    cpu_single_env = NULL;
702
    return ret;
703
}
704

    
705
/* must only be called from the generated code as an exception can be
706
   generated */
707
void tb_invalidate_page_range(target_ulong start, target_ulong end)
708
{
709
    /* XXX: cannot enable it yet because it yields to MMU exception
710
       where NIP != read address on PowerPC */
711
#if 0
712
    target_ulong phys_addr;
713
    phys_addr = get_phys_addr_code(env, start);
714
    tb_invalidate_phys_page_range(phys_addr, phys_addr + end - start, 0);
715
#endif
716
}
717

    
718
#if defined(TARGET_I386) && defined(CONFIG_USER_ONLY)
719

    
720
void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector)
721
{
722
    CPUX86State *saved_env;
723

    
724
    saved_env = env;
725
    env = s;
726
    if (!(env->cr[0] & CR0_PE_MASK) || (env->eflags & VM_MASK)) {
727
        selector &= 0xffff;
728
        cpu_x86_load_seg_cache(env, seg_reg, selector,
729
                               (selector << 4), 0xffff, 0);
730
    } else {
731
        load_seg(seg_reg, selector);
732
    }
733
    env = saved_env;
734
}
735

    
736
void cpu_x86_fsave(CPUX86State *s, target_ulong ptr, int data32)
737
{
738
    CPUX86State *saved_env;
739

    
740
    saved_env = env;
741
    env = s;
742

    
743
    helper_fsave(ptr, data32);
744

    
745
    env = saved_env;
746
}
747

    
748
void cpu_x86_frstor(CPUX86State *s, target_ulong ptr, int data32)
749
{
750
    CPUX86State *saved_env;
751

    
752
    saved_env = env;
753
    env = s;
754

    
755
    helper_frstor(ptr, data32);
756

    
757
    env = saved_env;
758
}
759

    
760
#endif /* TARGET_I386 */
761

    
762
#if !defined(CONFIG_SOFTMMU)
763

    
764
#if defined(TARGET_I386)
765

    
766
/* 'pc' is the host PC at which the exception was raised. 'address' is
767
   the effective address of the memory exception. 'is_write' is 1 if a
768
   write caused the exception and otherwise 0'. 'old_set' is the
769
   signal set which should be restored */
770
static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
771
                                    int is_write, sigset_t *old_set,
772
                                    void *puc)
773
{
774
    TranslationBlock *tb;
775
    int ret;
776

    
777
    if (cpu_single_env)
778
        env = cpu_single_env; /* XXX: find a correct solution for multithread */
779
#if defined(DEBUG_SIGNAL)
780
    qemu_printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
781
                pc, address, is_write, *(unsigned long *)old_set);
782
#endif
783
    /* XXX: locking issue */
784
    if (is_write && page_unprotect(h2g(address), pc, puc)) {
785
        return 1;
786
    }
787

    
788
    /* see if it is an MMU fault */
789
    ret = cpu_x86_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
790
    if (ret < 0)
791
        return 0; /* not an MMU fault */
792
    if (ret == 0)
793
        return 1; /* the MMU fault was handled without causing real CPU fault */
794
    /* now we have a real cpu fault */
795
    tb = tb_find_pc(pc);
796
    if (tb) {
797
        /* the PC is inside the translated code. It means that we have
798
           a virtual CPU fault */
799
        cpu_restore_state(tb, env, pc, puc);
800
    }
801
    if (ret == 1) {
802
#if 0
803
        printf("PF exception: EIP=0x%08x CR2=0x%08x error=0x%x\n",
804
               env->eip, env->cr[2], env->error_code);
805
#endif
806
        /* we restore the process signal mask as the sigreturn should
807
           do it (XXX: use sigsetjmp) */
808
        sigprocmask(SIG_SETMASK, old_set, NULL);
809
        raise_exception_err(env->exception_index, env->error_code);
810
    } else {
811
        /* activate soft MMU for this block */
812
        env->hflags |= HF_SOFTMMU_MASK;
813
        cpu_resume_from_signal(env, puc);
814
    }
815
    /* never comes here */
816
    return 1;
817
}
818

    
819
#elif defined(TARGET_ARM)
820
static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
821
                                    int is_write, sigset_t *old_set,
822
                                    void *puc)
823
{
824
    TranslationBlock *tb;
825
    int ret;
826

    
827
    if (cpu_single_env)
828
        env = cpu_single_env; /* XXX: find a correct solution for multithread */
829
#if defined(DEBUG_SIGNAL)
830
    printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
831
           pc, address, is_write, *(unsigned long *)old_set);
832
#endif
833
    /* XXX: locking issue */
834
    if (is_write && page_unprotect(h2g(address), pc, puc)) {
835
        return 1;
836
    }
837
    /* see if it is an MMU fault */
838
    ret = cpu_arm_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
839
    if (ret < 0)
840
        return 0; /* not an MMU fault */
841
    if (ret == 0)
842
        return 1; /* the MMU fault was handled without causing real CPU fault */
843
    /* now we have a real cpu fault */
844
    tb = tb_find_pc(pc);
845
    if (tb) {
846
        /* the PC is inside the translated code. It means that we have
847
           a virtual CPU fault */
848
        cpu_restore_state(tb, env, pc, puc);
849
    }
850
    /* we restore the process signal mask as the sigreturn should
851
       do it (XXX: use sigsetjmp) */
852
    sigprocmask(SIG_SETMASK, old_set, NULL);
853
    cpu_loop_exit();
854
}
855
#elif defined(TARGET_SPARC)
856
static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
857
                                    int is_write, sigset_t *old_set,
858
                                    void *puc)
859
{
860
    TranslationBlock *tb;
861
    int ret;
862

    
863
    if (cpu_single_env)
864
        env = cpu_single_env; /* XXX: find a correct solution for multithread */
865
#if defined(DEBUG_SIGNAL)
866
    printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
867
           pc, address, is_write, *(unsigned long *)old_set);
868
#endif
869
    /* XXX: locking issue */
870
    if (is_write && page_unprotect(h2g(address), pc, puc)) {
871
        return 1;
872
    }
873
    /* see if it is an MMU fault */
874
    ret = cpu_sparc_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
875
    if (ret < 0)
876
        return 0; /* not an MMU fault */
877
    if (ret == 0)
878
        return 1; /* the MMU fault was handled without causing real CPU fault */
879
    /* now we have a real cpu fault */
880
    tb = tb_find_pc(pc);
881
    if (tb) {
882
        /* the PC is inside the translated code. It means that we have
883
           a virtual CPU fault */
884
        cpu_restore_state(tb, env, pc, puc);
885
    }
886
    /* we restore the process signal mask as the sigreturn should
887
       do it (XXX: use sigsetjmp) */
888
    sigprocmask(SIG_SETMASK, old_set, NULL);
889
    cpu_loop_exit();
890
}
891
#elif defined (TARGET_PPC)
892
static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
893
                                    int is_write, sigset_t *old_set,
894
                                    void *puc)
895
{
896
    TranslationBlock *tb;
897
    int ret;
898

    
899
    if (cpu_single_env)
900
        env = cpu_single_env; /* XXX: find a correct solution for multithread */
901
#if defined(DEBUG_SIGNAL)
902
    printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
903
           pc, address, is_write, *(unsigned long *)old_set);
904
#endif
905
    /* XXX: locking issue */
906
    if (is_write && page_unprotect(h2g(address), pc, puc)) {
907
        return 1;
908
    }
909

    
910
    /* see if it is an MMU fault */
911
    ret = cpu_ppc_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
912
    if (ret < 0)
913
        return 0; /* not an MMU fault */
914
    if (ret == 0)
915
        return 1; /* the MMU fault was handled without causing real CPU fault */
916

    
917
    /* now we have a real cpu fault */
918
    tb = tb_find_pc(pc);
919
    if (tb) {
920
        /* the PC is inside the translated code. It means that we have
921
           a virtual CPU fault */
922
        cpu_restore_state(tb, env, pc, puc);
923
    }
924
    if (ret == 1) {
925
#if 0
926
        printf("PF exception: NIP=0x%08x error=0x%x %p\n",
927
               env->nip, env->error_code, tb);
928
#endif
929
    /* we restore the process signal mask as the sigreturn should
930
       do it (XXX: use sigsetjmp) */
931
        sigprocmask(SIG_SETMASK, old_set, NULL);
932
        do_raise_exception_err(env->exception_index, env->error_code);
933
    } else {
934
        /* activate soft MMU for this block */
935
        cpu_resume_from_signal(env, puc);
936
    }
937
    /* never comes here */
938
    return 1;
939
}
940

    
941
#elif defined(TARGET_M68K)
942
static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
943
                                    int is_write, sigset_t *old_set,
944
                                    void *puc)
945
{
946
    TranslationBlock *tb;
947
    int ret;
948

    
949
    if (cpu_single_env)
950
        env = cpu_single_env; /* XXX: find a correct solution for multithread */
951
#if defined(DEBUG_SIGNAL)
952
    printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
953
           pc, address, is_write, *(unsigned long *)old_set);
954
#endif
955
    /* XXX: locking issue */
956
    if (is_write && page_unprotect(address, pc, puc)) {
957
        return 1;
958
    }
959
    /* see if it is an MMU fault */
960
    ret = cpu_m68k_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
961
    if (ret < 0)
962
        return 0; /* not an MMU fault */
963
    if (ret == 0)
964
        return 1; /* the MMU fault was handled without causing real CPU fault */
965
    /* now we have a real cpu fault */
966
    tb = tb_find_pc(pc);
967
    if (tb) {
968
        /* the PC is inside the translated code. It means that we have
969
           a virtual CPU fault */
970
        cpu_restore_state(tb, env, pc, puc);
971
    }
972
    /* we restore the process signal mask as the sigreturn should
973
       do it (XXX: use sigsetjmp) */
974
    sigprocmask(SIG_SETMASK, old_set, NULL);
975
    cpu_loop_exit();
976
    /* never comes here */
977
    return 1;
978
}
979

    
980
#elif defined (TARGET_MIPS)
981
static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
982
                                    int is_write, sigset_t *old_set,
983
                                    void *puc)
984
{
985
    TranslationBlock *tb;
986
    int ret;
987

    
988
    if (cpu_single_env)
989
        env = cpu_single_env; /* XXX: find a correct solution for multithread */
990
#if defined(DEBUG_SIGNAL)
991
    printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
992
           pc, address, is_write, *(unsigned long *)old_set);
993
#endif
994
    /* XXX: locking issue */
995
    if (is_write && page_unprotect(h2g(address), pc, puc)) {
996
        return 1;
997
    }
998

    
999
    /* see if it is an MMU fault */
1000
    ret = cpu_mips_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
1001
    if (ret < 0)
1002
        return 0; /* not an MMU fault */
1003
    if (ret == 0)
1004
        return 1; /* the MMU fault was handled without causing real CPU fault */
1005

    
1006
    /* now we have a real cpu fault */
1007
    tb = tb_find_pc(pc);
1008
    if (tb) {
1009
        /* the PC is inside the translated code. It means that we have
1010
           a virtual CPU fault */
1011
        cpu_restore_state(tb, env, pc, puc);
1012
    }
1013
    if (ret == 1) {
1014
#if 0
1015
        printf("PF exception: PC=0x" TARGET_FMT_lx " error=0x%x %p\n",
1016
               env->PC, env->error_code, tb);
1017
#endif
1018
    /* we restore the process signal mask as the sigreturn should
1019
       do it (XXX: use sigsetjmp) */
1020
        sigprocmask(SIG_SETMASK, old_set, NULL);
1021
        do_raise_exception_err(env->exception_index, env->error_code);
1022
    } else {
1023
        /* activate soft MMU for this block */
1024
        cpu_resume_from_signal(env, puc);
1025
    }
1026
    /* never comes here */
1027
    return 1;
1028
}
1029

    
1030
#elif defined (TARGET_SH4)
1031
static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
1032
                                    int is_write, sigset_t *old_set,
1033
                                    void *puc)
1034
{
1035
    TranslationBlock *tb;
1036
    int ret;
1037

    
1038
    if (cpu_single_env)
1039
        env = cpu_single_env; /* XXX: find a correct solution for multithread */
1040
#if defined(DEBUG_SIGNAL)
1041
    printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
1042
           pc, address, is_write, *(unsigned long *)old_set);
1043
#endif
1044
    /* XXX: locking issue */
1045
    if (is_write && page_unprotect(h2g(address), pc, puc)) {
1046
        return 1;
1047
    }
1048

    
1049
    /* see if it is an MMU fault */
1050
    ret = cpu_sh4_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
1051
    if (ret < 0)
1052
        return 0; /* not an MMU fault */
1053
    if (ret == 0)
1054
        return 1; /* the MMU fault was handled without causing real CPU fault */
1055

    
1056
    /* now we have a real cpu fault */
1057
    tb = tb_find_pc(pc);
1058
    if (tb) {
1059
        /* the PC is inside the translated code. It means that we have
1060
           a virtual CPU fault */
1061
        cpu_restore_state(tb, env, pc, puc);
1062
    }
1063
#if 0
1064
        printf("PF exception: NIP=0x%08x error=0x%x %p\n",
1065
               env->nip, env->error_code, tb);
1066
#endif
1067
    /* we restore the process signal mask as the sigreturn should
1068
       do it (XXX: use sigsetjmp) */
1069
    sigprocmask(SIG_SETMASK, old_set, NULL);
1070
    cpu_loop_exit();
1071
    /* never comes here */
1072
    return 1;
1073
}
1074

    
1075
#elif defined (TARGET_ALPHA)
1076
static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
1077
                                    int is_write, sigset_t *old_set,
1078
                                    void *puc)
1079
{
1080
    TranslationBlock *tb;
1081
    int ret;
1082

    
1083
    if (cpu_single_env)
1084
        env = cpu_single_env; /* XXX: find a correct solution for multithread */
1085
#if defined(DEBUG_SIGNAL)
1086
    printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
1087
           pc, address, is_write, *(unsigned long *)old_set);
1088
#endif
1089
    /* XXX: locking issue */
1090
    if (is_write && page_unprotect(h2g(address), pc, puc)) {
1091
        return 1;
1092
    }
1093

    
1094
    /* see if it is an MMU fault */
1095
    ret = cpu_alpha_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
1096
    if (ret < 0)
1097
        return 0; /* not an MMU fault */
1098
    if (ret == 0)
1099
        return 1; /* the MMU fault was handled without causing real CPU fault */
1100

    
1101
    /* now we have a real cpu fault */
1102
    tb = tb_find_pc(pc);
1103
    if (tb) {
1104
        /* the PC is inside the translated code. It means that we have
1105
           a virtual CPU fault */
1106
        cpu_restore_state(tb, env, pc, puc);
1107
    }
1108
#if 0
1109
        printf("PF exception: NIP=0x%08x error=0x%x %p\n",
1110
               env->nip, env->error_code, tb);
1111
#endif
1112
    /* we restore the process signal mask as the sigreturn should
1113
       do it (XXX: use sigsetjmp) */
1114
    sigprocmask(SIG_SETMASK, old_set, NULL);
1115
    cpu_loop_exit();
1116
    /* never comes here */
1117
    return 1;
1118
}
1119
#elif defined (TARGET_CRIS)
1120
static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
1121
                                    int is_write, sigset_t *old_set,
1122
                                    void *puc)
1123
{
1124
    TranslationBlock *tb;
1125
    int ret;
1126

    
1127
    if (cpu_single_env)
1128
        env = cpu_single_env; /* XXX: find a correct solution for multithread */
1129
#if defined(DEBUG_SIGNAL)
1130
    printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
1131
           pc, address, is_write, *(unsigned long *)old_set);
1132
#endif
1133
    /* XXX: locking issue */
1134
    if (is_write && page_unprotect(h2g(address), pc, puc)) {
1135
        return 1;
1136
    }
1137

    
1138
    /* see if it is an MMU fault */
1139
    ret = cpu_cris_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
1140
    if (ret < 0)
1141
        return 0; /* not an MMU fault */
1142
    if (ret == 0)
1143
        return 1; /* the MMU fault was handled without causing real CPU fault */
1144

    
1145
    /* now we have a real cpu fault */
1146
    tb = tb_find_pc(pc);
1147
    if (tb) {
1148
        /* the PC is inside the translated code. It means that we have
1149
           a virtual CPU fault */
1150
        cpu_restore_state(tb, env, pc, puc);
1151
    }
1152
#if 0
1153
        printf("PF exception: NIP=0x%08x error=0x%x %p\n",
1154
               env->nip, env->error_code, tb);
1155
#endif
1156
    /* we restore the process signal mask as the sigreturn should
1157
       do it (XXX: use sigsetjmp) */
1158
    sigprocmask(SIG_SETMASK, old_set, NULL);
1159
    cpu_loop_exit();
1160
    /* never comes here */
1161
    return 1;
1162
}
1163

    
1164
#else
1165
#error unsupported target CPU
1166
#endif
1167

    
1168
#if defined(__i386__)
1169

    
1170
#if defined(__APPLE__)
1171
# include <sys/ucontext.h>
1172

    
1173
# define EIP_sig(context)  (*((unsigned long*)&(context)->uc_mcontext->ss.eip))
1174
# define TRAP_sig(context)    ((context)->uc_mcontext->es.trapno)
1175
# define ERROR_sig(context)   ((context)->uc_mcontext->es.err)
1176
#else
1177
# define EIP_sig(context)     ((context)->uc_mcontext.gregs[REG_EIP])
1178
# define TRAP_sig(context)    ((context)->uc_mcontext.gregs[REG_TRAPNO])
1179
# define ERROR_sig(context)   ((context)->uc_mcontext.gregs[REG_ERR])
1180
#endif
1181

    
1182
int cpu_signal_handler(int host_signum, void *pinfo,
1183
                       void *puc)
1184
{
1185
    siginfo_t *info = pinfo;
1186
    struct ucontext *uc = puc;
1187
    unsigned long pc;
1188
    int trapno;
1189

    
1190
#ifndef REG_EIP
1191
/* for glibc 2.1 */
1192
#define REG_EIP    EIP
1193
#define REG_ERR    ERR
1194
#define REG_TRAPNO TRAPNO
1195
#endif
1196
    pc = EIP_sig(uc);
1197
    trapno = TRAP_sig(uc);
1198
    return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1199
                             trapno == 0xe ?
1200
                             (ERROR_sig(uc) >> 1) & 1 : 0,
1201
                             &uc->uc_sigmask, puc);
1202
}
1203

    
1204
#elif defined(__x86_64__)
1205

    
1206
int cpu_signal_handler(int host_signum, void *pinfo,
1207
                       void *puc)
1208
{
1209
    siginfo_t *info = pinfo;
1210
    struct ucontext *uc = puc;
1211
    unsigned long pc;
1212

    
1213
    pc = uc->uc_mcontext.gregs[REG_RIP];
1214
    return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1215
                             uc->uc_mcontext.gregs[REG_TRAPNO] == 0xe ?
1216
                             (uc->uc_mcontext.gregs[REG_ERR] >> 1) & 1 : 0,
1217
                             &uc->uc_sigmask, puc);
1218
}
1219

    
1220
#elif defined(__powerpc__)
1221

    
1222
/***********************************************************************
1223
 * signal context platform-specific definitions
1224
 * From Wine
1225
 */
1226
#ifdef linux
1227
/* All Registers access - only for local access */
1228
# define REG_sig(reg_name, context)                ((context)->uc_mcontext.regs->reg_name)
1229
/* Gpr Registers access  */
1230
# define GPR_sig(reg_num, context)                REG_sig(gpr[reg_num], context)
1231
# define IAR_sig(context)                        REG_sig(nip, context)        /* Program counter */
1232
# define MSR_sig(context)                        REG_sig(msr, context)   /* Machine State Register (Supervisor) */
1233
# define CTR_sig(context)                        REG_sig(ctr, context)   /* Count register */
1234
# define XER_sig(context)                        REG_sig(xer, context) /* User's integer exception register */
1235
# define LR_sig(context)                        REG_sig(link, context) /* Link register */
1236
# define CR_sig(context)                        REG_sig(ccr, context) /* Condition register */
1237
/* Float Registers access  */
1238
# define FLOAT_sig(reg_num, context)                (((double*)((char*)((context)->uc_mcontext.regs+48*4)))[reg_num])
1239
# define FPSCR_sig(context)                        (*(int*)((char*)((context)->uc_mcontext.regs+(48+32*2)*4)))
1240
/* Exception Registers access */
1241
# define DAR_sig(context)                        REG_sig(dar, context)
1242
# define DSISR_sig(context)                        REG_sig(dsisr, context)
1243
# define TRAP_sig(context)                        REG_sig(trap, context)
1244
#endif /* linux */
1245

    
1246
#ifdef __APPLE__
1247
# include <sys/ucontext.h>
1248
typedef struct ucontext SIGCONTEXT;
1249
/* All Registers access - only for local access */
1250
# define REG_sig(reg_name, context)                ((context)->uc_mcontext->ss.reg_name)
1251
# define FLOATREG_sig(reg_name, context)        ((context)->uc_mcontext->fs.reg_name)
1252
# define EXCEPREG_sig(reg_name, context)        ((context)->uc_mcontext->es.reg_name)
1253
# define VECREG_sig(reg_name, context)                ((context)->uc_mcontext->vs.reg_name)
1254
/* Gpr Registers access */
1255
# define GPR_sig(reg_num, context)                REG_sig(r##reg_num, context)
1256
# define IAR_sig(context)                        REG_sig(srr0, context)        /* Program counter */
1257
# define MSR_sig(context)                        REG_sig(srr1, context)  /* Machine State Register (Supervisor) */
1258
# define CTR_sig(context)                        REG_sig(ctr, context)
1259
# define XER_sig(context)                        REG_sig(xer, context) /* Link register */
1260
# define LR_sig(context)                        REG_sig(lr, context)  /* User's integer exception register */
1261
# define CR_sig(context)                        REG_sig(cr, context)  /* Condition register */
1262
/* Float Registers access */
1263
# define FLOAT_sig(reg_num, context)                FLOATREG_sig(fpregs[reg_num], context)
1264
# define FPSCR_sig(context)                        ((double)FLOATREG_sig(fpscr, context))
1265
/* Exception Registers access */
1266
# define DAR_sig(context)                        EXCEPREG_sig(dar, context)     /* Fault registers for coredump */
1267
# define DSISR_sig(context)                        EXCEPREG_sig(dsisr, context)
1268
# define TRAP_sig(context)                        EXCEPREG_sig(exception, context) /* number of powerpc exception taken */
1269
#endif /* __APPLE__ */
1270

    
1271
int cpu_signal_handler(int host_signum, void *pinfo,
1272
                       void *puc)
1273
{
1274
    siginfo_t *info = pinfo;
1275
    struct ucontext *uc = puc;
1276
    unsigned long pc;
1277
    int is_write;
1278

    
1279
    pc = IAR_sig(uc);
1280
    is_write = 0;
1281
#if 0
1282
    /* ppc 4xx case */
1283
    if (DSISR_sig(uc) & 0x00800000)
1284
        is_write = 1;
1285
#else
1286
    if (TRAP_sig(uc) != 0x400 && (DSISR_sig(uc) & 0x02000000))
1287
        is_write = 1;
1288
#endif
1289
    return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1290
                             is_write, &uc->uc_sigmask, puc);
1291
}
1292

    
1293
#elif defined(__alpha__)
1294

    
1295
int cpu_signal_handler(int host_signum, void *pinfo,
1296
                           void *puc)
1297
{
1298
    siginfo_t *info = pinfo;
1299
    struct ucontext *uc = puc;
1300
    uint32_t *pc = uc->uc_mcontext.sc_pc;
1301
    uint32_t insn = *pc;
1302
    int is_write = 0;
1303

    
1304
    /* XXX: need kernel patch to get write flag faster */
1305
    switch (insn >> 26) {
1306
    case 0x0d: // stw
1307
    case 0x0e: // stb
1308
    case 0x0f: // stq_u
1309
    case 0x24: // stf
1310
    case 0x25: // stg
1311
    case 0x26: // sts
1312
    case 0x27: // stt
1313
    case 0x2c: // stl
1314
    case 0x2d: // stq
1315
    case 0x2e: // stl_c
1316
    case 0x2f: // stq_c
1317
        is_write = 1;
1318
    }
1319

    
1320
    return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1321
                             is_write, &uc->uc_sigmask, puc);
1322
}
1323
#elif defined(__sparc__)
1324

    
1325
int cpu_signal_handler(int host_signum, void *pinfo,
1326
                       void *puc)
1327
{
1328
    siginfo_t *info = pinfo;
1329
    uint32_t *regs = (uint32_t *)(info + 1);
1330
    void *sigmask = (regs + 20);
1331
    unsigned long pc;
1332
    int is_write;
1333
    uint32_t insn;
1334

    
1335
    /* XXX: is there a standard glibc define ? */
1336
    pc = regs[1];
1337
    /* XXX: need kernel patch to get write flag faster */
1338
    is_write = 0;
1339
    insn = *(uint32_t *)pc;
1340
    if ((insn >> 30) == 3) {
1341
      switch((insn >> 19) & 0x3f) {
1342
      case 0x05: // stb
1343
      case 0x06: // sth
1344
      case 0x04: // st
1345
      case 0x07: // std
1346
      case 0x24: // stf
1347
      case 0x27: // stdf
1348
      case 0x25: // stfsr
1349
        is_write = 1;
1350
        break;
1351
      }
1352
    }
1353
    return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1354
                             is_write, sigmask, NULL);
1355
}
1356

    
1357
#elif defined(__arm__)
1358

    
1359
int cpu_signal_handler(int host_signum, void *pinfo,
1360
                       void *puc)
1361
{
1362
    siginfo_t *info = pinfo;
1363
    struct ucontext *uc = puc;
1364
    unsigned long pc;
1365
    int is_write;
1366

    
1367
    pc = uc->uc_mcontext.gregs[R15];
1368
    /* XXX: compute is_write */
1369
    is_write = 0;
1370
    return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1371
                             is_write,
1372
                             &uc->uc_sigmask, puc);
1373
}
1374

    
1375
#elif defined(__mc68000)
1376

    
1377
int cpu_signal_handler(int host_signum, void *pinfo,
1378
                       void *puc)
1379
{
1380
    siginfo_t *info = pinfo;
1381
    struct ucontext *uc = puc;
1382
    unsigned long pc;
1383
    int is_write;
1384

    
1385
    pc = uc->uc_mcontext.gregs[16];
1386
    /* XXX: compute is_write */
1387
    is_write = 0;
1388
    return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1389
                             is_write,
1390
                             &uc->uc_sigmask, puc);
1391
}
1392

    
1393
#elif defined(__ia64)
1394

    
1395
#ifndef __ISR_VALID
1396
  /* This ought to be in <bits/siginfo.h>... */
1397
# define __ISR_VALID        1
1398
#endif
1399

    
1400
int cpu_signal_handler(int host_signum, void *pinfo, void *puc)
1401
{
1402
    siginfo_t *info = pinfo;
1403
    struct ucontext *uc = puc;
1404
    unsigned long ip;
1405
    int is_write = 0;
1406

    
1407
    ip = uc->uc_mcontext.sc_ip;
1408
    switch (host_signum) {
1409
      case SIGILL:
1410
      case SIGFPE:
1411
      case SIGSEGV:
1412
      case SIGBUS:
1413
      case SIGTRAP:
1414
          if (info->si_code && (info->si_segvflags & __ISR_VALID))
1415
              /* ISR.W (write-access) is bit 33:  */
1416
              is_write = (info->si_isr >> 33) & 1;
1417
          break;
1418

    
1419
      default:
1420
          break;
1421
    }
1422
    return handle_cpu_signal(ip, (unsigned long)info->si_addr,
1423
                             is_write,
1424
                             &uc->uc_sigmask, puc);
1425
}
1426

    
1427
#elif defined(__s390__)
1428

    
1429
int cpu_signal_handler(int host_signum, void *pinfo,
1430
                       void *puc)
1431
{
1432
    siginfo_t *info = pinfo;
1433
    struct ucontext *uc = puc;
1434
    unsigned long pc;
1435
    int is_write;
1436

    
1437
    pc = uc->uc_mcontext.psw.addr;
1438
    /* XXX: compute is_write */
1439
    is_write = 0;
1440
    return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1441
                             is_write, &uc->uc_sigmask, puc);
1442
}
1443

    
1444
#elif defined(__mips__)
1445

    
1446
int cpu_signal_handler(int host_signum, void *pinfo,
1447
                       void *puc)
1448
{
1449
    siginfo_t *info = pinfo;
1450
    struct ucontext *uc = puc;
1451
    greg_t pc = uc->uc_mcontext.pc;
1452
    int is_write;
1453

    
1454
    /* XXX: compute is_write */
1455
    is_write = 0;
1456
    return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1457
                             is_write, &uc->uc_sigmask, puc);
1458
}
1459

    
1460
#else
1461

    
1462
#error host CPU specific signal handler needed
1463

    
1464
#endif
1465

    
1466
#endif /* !defined(CONFIG_SOFTMMU) */