Fix Sparc32 interrupt handling
[qemu] / cpu-exec.c
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                                       unsigned int 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     unsigned int 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     cs_base = env->segs[R_CS].base;
167     pc = cs_base + env->eip;
168 #elif defined(TARGET_ARM)
169     flags = env->thumb | (env->vfp.vec_len << 1)
170             | (env->vfp.vec_stride << 4);
171     if ((env->uncached_cpsr & CPSR_M) != ARM_CPU_MODE_USR)
172         flags |= (1 << 6);
173     if (env->vfp.xregs[ARM_VFP_FPEXC] & (1 << 30))
174         flags |= (1 << 7);
175     cs_base = 0;
176     pc = env->regs[15];
177 #elif defined(TARGET_SPARC)
178 #ifdef TARGET_SPARC64
179     // Combined FPU enable bits . PRIV . DMMU enabled . IMMU enabled
180     flags = (((env->pstate & PS_PEF) >> 1) | ((env->fprs & FPRS_FEF) << 2))
181         | (env->pstate & PS_PRIV) | ((env->lsu & (DMMU_E | IMMU_E)) >> 2);
182 #else
183     // FPU enable . MMU enabled . MMU no-fault . Supervisor
184     flags = (env->psref << 3) | ((env->mmuregs[0] & (MMU_E | MMU_NF)) << 1)
185         | env->psrs;
186 #endif
187     cs_base = env->npc;
188     pc = env->pc;
189 #elif defined(TARGET_PPC)
190     flags = (msr_pr << MSR_PR) | (msr_fp << MSR_FP) |
191         (msr_se << MSR_SE) | (msr_le << MSR_LE);
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;
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 #else
213 #error unsupported CPU
214 #endif
215     tb = env->tb_jmp_cache[tb_jmp_cache_hash_func(pc)];
216     if (__builtin_expect(!tb || tb->pc != pc || tb->cs_base != cs_base ||
217                          tb->flags != flags, 0)) {
218         tb = tb_find_slow(pc, cs_base, flags);
219         /* Note: we do it here to avoid a gcc bug on Mac OS X when
220            doing it in tb_find_slow */
221         if (tb_invalidated_flag) {
222             /* as some TB could have been invalidated because
223                of memory exceptions while generating the code, we
224                must recompute the hash index here */
225             T0 = 0;
226         }
227     }
228     return tb;
229 }
230
231
232 /* main execution loop */
233
234 int cpu_exec(CPUState *env1)
235 {
236 #define DECLARE_HOST_REGS 1
237 #include "hostregs_helper.h"
238 #if defined(TARGET_SPARC)
239 #if defined(reg_REGWPTR)
240     uint32_t *saved_regwptr;
241 #endif
242 #endif
243 #if defined(__sparc__) && !defined(HOST_SOLARIS)
244     int saved_i7;
245     target_ulong tmp_T0;
246 #endif
247     int ret, interrupt_request;
248     void (*gen_func)(void);
249     TranslationBlock *tb;
250     uint8_t *tc_ptr;
251
252     if (cpu_halted(env1) == EXCP_HALTED)
253         return EXCP_HALTED;
254
255     cpu_single_env = env1; 
256
257     /* first we save global registers */
258 #define SAVE_HOST_REGS 1
259 #include "hostregs_helper.h"
260     env = env1;
261 #if defined(__sparc__) && !defined(HOST_SOLARIS)
262     /* we also save i7 because longjmp may not restore it */
263     asm volatile ("mov %%i7, %0" : "=r" (saved_i7));
264 #endif
265
266     env_to_regs();
267 #if defined(TARGET_I386)
268     /* put eflags in CPU temporary format */
269     CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
270     DF = 1 - (2 * ((env->eflags >> 10) & 1));
271     CC_OP = CC_OP_EFLAGS;
272     env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
273 #elif defined(TARGET_SPARC)
274 #if defined(reg_REGWPTR)
275     saved_regwptr = REGWPTR;
276 #endif
277 #elif defined(TARGET_M68K)
278     env->cc_op = CC_OP_FLAGS;
279     env->cc_dest = env->sr & 0xf;
280     env->cc_x = (env->sr >> 4) & 1;
281 #elif defined(TARGET_ALPHA)
282 #elif defined(TARGET_ARM)
283 #elif defined(TARGET_PPC)
284 #elif defined(TARGET_MIPS)
285 #elif defined(TARGET_SH4)
286     /* XXXXX */
287 #else
288 #error unsupported target CPU
289 #endif
290     env->exception_index = -1;
291
292     /* prepare setjmp context for exception handling */
293     for(;;) {
294         if (setjmp(env->jmp_env) == 0) {
295             env->current_tb = NULL;
296             /* if an exception is pending, we execute it here */
297             if (env->exception_index >= 0) {
298                 if (env->exception_index >= EXCP_INTERRUPT) {
299                     /* exit request from the cpu execution loop */
300                     ret = env->exception_index;
301                     break;
302                 } else if (env->user_mode_only) {
303                     /* if user mode only, we simulate a fake exception
304                        which will be handled outside the cpu execution
305                        loop */
306 #if defined(TARGET_I386)
307                     do_interrupt_user(env->exception_index, 
308                                       env->exception_is_int, 
309                                       env->error_code, 
310                                       env->exception_next_eip);
311 #endif
312                     ret = env->exception_index;
313                     break;
314                 } else {
315 #if defined(TARGET_I386)
316                     /* simulate a real cpu exception. On i386, it can
317                        trigger new exceptions, but we do not handle
318                        double or triple faults yet. */
319                     do_interrupt(env->exception_index, 
320                                  env->exception_is_int, 
321                                  env->error_code, 
322                                  env->exception_next_eip, 0);
323                     /* successfully delivered */
324                     env->old_exception = -1;
325 #elif defined(TARGET_PPC)
326                     do_interrupt(env);
327 #elif defined(TARGET_MIPS)
328                     do_interrupt(env);
329 #elif defined(TARGET_SPARC)
330                     do_interrupt(env->exception_index);
331 #elif defined(TARGET_ARM)
332                     do_interrupt(env);
333 #elif defined(TARGET_SH4)
334                     do_interrupt(env);
335 #elif defined(TARGET_ALPHA)
336                     do_interrupt(env);
337 #elif defined(TARGET_M68K)
338                     do_interrupt(0);
339 #endif
340                 }
341                 env->exception_index = -1;
342             } 
343 #ifdef USE_KQEMU
344             if (kqemu_is_ok(env) && env->interrupt_request == 0) {
345                 int ret;
346                 env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
347                 ret = kqemu_cpu_exec(env);
348                 /* put eflags in CPU temporary format */
349                 CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
350                 DF = 1 - (2 * ((env->eflags >> 10) & 1));
351                 CC_OP = CC_OP_EFLAGS;
352                 env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
353                 if (ret == 1) {
354                     /* exception */
355                     longjmp(env->jmp_env, 1);
356                 } else if (ret == 2) {
357                     /* softmmu execution needed */
358                 } else {
359                     if (env->interrupt_request != 0) {
360                         /* hardware interrupt will be executed just after */
361                     } else {
362                         /* otherwise, we restart */
363                         longjmp(env->jmp_env, 1);
364                     }
365                 }
366             }
367 #endif
368
369             T0 = 0; /* force lookup of first TB */
370             for(;;) {
371 #if defined(__sparc__) && !defined(HOST_SOLARIS)
372                 /* g1 can be modified by some libc? functions */ 
373                 tmp_T0 = T0;
374 #endif      
375                 interrupt_request = env->interrupt_request;
376                 if (__builtin_expect(interrupt_request, 0)) {
377                     if (interrupt_request & CPU_INTERRUPT_DEBUG) {
378                         env->interrupt_request &= ~CPU_INTERRUPT_DEBUG;
379                         env->exception_index = EXCP_DEBUG;
380                         cpu_loop_exit();
381                     }
382 #if defined(TARGET_ARM) || defined(TARGET_SPARC) || defined(TARGET_MIPS) || \
383     defined(TARGET_PPC) || defined(TARGET_ALPHA)
384                     if (interrupt_request & CPU_INTERRUPT_HALT) {
385                         env->interrupt_request &= ~CPU_INTERRUPT_HALT;
386                         env->halted = 1;
387                         env->exception_index = EXCP_HLT;
388                         cpu_loop_exit();
389                     }
390 #endif
391 #if defined(TARGET_I386)
392                     if ((interrupt_request & CPU_INTERRUPT_SMI) &&
393                         !(env->hflags & HF_SMM_MASK)) {
394                         env->interrupt_request &= ~CPU_INTERRUPT_SMI;
395                         do_smm_enter();
396 #if defined(__sparc__) && !defined(HOST_SOLARIS)
397                         tmp_T0 = 0;
398 #else
399                         T0 = 0;
400 #endif
401                     } else if ((interrupt_request & CPU_INTERRUPT_HARD) &&
402                         (env->eflags & IF_MASK) && 
403                         !(env->hflags & HF_INHIBIT_IRQ_MASK)) {
404                         int intno;
405                         env->interrupt_request &= ~CPU_INTERRUPT_HARD;
406                         intno = cpu_get_pic_interrupt(env);
407                         if (loglevel & CPU_LOG_TB_IN_ASM) {
408                             fprintf(logfile, "Servicing hardware INT=0x%02x\n", intno);
409                         }
410                         do_interrupt(intno, 0, 0, 0, 1);
411                         /* ensure that no TB jump will be modified as
412                            the program flow was changed */
413 #if defined(__sparc__) && !defined(HOST_SOLARIS)
414                         tmp_T0 = 0;
415 #else
416                         T0 = 0;
417 #endif
418                     }
419 #elif defined(TARGET_PPC)
420 #if 0
421                     if ((interrupt_request & CPU_INTERRUPT_RESET)) {
422                         cpu_ppc_reset(env);
423                     }
424 #endif
425                     if (interrupt_request & CPU_INTERRUPT_HARD) {
426                         ppc_hw_interrupt(env);
427                         if (env->pending_interrupts == 0)
428                             env->interrupt_request &= ~CPU_INTERRUPT_HARD;
429 #if defined(__sparc__) && !defined(HOST_SOLARIS)
430                         tmp_T0 = 0;
431 #else
432                         T0 = 0;
433 #endif
434                     }
435 #elif defined(TARGET_MIPS)
436                     if ((interrupt_request & CPU_INTERRUPT_HARD) &&
437                         (env->CP0_Status & env->CP0_Cause & CP0Ca_IP_mask) &&
438                         (env->CP0_Status & (1 << CP0St_IE)) &&
439                         !(env->CP0_Status & (1 << CP0St_EXL)) &&
440                         !(env->CP0_Status & (1 << CP0St_ERL)) &&
441                         !(env->hflags & MIPS_HFLAG_DM)) {
442                         /* Raise it */
443                         env->exception_index = EXCP_EXT_INTERRUPT;
444                         env->error_code = 0;
445                         do_interrupt(env);
446 #if defined(__sparc__) && !defined(HOST_SOLARIS)
447                         tmp_T0 = 0;
448 #else
449                         T0 = 0;
450 #endif
451                     }
452 #elif defined(TARGET_SPARC)
453                     if ((interrupt_request & CPU_INTERRUPT_HARD) &&
454                         (env->psret != 0)) {
455                         int pil = env->interrupt_index & 15;
456                         int type = env->interrupt_index & 0xf0;
457
458                         if (((type == TT_EXTINT) &&
459                              (pil == 15 || pil > env->psrpil)) ||
460                             type != TT_EXTINT) {
461                             env->interrupt_request &= ~CPU_INTERRUPT_HARD;
462                             do_interrupt(env->interrupt_index);
463                             env->interrupt_index = 0;
464 #if !defined(TARGET_SPARC64) && !defined(CONFIG_USER_ONLY)
465                             cpu_check_irqs(env);
466 #endif
467 #if defined(__sparc__) && !defined(HOST_SOLARIS)
468                             tmp_T0 = 0;
469 #else
470                             T0 = 0;
471 #endif
472                         }
473                     } else if (interrupt_request & CPU_INTERRUPT_TIMER) {
474                         //do_interrupt(0, 0, 0, 0, 0);
475                         env->interrupt_request &= ~CPU_INTERRUPT_TIMER;
476                     }
477 #elif defined(TARGET_ARM)
478                     if (interrupt_request & CPU_INTERRUPT_FIQ
479                         && !(env->uncached_cpsr & CPSR_F)) {
480                         env->exception_index = EXCP_FIQ;
481                         do_interrupt(env);
482                     }
483                     if (interrupt_request & CPU_INTERRUPT_HARD
484                         && !(env->uncached_cpsr & CPSR_I)) {
485                         env->exception_index = EXCP_IRQ;
486                         do_interrupt(env);
487                     }
488 #elif defined(TARGET_SH4)
489                     /* XXXXX */
490 #elif defined(TARGET_ALPHA)
491                     if (interrupt_request & CPU_INTERRUPT_HARD) {
492                         do_interrupt(env);
493                     }
494 #elif defined(TARGET_M68K)
495                     if (interrupt_request & CPU_INTERRUPT_HARD
496                         && ((env->sr & SR_I) >> SR_I_SHIFT)
497                             < env->pending_level) {
498                         /* Real hardware gets the interrupt vector via an
499                            IACK cycle at this point.  Current emulated
500                            hardware doesn't rely on this, so we
501                            provide/save the vector when the interrupt is
502                            first signalled.  */
503                         env->exception_index = env->pending_vector;
504                         do_interrupt(1);
505                     }
506 #endif
507                    /* Don't use the cached interupt_request value,
508                       do_interrupt may have updated the EXITTB flag. */
509                     if (env->interrupt_request & CPU_INTERRUPT_EXITTB) {
510                         env->interrupt_request &= ~CPU_INTERRUPT_EXITTB;
511                         /* ensure that no TB jump will be modified as
512                            the program flow was changed */
513 #if defined(__sparc__) && !defined(HOST_SOLARIS)
514                         tmp_T0 = 0;
515 #else
516                         T0 = 0;
517 #endif
518                     }
519                     if (interrupt_request & CPU_INTERRUPT_EXIT) {
520                         env->interrupt_request &= ~CPU_INTERRUPT_EXIT;
521                         env->exception_index = EXCP_INTERRUPT;
522                         cpu_loop_exit();
523                     }
524                 }
525 #ifdef DEBUG_EXEC
526                 if ((loglevel & CPU_LOG_TB_CPU)) {
527                     /* restore flags in standard format */
528                     regs_to_env();
529 #if defined(TARGET_I386)
530                     env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
531                     cpu_dump_state(env, logfile, fprintf, X86_DUMP_CCOP);
532                     env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
533 #elif defined(TARGET_ARM)
534                     cpu_dump_state(env, logfile, fprintf, 0);
535 #elif defined(TARGET_SPARC)
536                     REGWPTR = env->regbase + (env->cwp * 16);
537                     env->regwptr = REGWPTR;
538                     cpu_dump_state(env, logfile, fprintf, 0);
539 #elif defined(TARGET_PPC)
540                     cpu_dump_state(env, logfile, fprintf, 0);
541 #elif defined(TARGET_M68K)
542                     cpu_m68k_flush_flags(env, env->cc_op);
543                     env->cc_op = CC_OP_FLAGS;
544                     env->sr = (env->sr & 0xffe0)
545                               | env->cc_dest | (env->cc_x << 4);
546                     cpu_dump_state(env, logfile, fprintf, 0);
547 #elif defined(TARGET_MIPS)
548                     cpu_dump_state(env, logfile, fprintf, 0);
549 #elif defined(TARGET_SH4)
550                     cpu_dump_state(env, logfile, fprintf, 0);
551 #elif defined(TARGET_ALPHA)
552                     cpu_dump_state(env, logfile, fprintf, 0);
553 #else
554 #error unsupported target CPU 
555 #endif
556                 }
557 #endif
558                 tb = tb_find_fast();
559 #ifdef DEBUG_EXEC
560                 if ((loglevel & CPU_LOG_EXEC)) {
561                     fprintf(logfile, "Trace 0x%08lx [" TARGET_FMT_lx "] %s\n",
562                             (long)tb->tc_ptr, tb->pc,
563                             lookup_symbol(tb->pc));
564                 }
565 #endif
566 #if defined(__sparc__) && !defined(HOST_SOLARIS)
567                 T0 = tmp_T0;
568 #endif      
569                 /* see if we can patch the calling TB. When the TB
570                    spans two pages, we cannot safely do a direct
571                    jump. */
572                 {
573                     if (T0 != 0 &&
574 #if USE_KQEMU
575                         (env->kqemu_enabled != 2) &&
576 #endif
577                         tb->page_addr[1] == -1
578 #if defined(TARGET_I386) && defined(USE_CODE_COPY)
579                     && (tb->cflags & CF_CODE_COPY) == 
580                     (((TranslationBlock *)(T0 & ~3))->cflags & CF_CODE_COPY)
581 #endif
582                     ) {
583                     spin_lock(&tb_lock);
584                     tb_add_jump((TranslationBlock *)(long)(T0 & ~3), T0 & 3, tb);
585 #if defined(USE_CODE_COPY)
586                     /* propagates the FP use info */
587                     ((TranslationBlock *)(T0 & ~3))->cflags |= 
588                         (tb->cflags & CF_FP_USED);
589 #endif
590                     spin_unlock(&tb_lock);
591                 }
592                 }
593                 tc_ptr = tb->tc_ptr;
594                 env->current_tb = tb;
595                 /* execute the generated code */
596                 gen_func = (void *)tc_ptr;
597 #if defined(__sparc__)
598                 __asm__ __volatile__("call      %0\n\t"
599                                      "mov       %%o7,%%i0"
600                                      : /* no outputs */
601                                      : "r" (gen_func) 
602                                      : "i0", "i1", "i2", "i3", "i4", "i5",
603                                        "o0", "o1", "o2", "o3", "o4", "o5",
604                                        "l0", "l1", "l2", "l3", "l4", "l5",
605                                        "l6", "l7");
606 #elif defined(__arm__)
607                 asm volatile ("mov pc, %0\n\t"
608                               ".global exec_loop\n\t"
609                               "exec_loop:\n\t"
610                               : /* no outputs */
611                               : "r" (gen_func)
612                               : "r1", "r2", "r3", "r8", "r9", "r10", "r12", "r14");
613 #elif defined(TARGET_I386) && defined(USE_CODE_COPY)
614 {
615     if (!(tb->cflags & CF_CODE_COPY)) {
616         if ((tb->cflags & CF_FP_USED) && env->native_fp_regs) {
617             save_native_fp_state(env);
618         }
619         gen_func();
620     } else {
621         if ((tb->cflags & CF_FP_USED) && !env->native_fp_regs) {
622             restore_native_fp_state(env);
623         }
624         /* we work with native eflags */
625         CC_SRC = cc_table[CC_OP].compute_all();
626         CC_OP = CC_OP_EFLAGS;
627         asm(".globl exec_loop\n"
628             "\n"
629             "debug1:\n"
630             "    pushl %%ebp\n"
631             "    fs movl %10, %9\n"
632             "    fs movl %11, %%eax\n"
633             "    andl $0x400, %%eax\n"
634             "    fs orl %8, %%eax\n"
635             "    pushl %%eax\n"
636             "    popf\n"
637             "    fs movl %%esp, %12\n"
638             "    fs movl %0, %%eax\n"
639             "    fs movl %1, %%ecx\n"
640             "    fs movl %2, %%edx\n"
641             "    fs movl %3, %%ebx\n"
642             "    fs movl %4, %%esp\n"
643             "    fs movl %5, %%ebp\n"
644             "    fs movl %6, %%esi\n"
645             "    fs movl %7, %%edi\n"
646             "    fs jmp *%9\n"
647             "exec_loop:\n"
648             "    fs movl %%esp, %4\n"
649             "    fs movl %12, %%esp\n"
650             "    fs movl %%eax, %0\n"
651             "    fs movl %%ecx, %1\n"
652             "    fs movl %%edx, %2\n"
653             "    fs movl %%ebx, %3\n"
654             "    fs movl %%ebp, %5\n"
655             "    fs movl %%esi, %6\n"
656             "    fs movl %%edi, %7\n"
657             "    pushf\n"
658             "    popl %%eax\n"
659             "    movl %%eax, %%ecx\n"
660             "    andl $0x400, %%ecx\n"
661             "    shrl $9, %%ecx\n"
662             "    andl $0x8d5, %%eax\n"
663             "    fs movl %%eax, %8\n"
664             "    movl $1, %%eax\n"
665             "    subl %%ecx, %%eax\n"
666             "    fs movl %%eax, %11\n"
667             "    fs movl %9, %%ebx\n" /* get T0 value */
668             "    popl %%ebp\n"
669             :
670             : "m" (*(uint8_t *)offsetof(CPUState, regs[0])),
671             "m" (*(uint8_t *)offsetof(CPUState, regs[1])),
672             "m" (*(uint8_t *)offsetof(CPUState, regs[2])),
673             "m" (*(uint8_t *)offsetof(CPUState, regs[3])),
674             "m" (*(uint8_t *)offsetof(CPUState, regs[4])),
675             "m" (*(uint8_t *)offsetof(CPUState, regs[5])),
676             "m" (*(uint8_t *)offsetof(CPUState, regs[6])),
677             "m" (*(uint8_t *)offsetof(CPUState, regs[7])),
678             "m" (*(uint8_t *)offsetof(CPUState, cc_src)),
679             "m" (*(uint8_t *)offsetof(CPUState, tmp0)),
680             "a" (gen_func),
681             "m" (*(uint8_t *)offsetof(CPUState, df)),
682             "m" (*(uint8_t *)offsetof(CPUState, saved_esp))
683             : "%ecx", "%edx"
684             );
685     }
686 }
687 #elif defined(__ia64)
688                 struct fptr {
689                         void *ip;
690                         void *gp;
691                 } fp;
692
693                 fp.ip = tc_ptr;
694                 fp.gp = code_gen_buffer + 2 * (1 << 20);
695                 (*(void (*)(void)) &fp)();
696 #else
697                 gen_func();
698 #endif
699                 env->current_tb = NULL;
700                 /* reset soft MMU for next block (it can currently
701                    only be set by a memory fault) */
702 #if defined(TARGET_I386) && !defined(CONFIG_SOFTMMU)
703                 if (env->hflags & HF_SOFTMMU_MASK) {
704                     env->hflags &= ~HF_SOFTMMU_MASK;
705                     /* do not allow linking to another block */
706                     T0 = 0;
707                 }
708 #endif
709 #if defined(USE_KQEMU)
710 #define MIN_CYCLE_BEFORE_SWITCH (100 * 1000)
711                 if (kqemu_is_ok(env) &&
712                     (cpu_get_time_fast() - env->last_io_time) >= MIN_CYCLE_BEFORE_SWITCH) {
713                     cpu_loop_exit();
714                 }
715 #endif
716             } /* for(;;) */
717         } else {
718             env_to_regs();
719         }
720     } /* for(;;) */
721
722
723 #if defined(TARGET_I386)
724 #if defined(USE_CODE_COPY)
725     if (env->native_fp_regs) {
726         save_native_fp_state(env);
727     }
728 #endif
729     /* restore flags in standard format */
730     env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
731 #elif defined(TARGET_ARM)
732     /* XXX: Save/restore host fpu exception state?.  */
733 #elif defined(TARGET_SPARC)
734 #if defined(reg_REGWPTR)
735     REGWPTR = saved_regwptr;
736 #endif
737 #elif defined(TARGET_PPC)
738 #elif defined(TARGET_M68K)
739     cpu_m68k_flush_flags(env, env->cc_op);
740     env->cc_op = CC_OP_FLAGS;
741     env->sr = (env->sr & 0xffe0)
742               | env->cc_dest | (env->cc_x << 4);
743 #elif defined(TARGET_MIPS)
744 #elif defined(TARGET_SH4)
745 #elif defined(TARGET_ALPHA)
746     /* XXXXX */
747 #else
748 #error unsupported target CPU
749 #endif
750
751     /* restore global registers */
752 #if defined(__sparc__) && !defined(HOST_SOLARIS)
753     asm volatile ("mov %0, %%i7" : : "r" (saved_i7));
754 #endif
755 #include "hostregs_helper.h"
756
757     /* fail safe : never use cpu_single_env outside cpu_exec() */
758     cpu_single_env = NULL; 
759     return ret;
760 }
761
762 /* must only be called from the generated code as an exception can be
763    generated */
764 void tb_invalidate_page_range(target_ulong start, target_ulong end)
765 {
766     /* XXX: cannot enable it yet because it yields to MMU exception
767        where NIP != read address on PowerPC */
768 #if 0
769     target_ulong phys_addr;
770     phys_addr = get_phys_addr_code(env, start);
771     tb_invalidate_phys_page_range(phys_addr, phys_addr + end - start, 0);
772 #endif
773 }
774
775 #if defined(TARGET_I386) && defined(CONFIG_USER_ONLY)
776
777 void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector)
778 {
779     CPUX86State *saved_env;
780
781     saved_env = env;
782     env = s;
783     if (!(env->cr[0] & CR0_PE_MASK) || (env->eflags & VM_MASK)) {
784         selector &= 0xffff;
785         cpu_x86_load_seg_cache(env, seg_reg, selector, 
786                                (selector << 4), 0xffff, 0);
787     } else {
788         load_seg(seg_reg, selector);
789     }
790     env = saved_env;
791 }
792
793 void cpu_x86_fsave(CPUX86State *s, uint8_t *ptr, int data32)
794 {
795     CPUX86State *saved_env;
796
797     saved_env = env;
798     env = s;
799     
800     helper_fsave((target_ulong)ptr, data32);
801
802     env = saved_env;
803 }
804
805 void cpu_x86_frstor(CPUX86State *s, uint8_t *ptr, int data32)
806 {
807     CPUX86State *saved_env;
808
809     saved_env = env;
810     env = s;
811     
812     helper_frstor((target_ulong)ptr, data32);
813
814     env = saved_env;
815 }
816
817 #endif /* TARGET_I386 */
818
819 #if !defined(CONFIG_SOFTMMU)
820
821 #if defined(TARGET_I386)
822
823 /* 'pc' is the host PC at which the exception was raised. 'address' is
824    the effective address of the memory exception. 'is_write' is 1 if a
825    write caused the exception and otherwise 0'. 'old_set' is the
826    signal set which should be restored */
827 static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
828                                     int is_write, sigset_t *old_set, 
829                                     void *puc)
830 {
831     TranslationBlock *tb;
832     int ret;
833
834     if (cpu_single_env)
835         env = cpu_single_env; /* XXX: find a correct solution for multithread */
836 #if defined(DEBUG_SIGNAL)
837     qemu_printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n", 
838                 pc, address, is_write, *(unsigned long *)old_set);
839 #endif
840     /* XXX: locking issue */
841     if (is_write && page_unprotect(h2g(address), pc, puc)) {
842         return 1;
843     }
844
845     /* see if it is an MMU fault */
846     ret = cpu_x86_handle_mmu_fault(env, address, is_write, 
847                                    ((env->hflags & HF_CPL_MASK) == 3), 0);
848     if (ret < 0)
849         return 0; /* not an MMU fault */
850     if (ret == 0)
851         return 1; /* the MMU fault was handled without causing real CPU fault */
852     /* now we have a real cpu fault */
853     tb = tb_find_pc(pc);
854     if (tb) {
855         /* the PC is inside the translated code. It means that we have
856            a virtual CPU fault */
857         cpu_restore_state(tb, env, pc, puc);
858     }
859     if (ret == 1) {
860 #if 0
861         printf("PF exception: EIP=0x%08x CR2=0x%08x error=0x%x\n", 
862                env->eip, env->cr[2], env->error_code);
863 #endif
864         /* we restore the process signal mask as the sigreturn should
865            do it (XXX: use sigsetjmp) */
866         sigprocmask(SIG_SETMASK, old_set, NULL);
867         raise_exception_err(env->exception_index, env->error_code);
868     } else {
869         /* activate soft MMU for this block */
870         env->hflags |= HF_SOFTMMU_MASK;
871         cpu_resume_from_signal(env, puc);
872     }
873     /* never comes here */
874     return 1;
875 }
876
877 #elif defined(TARGET_ARM)
878 static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
879                                     int is_write, sigset_t *old_set,
880                                     void *puc)
881 {
882     TranslationBlock *tb;
883     int ret;
884
885     if (cpu_single_env)
886         env = cpu_single_env; /* XXX: find a correct solution for multithread */
887 #if defined(DEBUG_SIGNAL)
888     printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n", 
889            pc, address, is_write, *(unsigned long *)old_set);
890 #endif
891     /* XXX: locking issue */
892     if (is_write && page_unprotect(h2g(address), pc, puc)) {
893         return 1;
894     }
895     /* see if it is an MMU fault */
896     ret = cpu_arm_handle_mmu_fault(env, address, is_write, 1, 0);
897     if (ret < 0)
898         return 0; /* not an MMU fault */
899     if (ret == 0)
900         return 1; /* the MMU fault was handled without causing real CPU fault */
901     /* now we have a real cpu fault */
902     tb = tb_find_pc(pc);
903     if (tb) {
904         /* the PC is inside the translated code. It means that we have
905            a virtual CPU fault */
906         cpu_restore_state(tb, env, pc, puc);
907     }
908     /* we restore the process signal mask as the sigreturn should
909        do it (XXX: use sigsetjmp) */
910     sigprocmask(SIG_SETMASK, old_set, NULL);
911     cpu_loop_exit();
912 }
913 #elif defined(TARGET_SPARC)
914 static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
915                                     int is_write, sigset_t *old_set,
916                                     void *puc)
917 {
918     TranslationBlock *tb;
919     int ret;
920
921     if (cpu_single_env)
922         env = cpu_single_env; /* XXX: find a correct solution for multithread */
923 #if defined(DEBUG_SIGNAL)
924     printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n", 
925            pc, address, is_write, *(unsigned long *)old_set);
926 #endif
927     /* XXX: locking issue */
928     if (is_write && page_unprotect(h2g(address), pc, puc)) {
929         return 1;
930     }
931     /* see if it is an MMU fault */
932     ret = cpu_sparc_handle_mmu_fault(env, address, is_write, 1, 0);
933     if (ret < 0)
934         return 0; /* not an MMU fault */
935     if (ret == 0)
936         return 1; /* the MMU fault was handled without causing real CPU fault */
937     /* now we have a real cpu fault */
938     tb = tb_find_pc(pc);
939     if (tb) {
940         /* the PC is inside the translated code. It means that we have
941            a virtual CPU fault */
942         cpu_restore_state(tb, env, pc, puc);
943     }
944     /* we restore the process signal mask as the sigreturn should
945        do it (XXX: use sigsetjmp) */
946     sigprocmask(SIG_SETMASK, old_set, NULL);
947     cpu_loop_exit();
948 }
949 #elif defined (TARGET_PPC)
950 static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
951                                     int is_write, sigset_t *old_set,
952                                     void *puc)
953 {
954     TranslationBlock *tb;
955     int ret;
956     
957     if (cpu_single_env)
958         env = cpu_single_env; /* XXX: find a correct solution for multithread */
959 #if defined(DEBUG_SIGNAL)
960     printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n", 
961            pc, address, is_write, *(unsigned long *)old_set);
962 #endif
963     /* XXX: locking issue */
964     if (is_write && page_unprotect(h2g(address), pc, puc)) {
965         return 1;
966     }
967
968     /* see if it is an MMU fault */
969     ret = cpu_ppc_handle_mmu_fault(env, address, is_write, msr_pr, 0);
970     if (ret < 0)
971         return 0; /* not an MMU fault */
972     if (ret == 0)
973         return 1; /* the MMU fault was handled without causing real CPU fault */
974
975     /* now we have a real cpu fault */
976     tb = tb_find_pc(pc);
977     if (tb) {
978         /* the PC is inside the translated code. It means that we have
979            a virtual CPU fault */
980         cpu_restore_state(tb, env, pc, puc);
981     }
982     if (ret == 1) {
983 #if 0
984         printf("PF exception: NIP=0x%08x error=0x%x %p\n", 
985                env->nip, env->error_code, tb);
986 #endif
987     /* we restore the process signal mask as the sigreturn should
988        do it (XXX: use sigsetjmp) */
989         sigprocmask(SIG_SETMASK, old_set, NULL);
990         do_raise_exception_err(env->exception_index, env->error_code);
991     } else {
992         /* activate soft MMU for this block */
993         cpu_resume_from_signal(env, puc);
994     }
995     /* never comes here */
996     return 1;
997 }
998
999 #elif defined(TARGET_M68K)
1000 static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
1001                                     int is_write, sigset_t *old_set,
1002                                     void *puc)
1003 {
1004     TranslationBlock *tb;
1005     int ret;
1006
1007     if (cpu_single_env)
1008         env = cpu_single_env; /* XXX: find a correct solution for multithread */
1009 #if defined(DEBUG_SIGNAL)
1010     printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n", 
1011            pc, address, is_write, *(unsigned long *)old_set);
1012 #endif
1013     /* XXX: locking issue */
1014     if (is_write && page_unprotect(address, pc, puc)) {
1015         return 1;
1016     }
1017     /* see if it is an MMU fault */
1018     ret = cpu_m68k_handle_mmu_fault(env, address, is_write, 1, 0);
1019     if (ret < 0)
1020         return 0; /* not an MMU fault */
1021     if (ret == 0)
1022         return 1; /* the MMU fault was handled without causing real CPU fault */
1023     /* now we have a real cpu fault */
1024     tb = tb_find_pc(pc);
1025     if (tb) {
1026         /* the PC is inside the translated code. It means that we have
1027            a virtual CPU fault */
1028         cpu_restore_state(tb, env, pc, puc);
1029     }
1030     /* we restore the process signal mask as the sigreturn should
1031        do it (XXX: use sigsetjmp) */
1032     sigprocmask(SIG_SETMASK, old_set, NULL);
1033     cpu_loop_exit();
1034     /* never comes here */
1035     return 1;
1036 }
1037
1038 #elif defined (TARGET_MIPS)
1039 static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
1040                                     int is_write, sigset_t *old_set,
1041                                     void *puc)
1042 {
1043     TranslationBlock *tb;
1044     int ret;
1045     
1046     if (cpu_single_env)
1047         env = cpu_single_env; /* XXX: find a correct solution for multithread */
1048 #if defined(DEBUG_SIGNAL)
1049     printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n", 
1050            pc, address, is_write, *(unsigned long *)old_set);
1051 #endif
1052     /* XXX: locking issue */
1053     if (is_write && page_unprotect(h2g(address), pc, puc)) {
1054         return 1;
1055     }
1056
1057     /* see if it is an MMU fault */
1058     ret = cpu_mips_handle_mmu_fault(env, address, is_write, 1, 0);
1059     if (ret < 0)
1060         return 0; /* not an MMU fault */
1061     if (ret == 0)
1062         return 1; /* the MMU fault was handled without causing real CPU fault */
1063
1064     /* now we have a real cpu fault */
1065     tb = tb_find_pc(pc);
1066     if (tb) {
1067         /* the PC is inside the translated code. It means that we have
1068            a virtual CPU fault */
1069         cpu_restore_state(tb, env, pc, puc);
1070     }
1071     if (ret == 1) {
1072 #if 0
1073         printf("PF exception: PC=0x" TARGET_FMT_lx " error=0x%x %p\n", 
1074                env->PC, env->error_code, tb);
1075 #endif
1076     /* we restore the process signal mask as the sigreturn should
1077        do it (XXX: use sigsetjmp) */
1078         sigprocmask(SIG_SETMASK, old_set, NULL);
1079         do_raise_exception_err(env->exception_index, env->error_code);
1080     } else {
1081         /* activate soft MMU for this block */
1082         cpu_resume_from_signal(env, puc);
1083     }
1084     /* never comes here */
1085     return 1;
1086 }
1087
1088 #elif defined (TARGET_SH4)
1089 static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
1090                                     int is_write, sigset_t *old_set,
1091                                     void *puc)
1092 {
1093     TranslationBlock *tb;
1094     int ret;
1095     
1096     if (cpu_single_env)
1097         env = cpu_single_env; /* XXX: find a correct solution for multithread */
1098 #if defined(DEBUG_SIGNAL)
1099     printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n", 
1100            pc, address, is_write, *(unsigned long *)old_set);
1101 #endif
1102     /* XXX: locking issue */
1103     if (is_write && page_unprotect(h2g(address), pc, puc)) {
1104         return 1;
1105     }
1106
1107     /* see if it is an MMU fault */
1108     ret = cpu_sh4_handle_mmu_fault(env, address, is_write, 1, 0);
1109     if (ret < 0)
1110         return 0; /* not an MMU fault */
1111     if (ret == 0)
1112         return 1; /* the MMU fault was handled without causing real CPU fault */
1113
1114     /* now we have a real cpu fault */
1115     tb = tb_find_pc(pc);
1116     if (tb) {
1117         /* the PC is inside the translated code. It means that we have
1118            a virtual CPU fault */
1119         cpu_restore_state(tb, env, pc, puc);
1120     }
1121 #if 0
1122         printf("PF exception: NIP=0x%08x error=0x%x %p\n", 
1123                env->nip, env->error_code, tb);
1124 #endif
1125     /* we restore the process signal mask as the sigreturn should
1126        do it (XXX: use sigsetjmp) */
1127     sigprocmask(SIG_SETMASK, old_set, NULL);
1128     cpu_loop_exit();
1129     /* never comes here */
1130     return 1;
1131 }
1132
1133 #elif defined (TARGET_ALPHA)
1134 static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
1135                                     int is_write, sigset_t *old_set,
1136                                     void *puc)
1137 {
1138     TranslationBlock *tb;
1139     int ret;
1140     
1141     if (cpu_single_env)
1142         env = cpu_single_env; /* XXX: find a correct solution for multithread */
1143 #if defined(DEBUG_SIGNAL)
1144     printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n", 
1145            pc, address, is_write, *(unsigned long *)old_set);
1146 #endif
1147     /* XXX: locking issue */
1148     if (is_write && page_unprotect(h2g(address), pc, puc)) {
1149         return 1;
1150     }
1151
1152     /* see if it is an MMU fault */
1153     ret = cpu_alpha_handle_mmu_fault(env, address, is_write, 1, 0);
1154     if (ret < 0)
1155         return 0; /* not an MMU fault */
1156     if (ret == 0)
1157         return 1; /* the MMU fault was handled without causing real CPU fault */
1158
1159     /* now we have a real cpu fault */
1160     tb = tb_find_pc(pc);
1161     if (tb) {
1162         /* the PC is inside the translated code. It means that we have
1163            a virtual CPU fault */
1164         cpu_restore_state(tb, env, pc, puc);
1165     }
1166 #if 0
1167         printf("PF exception: NIP=0x%08x error=0x%x %p\n", 
1168                env->nip, env->error_code, tb);
1169 #endif
1170     /* we restore the process signal mask as the sigreturn should
1171        do it (XXX: use sigsetjmp) */
1172     sigprocmask(SIG_SETMASK, old_set, NULL);
1173     cpu_loop_exit();
1174     /* never comes here */
1175     return 1;
1176 }
1177 #else
1178 #error unsupported target CPU
1179 #endif
1180
1181 #if defined(__i386__)
1182
1183 #if defined(__APPLE__)
1184 # include <sys/ucontext.h>
1185
1186 # define EIP_sig(context)  (*((unsigned long*)&(context)->uc_mcontext->ss.eip))
1187 # define TRAP_sig(context)    ((context)->uc_mcontext->es.trapno)
1188 # define ERROR_sig(context)   ((context)->uc_mcontext->es.err)
1189 #else
1190 # define EIP_sig(context)     ((context)->uc_mcontext.gregs[REG_EIP])
1191 # define TRAP_sig(context)    ((context)->uc_mcontext.gregs[REG_TRAPNO])
1192 # define ERROR_sig(context)   ((context)->uc_mcontext.gregs[REG_ERR])
1193 #endif
1194
1195 #if defined(USE_CODE_COPY)
1196 static void cpu_send_trap(unsigned long pc, int trap, 
1197                           struct ucontext *uc)
1198 {
1199     TranslationBlock *tb;
1200
1201     if (cpu_single_env)
1202         env = cpu_single_env; /* XXX: find a correct solution for multithread */
1203     /* now we have a real cpu fault */
1204     tb = tb_find_pc(pc);
1205     if (tb) {
1206         /* the PC is inside the translated code. It means that we have
1207            a virtual CPU fault */
1208         cpu_restore_state(tb, env, pc, uc);
1209     }
1210     sigprocmask(SIG_SETMASK, &uc->uc_sigmask, NULL);
1211     raise_exception_err(trap, env->error_code);
1212 }
1213 #endif
1214
1215 int cpu_signal_handler(int host_signum, void *pinfo, 
1216                        void *puc)
1217 {
1218     siginfo_t *info = pinfo;
1219     struct ucontext *uc = puc;
1220     unsigned long pc;
1221     int trapno;
1222
1223 #ifndef REG_EIP
1224 /* for glibc 2.1 */
1225 #define REG_EIP    EIP
1226 #define REG_ERR    ERR
1227 #define REG_TRAPNO TRAPNO
1228 #endif
1229     pc = EIP_sig(uc);
1230     trapno = TRAP_sig(uc);
1231 #if defined(TARGET_I386) && defined(USE_CODE_COPY)
1232     if (trapno == 0x00 || trapno == 0x05) {
1233         /* send division by zero or bound exception */
1234         cpu_send_trap(pc, trapno, uc);
1235         return 1;
1236     } else
1237 #endif
1238         return handle_cpu_signal(pc, (unsigned long)info->si_addr, 
1239                                  trapno == 0xe ? 
1240                                  (ERROR_sig(uc) >> 1) & 1 : 0,
1241                                  &uc->uc_sigmask, puc);
1242 }
1243
1244 #elif defined(__x86_64__)
1245
1246 int cpu_signal_handler(int host_signum, void *pinfo,
1247                        void *puc)
1248 {
1249     siginfo_t *info = pinfo;
1250     struct ucontext *uc = puc;
1251     unsigned long pc;
1252
1253     pc = uc->uc_mcontext.gregs[REG_RIP];
1254     return handle_cpu_signal(pc, (unsigned long)info->si_addr, 
1255                              uc->uc_mcontext.gregs[REG_TRAPNO] == 0xe ? 
1256                              (uc->uc_mcontext.gregs[REG_ERR] >> 1) & 1 : 0,
1257                              &uc->uc_sigmask, puc);
1258 }
1259
1260 #elif defined(__powerpc__)
1261
1262 /***********************************************************************
1263  * signal context platform-specific definitions
1264  * From Wine
1265  */
1266 #ifdef linux
1267 /* All Registers access - only for local access */
1268 # define REG_sig(reg_name, context)             ((context)->uc_mcontext.regs->reg_name)
1269 /* Gpr Registers access  */
1270 # define GPR_sig(reg_num, context)              REG_sig(gpr[reg_num], context)
1271 # define IAR_sig(context)                       REG_sig(nip, context)   /* Program counter */
1272 # define MSR_sig(context)                       REG_sig(msr, context)   /* Machine State Register (Supervisor) */
1273 # define CTR_sig(context)                       REG_sig(ctr, context)   /* Count register */
1274 # define XER_sig(context)                       REG_sig(xer, context) /* User's integer exception register */
1275 # define LR_sig(context)                        REG_sig(link, context) /* Link register */
1276 # define CR_sig(context)                        REG_sig(ccr, context) /* Condition register */
1277 /* Float Registers access  */
1278 # define FLOAT_sig(reg_num, context)            (((double*)((char*)((context)->uc_mcontext.regs+48*4)))[reg_num])
1279 # define FPSCR_sig(context)                     (*(int*)((char*)((context)->uc_mcontext.regs+(48+32*2)*4)))
1280 /* Exception Registers access */
1281 # define DAR_sig(context)                       REG_sig(dar, context)
1282 # define DSISR_sig(context)                     REG_sig(dsisr, context)
1283 # define TRAP_sig(context)                      REG_sig(trap, context)
1284 #endif /* linux */
1285
1286 #ifdef __APPLE__
1287 # include <sys/ucontext.h>
1288 typedef struct ucontext SIGCONTEXT;
1289 /* All Registers access - only for local access */
1290 # define REG_sig(reg_name, context)             ((context)->uc_mcontext->ss.reg_name)
1291 # define FLOATREG_sig(reg_name, context)        ((context)->uc_mcontext->fs.reg_name)
1292 # define EXCEPREG_sig(reg_name, context)        ((context)->uc_mcontext->es.reg_name)
1293 # define VECREG_sig(reg_name, context)          ((context)->uc_mcontext->vs.reg_name)
1294 /* Gpr Registers access */
1295 # define GPR_sig(reg_num, context)              REG_sig(r##reg_num, context)
1296 # define IAR_sig(context)                       REG_sig(srr0, context)  /* Program counter */
1297 # define MSR_sig(context)                       REG_sig(srr1, context)  /* Machine State Register (Supervisor) */
1298 # define CTR_sig(context)                       REG_sig(ctr, context)
1299 # define XER_sig(context)                       REG_sig(xer, context) /* Link register */
1300 # define LR_sig(context)                        REG_sig(lr, context)  /* User's integer exception register */
1301 # define CR_sig(context)                        REG_sig(cr, context)  /* Condition register */
1302 /* Float Registers access */
1303 # define FLOAT_sig(reg_num, context)            FLOATREG_sig(fpregs[reg_num], context)
1304 # define FPSCR_sig(context)                     ((double)FLOATREG_sig(fpscr, context))
1305 /* Exception Registers access */
1306 # define DAR_sig(context)                       EXCEPREG_sig(dar, context)     /* Fault registers for coredump */
1307 # define DSISR_sig(context)                     EXCEPREG_sig(dsisr, context)
1308 # define TRAP_sig(context)                      EXCEPREG_sig(exception, context) /* number of powerpc exception taken */
1309 #endif /* __APPLE__ */
1310
1311 int cpu_signal_handler(int host_signum, void *pinfo, 
1312                        void *puc)
1313 {
1314     siginfo_t *info = pinfo;
1315     struct ucontext *uc = puc;
1316     unsigned long pc;
1317     int is_write;
1318
1319     pc = IAR_sig(uc);
1320     is_write = 0;
1321 #if 0
1322     /* ppc 4xx case */
1323     if (DSISR_sig(uc) & 0x00800000)
1324         is_write = 1;
1325 #else
1326     if (TRAP_sig(uc) != 0x400 && (DSISR_sig(uc) & 0x02000000))
1327         is_write = 1;
1328 #endif
1329     return handle_cpu_signal(pc, (unsigned long)info->si_addr, 
1330                              is_write, &uc->uc_sigmask, puc);
1331 }
1332
1333 #elif defined(__alpha__)
1334
1335 int cpu_signal_handler(int host_signum, void *pinfo, 
1336                            void *puc)
1337 {
1338     siginfo_t *info = pinfo;
1339     struct ucontext *uc = puc;
1340     uint32_t *pc = uc->uc_mcontext.sc_pc;
1341     uint32_t insn = *pc;
1342     int is_write = 0;
1343
1344     /* XXX: need kernel patch to get write flag faster */
1345     switch (insn >> 26) {
1346     case 0x0d: // stw
1347     case 0x0e: // stb
1348     case 0x0f: // stq_u
1349     case 0x24: // stf
1350     case 0x25: // stg
1351     case 0x26: // sts
1352     case 0x27: // stt
1353     case 0x2c: // stl
1354     case 0x2d: // stq
1355     case 0x2e: // stl_c
1356     case 0x2f: // stq_c
1357         is_write = 1;
1358     }
1359
1360     return handle_cpu_signal(pc, (unsigned long)info->si_addr, 
1361                              is_write, &uc->uc_sigmask, puc);
1362 }
1363 #elif defined(__sparc__)
1364
1365 int cpu_signal_handler(int host_signum, void *pinfo, 
1366                        void *puc)
1367 {
1368     siginfo_t *info = pinfo;
1369     uint32_t *regs = (uint32_t *)(info + 1);
1370     void *sigmask = (regs + 20);
1371     unsigned long pc;
1372     int is_write;
1373     uint32_t insn;
1374     
1375     /* XXX: is there a standard glibc define ? */
1376     pc = regs[1];
1377     /* XXX: need kernel patch to get write flag faster */
1378     is_write = 0;
1379     insn = *(uint32_t *)pc;
1380     if ((insn >> 30) == 3) {
1381       switch((insn >> 19) & 0x3f) {
1382       case 0x05: // stb
1383       case 0x06: // sth
1384       case 0x04: // st
1385       case 0x07: // std
1386       case 0x24: // stf
1387       case 0x27: // stdf
1388       case 0x25: // stfsr
1389         is_write = 1;
1390         break;
1391       }
1392     }
1393     return handle_cpu_signal(pc, (unsigned long)info->si_addr, 
1394                              is_write, sigmask, NULL);
1395 }
1396
1397 #elif defined(__arm__)
1398
1399 int cpu_signal_handler(int host_signum, void *pinfo, 
1400                        void *puc)
1401 {
1402     siginfo_t *info = pinfo;
1403     struct ucontext *uc = puc;
1404     unsigned long pc;
1405     int is_write;
1406     
1407     pc = uc->uc_mcontext.gregs[R15];
1408     /* XXX: compute is_write */
1409     is_write = 0;
1410     return handle_cpu_signal(pc, (unsigned long)info->si_addr, 
1411                              is_write,
1412                              &uc->uc_sigmask, puc);
1413 }
1414
1415 #elif defined(__mc68000)
1416
1417 int cpu_signal_handler(int host_signum, void *pinfo, 
1418                        void *puc)
1419 {
1420     siginfo_t *info = pinfo;
1421     struct ucontext *uc = puc;
1422     unsigned long pc;
1423     int is_write;
1424     
1425     pc = uc->uc_mcontext.gregs[16];
1426     /* XXX: compute is_write */
1427     is_write = 0;
1428     return handle_cpu_signal(pc, (unsigned long)info->si_addr, 
1429                              is_write,
1430                              &uc->uc_sigmask, puc);
1431 }
1432
1433 #elif defined(__ia64)
1434
1435 #ifndef __ISR_VALID
1436   /* This ought to be in <bits/siginfo.h>... */
1437 # define __ISR_VALID    1
1438 #endif
1439
1440 int cpu_signal_handler(int host_signum, void *pinfo, void *puc)
1441 {
1442     siginfo_t *info = pinfo;
1443     struct ucontext *uc = puc;
1444     unsigned long ip;
1445     int is_write = 0;
1446
1447     ip = uc->uc_mcontext.sc_ip;
1448     switch (host_signum) {
1449       case SIGILL:
1450       case SIGFPE:
1451       case SIGSEGV:
1452       case SIGBUS:
1453       case SIGTRAP:
1454           if (info->si_code && (info->si_segvflags & __ISR_VALID))
1455               /* ISR.W (write-access) is bit 33:  */
1456               is_write = (info->si_isr >> 33) & 1;
1457           break;
1458
1459       default:
1460           break;
1461     }
1462     return handle_cpu_signal(ip, (unsigned long)info->si_addr,
1463                              is_write,
1464                              &uc->uc_sigmask, puc);
1465 }
1466
1467 #elif defined(__s390__)
1468
1469 int cpu_signal_handler(int host_signum, void *pinfo, 
1470                        void *puc)
1471 {
1472     siginfo_t *info = pinfo;
1473     struct ucontext *uc = puc;
1474     unsigned long pc;
1475     int is_write;
1476     
1477     pc = uc->uc_mcontext.psw.addr;
1478     /* XXX: compute is_write */
1479     is_write = 0;
1480     return handle_cpu_signal(pc, (unsigned long)info->si_addr, 
1481                              is_write, &uc->uc_sigmask, puc);
1482 }
1483
1484 #elif defined(__mips__)
1485
1486 int cpu_signal_handler(int host_signum, void *pinfo, 
1487                        void *puc)
1488 {
1489     siginfo_t *info = pinfo;
1490     struct ucontext *uc = puc;
1491     greg_t pc = uc->uc_mcontext.pc;
1492     int is_write;
1493     
1494     /* XXX: compute is_write */
1495     is_write = 0;
1496     return handle_cpu_signal(pc, (unsigned long)info->si_addr, 
1497                              is_write, &uc->uc_sigmask, puc);
1498 }
1499
1500 #else
1501
1502 #error host CPU specific signal handler needed
1503
1504 #endif
1505
1506 #endif /* !defined(CONFIG_SOFTMMU) */