avoid generating useless exceptions (Jocelyn Mayer)
[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 #if defined(TARGET_ARM) || defined(TARGET_SPARC)
44 /* XXX: unify with i386 target */
45 void cpu_loop_exit(void)
46 {
47     longjmp(env->jmp_env, 1);
48 }
49 #endif
50 #ifndef TARGET_SPARC
51 #define reg_T2
52 #endif
53
54 /* exit the current TB from a signal handler. The host registers are
55    restored in a state compatible with the CPU emulator
56  */
57 void cpu_resume_from_signal(CPUState *env1, void *puc) 
58 {
59 #if !defined(CONFIG_SOFTMMU)
60     struct ucontext *uc = puc;
61 #endif
62
63     env = env1;
64
65     /* XXX: restore cpu registers saved in host registers */
66
67 #if !defined(CONFIG_SOFTMMU)
68     if (puc) {
69         /* XXX: use siglongjmp ? */
70         sigprocmask(SIG_SETMASK, &uc->uc_sigmask, NULL);
71     }
72 #endif
73     longjmp(env->jmp_env, 1);
74 }
75
76
77 static TranslationBlock *tb_find_slow(target_ulong pc,
78                                       target_ulong cs_base,
79                                       unsigned int flags)
80 {
81     TranslationBlock *tb, **ptb1;
82     int code_gen_size;
83     unsigned int h;
84     target_ulong phys_pc, phys_page1, phys_page2, virt_page2;
85     uint8_t *tc_ptr;
86     
87     spin_lock(&tb_lock);
88
89     tb_invalidated_flag = 0;
90     
91     regs_to_env(); /* XXX: do it just before cpu_gen_code() */
92     
93     /* find translated block using physical mappings */
94     phys_pc = get_phys_addr_code(env, pc);
95     phys_page1 = phys_pc & TARGET_PAGE_MASK;
96     phys_page2 = -1;
97     h = tb_phys_hash_func(phys_pc);
98     ptb1 = &tb_phys_hash[h];
99     for(;;) {
100         tb = *ptb1;
101         if (!tb)
102             goto not_found;
103         if (tb->pc == pc && 
104             tb->page_addr[0] == phys_page1 &&
105             tb->cs_base == cs_base && 
106             tb->flags == flags) {
107             /* check next page if needed */
108             if (tb->page_addr[1] != -1) {
109                 virt_page2 = (pc & TARGET_PAGE_MASK) + 
110                     TARGET_PAGE_SIZE;
111                 phys_page2 = get_phys_addr_code(env, virt_page2);
112                 if (tb->page_addr[1] == phys_page2)
113                     goto found;
114             } else {
115                 goto found;
116             }
117         }
118         ptb1 = &tb->phys_hash_next;
119     }
120  not_found:
121     /* if no translated code available, then translate it now */
122     tb = tb_alloc(pc);
123     if (!tb) {
124         /* flush must be done */
125         tb_flush(env);
126         /* cannot fail at this point */
127         tb = tb_alloc(pc);
128         /* don't forget to invalidate previous TB info */
129         T0 = 0;
130     }
131     tc_ptr = code_gen_ptr;
132     tb->tc_ptr = tc_ptr;
133     tb->cs_base = cs_base;
134     tb->flags = flags;
135     cpu_gen_code(env, tb, CODE_GEN_MAX_SIZE, &code_gen_size);
136     code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1));
137     
138     /* check next page if needed */
139     virt_page2 = (pc + tb->size - 1) & TARGET_PAGE_MASK;
140     phys_page2 = -1;
141     if ((pc & TARGET_PAGE_MASK) != virt_page2) {
142         phys_page2 = get_phys_addr_code(env, virt_page2);
143     }
144     tb_link_phys(tb, phys_pc, phys_page2);
145     
146  found:
147     if (tb_invalidated_flag) {
148         /* as some TB could have been invalidated because
149            of memory exceptions while generating the code, we
150            must recompute the hash index here */
151         T0 = 0;
152     }
153     /* we add the TB in the virtual pc hash table */
154     env->tb_jmp_cache[tb_jmp_cache_hash_func(pc)] = tb;
155     spin_unlock(&tb_lock);
156     return tb;
157 }
158
159 static inline TranslationBlock *tb_find_fast(void)
160 {
161     TranslationBlock *tb;
162     target_ulong cs_base, pc;
163     unsigned int flags;
164
165     /* we record a subset of the CPU state. It will
166        always be the same before a given translated block
167        is executed. */
168 #if defined(TARGET_I386)
169     flags = env->hflags;
170     flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK));
171     cs_base = env->segs[R_CS].base;
172     pc = cs_base + env->eip;
173 #elif defined(TARGET_ARM)
174     flags = env->thumb | (env->vfp.vec_len << 1)
175         | (env->vfp.vec_stride << 4);
176     cs_base = 0;
177     pc = env->regs[15];
178 #elif defined(TARGET_SPARC)
179 #ifdef TARGET_SPARC64
180     flags = (env->pstate << 2) | ((env->lsu & (DMMU_E | IMMU_E)) >> 2);
181 #else
182     flags = env->psrs | ((env->mmuregs[0] & (MMU_E | MMU_NF)) << 1);
183 #endif
184     cs_base = env->npc;
185     pc = env->pc;
186 #elif defined(TARGET_PPC)
187     flags = (msr_pr << MSR_PR) | (msr_fp << MSR_FP) |
188         (msr_se << MSR_SE) | (msr_le << MSR_LE);
189     cs_base = 0;
190     pc = env->nip;
191 #elif defined(TARGET_MIPS)
192     flags = env->hflags & MIPS_HFLAGS_TMASK;
193     cs_base = NULL;
194     pc = env->PC;
195 #else
196 #error unsupported CPU
197 #endif
198     tb = env->tb_jmp_cache[tb_jmp_cache_hash_func(pc)];
199     if (__builtin_expect(!tb || tb->pc != pc || tb->cs_base != cs_base ||
200                          tb->flags != flags, 0)) {
201         tb = tb_find_slow(pc, cs_base, flags);
202     }
203     return tb;
204 }
205
206
207 /* main execution loop */
208
209 int cpu_exec(CPUState *env1)
210 {
211     int saved_T0, saved_T1;
212 #if defined(reg_T2)
213     int saved_T2;
214 #endif
215     CPUState *saved_env;
216 #if defined(TARGET_I386)
217 #ifdef reg_EAX
218     int saved_EAX;
219 #endif
220 #ifdef reg_ECX
221     int saved_ECX;
222 #endif
223 #ifdef reg_EDX
224     int saved_EDX;
225 #endif
226 #ifdef reg_EBX
227     int saved_EBX;
228 #endif
229 #ifdef reg_ESP
230     int saved_ESP;
231 #endif
232 #ifdef reg_EBP
233     int saved_EBP;
234 #endif
235 #ifdef reg_ESI
236     int saved_ESI;
237 #endif
238 #ifdef reg_EDI
239     int saved_EDI;
240 #endif
241 #elif defined(TARGET_SPARC)
242 #if defined(reg_REGWPTR)
243     uint32_t *saved_regwptr;
244 #endif
245 #endif
246 #ifdef __sparc__
247     int saved_i7, tmp_T0;
248 #endif
249     int ret, interrupt_request;
250     void (*gen_func)(void);
251     TranslationBlock *tb;
252     uint8_t *tc_ptr;
253
254 #if defined(TARGET_I386)
255     /* handle exit of HALTED state */
256     if (env1->hflags & HF_HALTED_MASK) {
257         /* disable halt condition */
258         if ((env1->interrupt_request & CPU_INTERRUPT_HARD) &&
259             (env1->eflags & IF_MASK)) {
260             env1->hflags &= ~HF_HALTED_MASK;
261         } else {
262             return EXCP_HALTED;
263         }
264     }
265 #endif
266
267     cpu_single_env = env1; 
268
269     /* first we save global registers */
270     saved_env = env;
271     env = env1;
272     saved_T0 = T0;
273     saved_T1 = T1;
274 #if defined(reg_T2)
275     saved_T2 = T2;
276 #endif
277 #ifdef __sparc__
278     /* we also save i7 because longjmp may not restore it */
279     asm volatile ("mov %%i7, %0" : "=r" (saved_i7));
280 #endif
281
282 #if defined(TARGET_I386)
283 #ifdef reg_EAX
284     saved_EAX = EAX;
285 #endif
286 #ifdef reg_ECX
287     saved_ECX = ECX;
288 #endif
289 #ifdef reg_EDX
290     saved_EDX = EDX;
291 #endif
292 #ifdef reg_EBX
293     saved_EBX = EBX;
294 #endif
295 #ifdef reg_ESP
296     saved_ESP = ESP;
297 #endif
298 #ifdef reg_EBP
299     saved_EBP = EBP;
300 #endif
301 #ifdef reg_ESI
302     saved_ESI = ESI;
303 #endif
304 #ifdef reg_EDI
305     saved_EDI = EDI;
306 #endif
307
308     env_to_regs();
309     /* put eflags in CPU temporary format */
310     CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
311     DF = 1 - (2 * ((env->eflags >> 10) & 1));
312     CC_OP = CC_OP_EFLAGS;
313     env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
314 #elif defined(TARGET_ARM)
315     {
316         unsigned int psr;
317         psr = env->cpsr;
318         env->CF = (psr >> 29) & 1;
319         env->NZF = (psr & 0xc0000000) ^ 0x40000000;
320         env->VF = (psr << 3) & 0x80000000;
321         env->QF = (psr >> 27) & 1;
322         env->cpsr = psr & ~CACHED_CPSR_BITS;
323     }
324 #elif defined(TARGET_SPARC)
325 #if defined(reg_REGWPTR)
326     saved_regwptr = REGWPTR;
327 #endif
328 #elif defined(TARGET_PPC)
329 #elif defined(TARGET_MIPS)
330 #else
331 #error unsupported target CPU
332 #endif
333     env->exception_index = -1;
334
335     /* prepare setjmp context for exception handling */
336     for(;;) {
337         if (setjmp(env->jmp_env) == 0) {
338             env->current_tb = NULL;
339             /* if an exception is pending, we execute it here */
340             if (env->exception_index >= 0) {
341                 if (env->exception_index >= EXCP_INTERRUPT) {
342                     /* exit request from the cpu execution loop */
343                     ret = env->exception_index;
344                     break;
345                 } else if (env->user_mode_only) {
346                     /* if user mode only, we simulate a fake exception
347                        which will be hanlded outside the cpu execution
348                        loop */
349 #if defined(TARGET_I386)
350                     do_interrupt_user(env->exception_index, 
351                                       env->exception_is_int, 
352                                       env->error_code, 
353                                       env->exception_next_eip);
354 #endif
355                     ret = env->exception_index;
356                     break;
357                 } else {
358 #if defined(TARGET_I386)
359                     /* simulate a real cpu exception. On i386, it can
360                        trigger new exceptions, but we do not handle
361                        double or triple faults yet. */
362                     do_interrupt(env->exception_index, 
363                                  env->exception_is_int, 
364                                  env->error_code, 
365                                  env->exception_next_eip, 0);
366 #elif defined(TARGET_PPC)
367                     do_interrupt(env);
368 #elif defined(TARGET_MIPS)
369                     do_interrupt(env);
370 #elif defined(TARGET_SPARC)
371                     do_interrupt(env->exception_index);
372 #endif
373                 }
374                 env->exception_index = -1;
375             } 
376 #ifdef USE_KQEMU
377             if (kqemu_is_ok(env) && env->interrupt_request == 0) {
378                 int ret;
379                 env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
380                 ret = kqemu_cpu_exec(env);
381                 /* put eflags in CPU temporary format */
382                 CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
383                 DF = 1 - (2 * ((env->eflags >> 10) & 1));
384                 CC_OP = CC_OP_EFLAGS;
385                 env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
386                 if (ret == 1) {
387                     /* exception */
388                     longjmp(env->jmp_env, 1);
389                 } else if (ret == 2) {
390                     /* softmmu execution needed */
391                 } else {
392                     if (env->interrupt_request != 0) {
393                         /* hardware interrupt will be executed just after */
394                     } else {
395                         /* otherwise, we restart */
396                         longjmp(env->jmp_env, 1);
397                     }
398                 }
399             }
400 #endif
401
402             T0 = 0; /* force lookup of first TB */
403             for(;;) {
404 #ifdef __sparc__
405                 /* g1 can be modified by some libc? functions */ 
406                 tmp_T0 = T0;
407 #endif      
408                 interrupt_request = env->interrupt_request;
409                 if (__builtin_expect(interrupt_request, 0)) {
410 #if defined(TARGET_I386)
411                     /* if hardware interrupt pending, we execute it */
412                     if ((interrupt_request & CPU_INTERRUPT_HARD) &&
413                         (env->eflags & IF_MASK) && 
414                         !(env->hflags & HF_INHIBIT_IRQ_MASK)) {
415                         int intno;
416                         env->interrupt_request &= ~CPU_INTERRUPT_HARD;
417                         intno = cpu_get_pic_interrupt(env);
418                         if (loglevel & CPU_LOG_TB_IN_ASM) {
419                             fprintf(logfile, "Servicing hardware INT=0x%02x\n", intno);
420                         }
421                         do_interrupt(intno, 0, 0, 0, 1);
422                         /* ensure that no TB jump will be modified as
423                            the program flow was changed */
424 #ifdef __sparc__
425                         tmp_T0 = 0;
426 #else
427                         T0 = 0;
428 #endif
429                     }
430 #elif defined(TARGET_PPC)
431 #if 0
432                     if ((interrupt_request & CPU_INTERRUPT_RESET)) {
433                         cpu_ppc_reset(env);
434                     }
435 #endif
436                     if (msr_ee != 0) {
437                         if ((interrupt_request & CPU_INTERRUPT_HARD)) {
438                             /* Raise it */
439                             env->exception_index = EXCP_EXTERNAL;
440                             env->error_code = 0;
441                             do_interrupt(env);
442                             env->interrupt_request &= ~CPU_INTERRUPT_HARD;
443 #ifdef __sparc__
444                             tmp_T0 = 0;
445 #else
446                             T0 = 0;
447 #endif
448                         } else if ((interrupt_request & CPU_INTERRUPT_TIMER)) {
449                             /* Raise it */
450                             env->exception_index = EXCP_DECR;
451                             env->error_code = 0;
452                             do_interrupt(env);
453                             env->interrupt_request &= ~CPU_INTERRUPT_TIMER;
454 #ifdef __sparc__
455                             tmp_T0 = 0;
456 #else
457                             T0 = 0;
458 #endif
459                         }
460                     }
461 #elif defined(TARGET_MIPS)
462                     if ((interrupt_request & CPU_INTERRUPT_HARD) &&
463                         (env->CP0_Status & (1 << CP0St_IE)) &&
464                         (env->CP0_Status & env->CP0_Cause & 0x0000FF00) &&
465                         !(env->hflags & MIPS_HFLAG_EXL) &&
466                         !(env->hflags & MIPS_HFLAG_ERL) &&
467                         !(env->hflags & MIPS_HFLAG_DM)) {
468                         /* Raise it */
469                         env->exception_index = EXCP_EXT_INTERRUPT;
470                         env->error_code = 0;
471                         do_interrupt(env);
472                         env->interrupt_request &= ~CPU_INTERRUPT_HARD;
473 #ifdef __sparc__
474                         tmp_T0 = 0;
475 #else
476                         T0 = 0;
477 #endif
478                     }
479 #elif defined(TARGET_SPARC)
480                     if ((interrupt_request & CPU_INTERRUPT_HARD) &&
481                         (env->psret != 0)) {
482                         int pil = env->interrupt_index & 15;
483                         int type = env->interrupt_index & 0xf0;
484
485                         if (((type == TT_EXTINT) &&
486                              (pil == 15 || pil > env->psrpil)) ||
487                             type != TT_EXTINT) {
488                             env->interrupt_request &= ~CPU_INTERRUPT_HARD;
489                             do_interrupt(env->interrupt_index);
490                             env->interrupt_index = 0;
491 #ifdef __sparc__
492                             tmp_T0 = 0;
493 #else
494                             T0 = 0;
495 #endif
496                         }
497                     } else if (interrupt_request & CPU_INTERRUPT_TIMER) {
498                         //do_interrupt(0, 0, 0, 0, 0);
499                         env->interrupt_request &= ~CPU_INTERRUPT_TIMER;
500                     }
501 #endif
502                     if (interrupt_request & CPU_INTERRUPT_EXITTB) {
503                         env->interrupt_request &= ~CPU_INTERRUPT_EXITTB;
504                         /* ensure that no TB jump will be modified as
505                            the program flow was changed */
506 #ifdef __sparc__
507                         tmp_T0 = 0;
508 #else
509                         T0 = 0;
510 #endif
511                     }
512                     if (interrupt_request & CPU_INTERRUPT_EXIT) {
513                         env->interrupt_request &= ~CPU_INTERRUPT_EXIT;
514                         env->exception_index = EXCP_INTERRUPT;
515                         cpu_loop_exit();
516                     }
517                 }
518 #ifdef DEBUG_EXEC
519                 if ((loglevel & CPU_LOG_EXEC)) {
520 #if defined(TARGET_I386)
521                     /* restore flags in standard format */
522 #ifdef reg_EAX
523                     env->regs[R_EAX] = EAX;
524 #endif
525 #ifdef reg_EBX
526                     env->regs[R_EBX] = EBX;
527 #endif
528 #ifdef reg_ECX
529                     env->regs[R_ECX] = ECX;
530 #endif
531 #ifdef reg_EDX
532                     env->regs[R_EDX] = EDX;
533 #endif
534 #ifdef reg_ESI
535                     env->regs[R_ESI] = ESI;
536 #endif
537 #ifdef reg_EDI
538                     env->regs[R_EDI] = EDI;
539 #endif
540 #ifdef reg_EBP
541                     env->regs[R_EBP] = EBP;
542 #endif
543 #ifdef reg_ESP
544                     env->regs[R_ESP] = ESP;
545 #endif
546                     env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
547                     cpu_dump_state(env, logfile, fprintf, X86_DUMP_CCOP);
548                     env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
549 #elif defined(TARGET_ARM)
550                     env->cpsr = compute_cpsr();
551                     cpu_dump_state(env, logfile, fprintf, 0);
552                     env->cpsr &= ~CACHED_CPSR_BITS;
553 #elif defined(TARGET_SPARC)
554                     REGWPTR = env->regbase + (env->cwp * 16);
555                     env->regwptr = REGWPTR;
556                     cpu_dump_state(env, logfile, fprintf, 0);
557 #elif defined(TARGET_PPC)
558                     cpu_dump_state(env, logfile, fprintf, 0);
559 #elif defined(TARGET_MIPS)
560                     cpu_dump_state(env, logfile, fprintf, 0);
561 #else
562 #error unsupported target CPU 
563 #endif
564                 }
565 #endif
566                 tb = tb_find_fast();
567 #ifdef DEBUG_EXEC
568                 if ((loglevel & CPU_LOG_EXEC)) {
569                     fprintf(logfile, "Trace 0x%08lx [" TARGET_FMT_lx "] %s\n",
570                             (long)tb->tc_ptr, tb->pc,
571                             lookup_symbol(tb->pc));
572                 }
573 #endif
574 #ifdef __sparc__
575                 T0 = tmp_T0;
576 #endif      
577                 /* see if we can patch the calling TB. When the TB
578                    spans two pages, we cannot safely do a direct
579                    jump. */
580                 {
581                     if (T0 != 0 &&
582                         tb->page_addr[1] == -1
583 #if defined(TARGET_I386) && defined(USE_CODE_COPY)
584                     && (tb->cflags & CF_CODE_COPY) == 
585                     (((TranslationBlock *)(T0 & ~3))->cflags & CF_CODE_COPY)
586 #endif
587                     ) {
588                     spin_lock(&tb_lock);
589                     tb_add_jump((TranslationBlock *)(long)(T0 & ~3), T0 & 3, tb);
590 #if defined(USE_CODE_COPY)
591                     /* propagates the FP use info */
592                     ((TranslationBlock *)(T0 & ~3))->cflags |= 
593                         (tb->cflags & CF_FP_USED);
594 #endif
595                     spin_unlock(&tb_lock);
596                 }
597                 }
598                 tc_ptr = tb->tc_ptr;
599                 env->current_tb = tb;
600                 /* execute the generated code */
601                 gen_func = (void *)tc_ptr;
602 #if defined(__sparc__)
603                 __asm__ __volatile__("call      %0\n\t"
604                                      "mov       %%o7,%%i0"
605                                      : /* no outputs */
606                                      : "r" (gen_func) 
607                                      : "i0", "i1", "i2", "i3", "i4", "i5");
608 #elif defined(__arm__)
609                 asm volatile ("mov pc, %0\n\t"
610                               ".global exec_loop\n\t"
611                               "exec_loop:\n\t"
612                               : /* no outputs */
613                               : "r" (gen_func)
614                               : "r1", "r2", "r3", "r8", "r9", "r10", "r12", "r14");
615 #elif defined(TARGET_I386) && defined(USE_CODE_COPY)
616 {
617     if (!(tb->cflags & CF_CODE_COPY)) {
618         if ((tb->cflags & CF_FP_USED) && env->native_fp_regs) {
619             save_native_fp_state(env);
620         }
621         gen_func();
622     } else {
623         if ((tb->cflags & CF_FP_USED) && !env->native_fp_regs) {
624             restore_native_fp_state(env);
625         }
626         /* we work with native eflags */
627         CC_SRC = cc_table[CC_OP].compute_all();
628         CC_OP = CC_OP_EFLAGS;
629         asm(".globl exec_loop\n"
630             "\n"
631             "debug1:\n"
632             "    pushl %%ebp\n"
633             "    fs movl %10, %9\n"
634             "    fs movl %11, %%eax\n"
635             "    andl $0x400, %%eax\n"
636             "    fs orl %8, %%eax\n"
637             "    pushl %%eax\n"
638             "    popf\n"
639             "    fs movl %%esp, %12\n"
640             "    fs movl %0, %%eax\n"
641             "    fs movl %1, %%ecx\n"
642             "    fs movl %2, %%edx\n"
643             "    fs movl %3, %%ebx\n"
644             "    fs movl %4, %%esp\n"
645             "    fs movl %5, %%ebp\n"
646             "    fs movl %6, %%esi\n"
647             "    fs movl %7, %%edi\n"
648             "    fs jmp *%9\n"
649             "exec_loop:\n"
650             "    fs movl %%esp, %4\n"
651             "    fs movl %12, %%esp\n"
652             "    fs movl %%eax, %0\n"
653             "    fs movl %%ecx, %1\n"
654             "    fs movl %%edx, %2\n"
655             "    fs movl %%ebx, %3\n"
656             "    fs movl %%ebp, %5\n"
657             "    fs movl %%esi, %6\n"
658             "    fs movl %%edi, %7\n"
659             "    pushf\n"
660             "    popl %%eax\n"
661             "    movl %%eax, %%ecx\n"
662             "    andl $0x400, %%ecx\n"
663             "    shrl $9, %%ecx\n"
664             "    andl $0x8d5, %%eax\n"
665             "    fs movl %%eax, %8\n"
666             "    movl $1, %%eax\n"
667             "    subl %%ecx, %%eax\n"
668             "    fs movl %%eax, %11\n"
669             "    fs movl %9, %%ebx\n" /* get T0 value */
670             "    popl %%ebp\n"
671             :
672             : "m" (*(uint8_t *)offsetof(CPUState, regs[0])),
673             "m" (*(uint8_t *)offsetof(CPUState, regs[1])),
674             "m" (*(uint8_t *)offsetof(CPUState, regs[2])),
675             "m" (*(uint8_t *)offsetof(CPUState, regs[3])),
676             "m" (*(uint8_t *)offsetof(CPUState, regs[4])),
677             "m" (*(uint8_t *)offsetof(CPUState, regs[5])),
678             "m" (*(uint8_t *)offsetof(CPUState, regs[6])),
679             "m" (*(uint8_t *)offsetof(CPUState, regs[7])),
680             "m" (*(uint8_t *)offsetof(CPUState, cc_src)),
681             "m" (*(uint8_t *)offsetof(CPUState, tmp0)),
682             "a" (gen_func),
683             "m" (*(uint8_t *)offsetof(CPUState, df)),
684             "m" (*(uint8_t *)offsetof(CPUState, saved_esp))
685             : "%ecx", "%edx"
686             );
687     }
688 }
689 #elif defined(__ia64)
690                 struct fptr {
691                         void *ip;
692                         void *gp;
693                 } fp;
694
695                 fp.ip = tc_ptr;
696                 fp.gp = code_gen_buffer + 2 * (1 << 20);
697                 (*(void (*)(void)) &fp)();
698 #else
699                 gen_func();
700 #endif
701                 env->current_tb = NULL;
702                 /* reset soft MMU for next block (it can currently
703                    only be set by a memory fault) */
704 #if defined(TARGET_I386) && !defined(CONFIG_SOFTMMU)
705                 if (env->hflags & HF_SOFTMMU_MASK) {
706                     env->hflags &= ~HF_SOFTMMU_MASK;
707                     /* do not allow linking to another block */
708                     T0 = 0;
709                 }
710 #endif
711             }
712         } else {
713             env_to_regs();
714         }
715     } /* for(;;) */
716
717
718 #if defined(TARGET_I386)
719 #if defined(USE_CODE_COPY)
720     if (env->native_fp_regs) {
721         save_native_fp_state(env);
722     }
723 #endif
724     /* restore flags in standard format */
725     env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
726
727     /* restore global registers */
728 #ifdef reg_EAX
729     EAX = saved_EAX;
730 #endif
731 #ifdef reg_ECX
732     ECX = saved_ECX;
733 #endif
734 #ifdef reg_EDX
735     EDX = saved_EDX;
736 #endif
737 #ifdef reg_EBX
738     EBX = saved_EBX;
739 #endif
740 #ifdef reg_ESP
741     ESP = saved_ESP;
742 #endif
743 #ifdef reg_EBP
744     EBP = saved_EBP;
745 #endif
746 #ifdef reg_ESI
747     ESI = saved_ESI;
748 #endif
749 #ifdef reg_EDI
750     EDI = saved_EDI;
751 #endif
752 #elif defined(TARGET_ARM)
753     env->cpsr = compute_cpsr();
754     /* XXX: Save/restore host fpu exception state?.  */
755 #elif defined(TARGET_SPARC)
756 #if defined(reg_REGWPTR)
757     REGWPTR = saved_regwptr;
758 #endif
759 #elif defined(TARGET_PPC)
760 #elif defined(TARGET_MIPS)
761 #else
762 #error unsupported target CPU
763 #endif
764 #ifdef __sparc__
765     asm volatile ("mov %0, %%i7" : : "r" (saved_i7));
766 #endif
767     T0 = saved_T0;
768     T1 = saved_T1;
769 #if defined(reg_T2)
770     T2 = saved_T2;
771 #endif
772     env = saved_env;
773     /* fail safe : never use cpu_single_env outside cpu_exec() */
774     cpu_single_env = NULL; 
775     return ret;
776 }
777
778 /* must only be called from the generated code as an exception can be
779    generated */
780 void tb_invalidate_page_range(target_ulong start, target_ulong end)
781 {
782     /* XXX: cannot enable it yet because it yields to MMU exception
783        where NIP != read address on PowerPC */
784 #if 0
785     target_ulong phys_addr;
786     phys_addr = get_phys_addr_code(env, start);
787     tb_invalidate_phys_page_range(phys_addr, phys_addr + end - start, 0);
788 #endif
789 }
790
791 #if defined(TARGET_I386) && defined(CONFIG_USER_ONLY)
792
793 void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector)
794 {
795     CPUX86State *saved_env;
796
797     saved_env = env;
798     env = s;
799     if (!(env->cr[0] & CR0_PE_MASK) || (env->eflags & VM_MASK)) {
800         selector &= 0xffff;
801         cpu_x86_load_seg_cache(env, seg_reg, selector, 
802                                (selector << 4), 0xffff, 0);
803     } else {
804         load_seg(seg_reg, selector);
805     }
806     env = saved_env;
807 }
808
809 void cpu_x86_fsave(CPUX86State *s, uint8_t *ptr, int data32)
810 {
811     CPUX86State *saved_env;
812
813     saved_env = env;
814     env = s;
815     
816     helper_fsave((target_ulong)ptr, data32);
817
818     env = saved_env;
819 }
820
821 void cpu_x86_frstor(CPUX86State *s, uint8_t *ptr, int data32)
822 {
823     CPUX86State *saved_env;
824
825     saved_env = env;
826     env = s;
827     
828     helper_frstor((target_ulong)ptr, data32);
829
830     env = saved_env;
831 }
832
833 #endif /* TARGET_I386 */
834
835 #if !defined(CONFIG_SOFTMMU)
836
837 #if defined(TARGET_I386)
838
839 /* 'pc' is the host PC at which the exception was raised. 'address' is
840    the effective address of the memory exception. 'is_write' is 1 if a
841    write caused the exception and otherwise 0'. 'old_set' is the
842    signal set which should be restored */
843 static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
844                                     int is_write, sigset_t *old_set, 
845                                     void *puc)
846 {
847     TranslationBlock *tb;
848     int ret;
849
850     if (cpu_single_env)
851         env = cpu_single_env; /* XXX: find a correct solution for multithread */
852 #if defined(DEBUG_SIGNAL)
853     qemu_printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n", 
854                 pc, address, is_write, *(unsigned long *)old_set);
855 #endif
856     /* XXX: locking issue */
857     if (is_write && page_unprotect(address, pc, puc)) {
858         return 1;
859     }
860
861     /* see if it is an MMU fault */
862     ret = cpu_x86_handle_mmu_fault(env, address, is_write, 
863                                    ((env->hflags & HF_CPL_MASK) == 3), 0);
864     if (ret < 0)
865         return 0; /* not an MMU fault */
866     if (ret == 0)
867         return 1; /* the MMU fault was handled without causing real CPU fault */
868     /* now we have a real cpu fault */
869     tb = tb_find_pc(pc);
870     if (tb) {
871         /* the PC is inside the translated code. It means that we have
872            a virtual CPU fault */
873         cpu_restore_state(tb, env, pc, puc);
874     }
875     if (ret == 1) {
876 #if 0
877         printf("PF exception: EIP=0x%08x CR2=0x%08x error=0x%x\n", 
878                env->eip, env->cr[2], env->error_code);
879 #endif
880         /* we restore the process signal mask as the sigreturn should
881            do it (XXX: use sigsetjmp) */
882         sigprocmask(SIG_SETMASK, old_set, NULL);
883         raise_exception_err(EXCP0E_PAGE, env->error_code);
884     } else {
885         /* activate soft MMU for this block */
886         env->hflags |= HF_SOFTMMU_MASK;
887         cpu_resume_from_signal(env, puc);
888     }
889     /* never comes here */
890     return 1;
891 }
892
893 #elif defined(TARGET_ARM)
894 static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
895                                     int is_write, sigset_t *old_set,
896                                     void *puc)
897 {
898     TranslationBlock *tb;
899     int ret;
900
901     if (cpu_single_env)
902         env = cpu_single_env; /* XXX: find a correct solution for multithread */
903 #if defined(DEBUG_SIGNAL)
904     printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n", 
905            pc, address, is_write, *(unsigned long *)old_set);
906 #endif
907     /* XXX: locking issue */
908     if (is_write && page_unprotect(address, pc, puc)) {
909         return 1;
910     }
911     /* see if it is an MMU fault */
912     ret = cpu_arm_handle_mmu_fault(env, address, is_write, 1, 0);
913     if (ret < 0)
914         return 0; /* not an MMU fault */
915     if (ret == 0)
916         return 1; /* the MMU fault was handled without causing real CPU fault */
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     /* we restore the process signal mask as the sigreturn should
925        do it (XXX: use sigsetjmp) */
926     sigprocmask(SIG_SETMASK, old_set, NULL);
927     cpu_loop_exit();
928 }
929 #elif defined(TARGET_SPARC)
930 static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
931                                     int is_write, sigset_t *old_set,
932                                     void *puc)
933 {
934     TranslationBlock *tb;
935     int ret;
936
937     if (cpu_single_env)
938         env = cpu_single_env; /* XXX: find a correct solution for multithread */
939 #if defined(DEBUG_SIGNAL)
940     printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n", 
941            pc, address, is_write, *(unsigned long *)old_set);
942 #endif
943     /* XXX: locking issue */
944     if (is_write && page_unprotect(address, pc, puc)) {
945         return 1;
946     }
947     /* see if it is an MMU fault */
948     ret = cpu_sparc_handle_mmu_fault(env, address, is_write, 1, 0);
949     if (ret < 0)
950         return 0; /* not an MMU fault */
951     if (ret == 0)
952         return 1; /* the MMU fault was handled without causing real CPU fault */
953     /* now we have a real cpu fault */
954     tb = tb_find_pc(pc);
955     if (tb) {
956         /* the PC is inside the translated code. It means that we have
957            a virtual CPU fault */
958         cpu_restore_state(tb, env, pc, puc);
959     }
960     /* we restore the process signal mask as the sigreturn should
961        do it (XXX: use sigsetjmp) */
962     sigprocmask(SIG_SETMASK, old_set, NULL);
963     cpu_loop_exit();
964 }
965 #elif defined (TARGET_PPC)
966 static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
967                                     int is_write, sigset_t *old_set,
968                                     void *puc)
969 {
970     TranslationBlock *tb;
971     int ret;
972     
973     if (cpu_single_env)
974         env = cpu_single_env; /* XXX: find a correct solution for multithread */
975 #if defined(DEBUG_SIGNAL)
976     printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n", 
977            pc, address, is_write, *(unsigned long *)old_set);
978 #endif
979     /* XXX: locking issue */
980     if (is_write && page_unprotect(address, pc, puc)) {
981         return 1;
982     }
983
984     /* see if it is an MMU fault */
985     ret = cpu_ppc_handle_mmu_fault(env, address, is_write, msr_pr, 0);
986     if (ret < 0)
987         return 0; /* not an MMU fault */
988     if (ret == 0)
989         return 1; /* the MMU fault was handled without causing real CPU fault */
990
991     /* now we have a real cpu fault */
992     tb = tb_find_pc(pc);
993     if (tb) {
994         /* the PC is inside the translated code. It means that we have
995            a virtual CPU fault */
996         cpu_restore_state(tb, env, pc, puc);
997     }
998     if (ret == 1) {
999 #if 0
1000         printf("PF exception: NIP=0x%08x error=0x%x %p\n", 
1001                env->nip, env->error_code, tb);
1002 #endif
1003     /* we restore the process signal mask as the sigreturn should
1004        do it (XXX: use sigsetjmp) */
1005         sigprocmask(SIG_SETMASK, old_set, NULL);
1006         do_raise_exception_err(env->exception_index, env->error_code);
1007     } else {
1008         /* activate soft MMU for this block */
1009         cpu_resume_from_signal(env, puc);
1010     }
1011     /* never comes here */
1012     return 1;
1013 }
1014
1015 #elif defined (TARGET_MIPS)
1016 static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
1017                                     int is_write, sigset_t *old_set,
1018                                     void *puc)
1019 {
1020     TranslationBlock *tb;
1021     int ret;
1022     
1023     if (cpu_single_env)
1024         env = cpu_single_env; /* XXX: find a correct solution for multithread */
1025 #if defined(DEBUG_SIGNAL)
1026     printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n", 
1027            pc, address, is_write, *(unsigned long *)old_set);
1028 #endif
1029     /* XXX: locking issue */
1030     if (is_write && page_unprotect(address, pc, puc)) {
1031         return 1;
1032     }
1033
1034     /* see if it is an MMU fault */
1035     ret = cpu_ppc_handle_mmu_fault(env, address, is_write, msr_pr, 0);
1036     if (ret < 0)
1037         return 0; /* not an MMU fault */
1038     if (ret == 0)
1039         return 1; /* the MMU fault was handled without causing real CPU fault */
1040
1041     /* now we have a real cpu fault */
1042     tb = tb_find_pc(pc);
1043     if (tb) {
1044         /* the PC is inside the translated code. It means that we have
1045            a virtual CPU fault */
1046         cpu_restore_state(tb, env, pc, puc);
1047     }
1048     if (ret == 1) {
1049 #if 0
1050         printf("PF exception: NIP=0x%08x error=0x%x %p\n", 
1051                env->nip, env->error_code, tb);
1052 #endif
1053     /* we restore the process signal mask as the sigreturn should
1054        do it (XXX: use sigsetjmp) */
1055         sigprocmask(SIG_SETMASK, old_set, NULL);
1056         do_raise_exception_err(env->exception_index, env->error_code);
1057     } else {
1058         /* activate soft MMU for this block */
1059         cpu_resume_from_signal(env, puc);
1060     }
1061     /* never comes here */
1062     return 1;
1063 }
1064
1065 #else
1066 #error unsupported target CPU
1067 #endif
1068
1069 #if defined(__i386__)
1070
1071 #if defined(USE_CODE_COPY)
1072 static void cpu_send_trap(unsigned long pc, int trap, 
1073                           struct ucontext *uc)
1074 {
1075     TranslationBlock *tb;
1076
1077     if (cpu_single_env)
1078         env = cpu_single_env; /* XXX: find a correct solution for multithread */
1079     /* now we have a real cpu fault */
1080     tb = tb_find_pc(pc);
1081     if (tb) {
1082         /* the PC is inside the translated code. It means that we have
1083            a virtual CPU fault */
1084         cpu_restore_state(tb, env, pc, uc);
1085     }
1086     sigprocmask(SIG_SETMASK, &uc->uc_sigmask, NULL);
1087     raise_exception_err(trap, env->error_code);
1088 }
1089 #endif
1090
1091 int cpu_signal_handler(int host_signum, struct siginfo *info, 
1092                        void *puc)
1093 {
1094     struct ucontext *uc = puc;
1095     unsigned long pc;
1096     int trapno;
1097
1098 #ifndef REG_EIP
1099 /* for glibc 2.1 */
1100 #define REG_EIP    EIP
1101 #define REG_ERR    ERR
1102 #define REG_TRAPNO TRAPNO
1103 #endif
1104     pc = uc->uc_mcontext.gregs[REG_EIP];
1105     trapno = uc->uc_mcontext.gregs[REG_TRAPNO];
1106 #if defined(TARGET_I386) && defined(USE_CODE_COPY)
1107     if (trapno == 0x00 || trapno == 0x05) {
1108         /* send division by zero or bound exception */
1109         cpu_send_trap(pc, trapno, uc);
1110         return 1;
1111     } else
1112 #endif
1113         return handle_cpu_signal(pc, (unsigned long)info->si_addr, 
1114                                  trapno == 0xe ? 
1115                                  (uc->uc_mcontext.gregs[REG_ERR] >> 1) & 1 : 0,
1116                                  &uc->uc_sigmask, puc);
1117 }
1118
1119 #elif defined(__x86_64__)
1120
1121 int cpu_signal_handler(int host_signum, struct siginfo *info,
1122                        void *puc)
1123 {
1124     struct ucontext *uc = puc;
1125     unsigned long pc;
1126
1127     pc = uc->uc_mcontext.gregs[REG_RIP];
1128     return handle_cpu_signal(pc, (unsigned long)info->si_addr, 
1129                              uc->uc_mcontext.gregs[REG_TRAPNO] == 0xe ? 
1130                              (uc->uc_mcontext.gregs[REG_ERR] >> 1) & 1 : 0,
1131                              &uc->uc_sigmask, puc);
1132 }
1133
1134 #elif defined(__powerpc__)
1135
1136 /***********************************************************************
1137  * signal context platform-specific definitions
1138  * From Wine
1139  */
1140 #ifdef linux
1141 /* All Registers access - only for local access */
1142 # define REG_sig(reg_name, context)             ((context)->uc_mcontext.regs->reg_name)
1143 /* Gpr Registers access  */
1144 # define GPR_sig(reg_num, context)              REG_sig(gpr[reg_num], context)
1145 # define IAR_sig(context)                       REG_sig(nip, context)   /* Program counter */
1146 # define MSR_sig(context)                       REG_sig(msr, context)   /* Machine State Register (Supervisor) */
1147 # define CTR_sig(context)                       REG_sig(ctr, context)   /* Count register */
1148 # define XER_sig(context)                       REG_sig(xer, context) /* User's integer exception register */
1149 # define LR_sig(context)                        REG_sig(link, context) /* Link register */
1150 # define CR_sig(context)                        REG_sig(ccr, context) /* Condition register */
1151 /* Float Registers access  */
1152 # define FLOAT_sig(reg_num, context)            (((double*)((char*)((context)->uc_mcontext.regs+48*4)))[reg_num])
1153 # define FPSCR_sig(context)                     (*(int*)((char*)((context)->uc_mcontext.regs+(48+32*2)*4)))
1154 /* Exception Registers access */
1155 # define DAR_sig(context)                       REG_sig(dar, context)
1156 # define DSISR_sig(context)                     REG_sig(dsisr, context)
1157 # define TRAP_sig(context)                      REG_sig(trap, context)
1158 #endif /* linux */
1159
1160 #ifdef __APPLE__
1161 # include <sys/ucontext.h>
1162 typedef struct ucontext SIGCONTEXT;
1163 /* All Registers access - only for local access */
1164 # define REG_sig(reg_name, context)             ((context)->uc_mcontext->ss.reg_name)
1165 # define FLOATREG_sig(reg_name, context)        ((context)->uc_mcontext->fs.reg_name)
1166 # define EXCEPREG_sig(reg_name, context)        ((context)->uc_mcontext->es.reg_name)
1167 # define VECREG_sig(reg_name, context)          ((context)->uc_mcontext->vs.reg_name)
1168 /* Gpr Registers access */
1169 # define GPR_sig(reg_num, context)              REG_sig(r##reg_num, context)
1170 # define IAR_sig(context)                       REG_sig(srr0, context)  /* Program counter */
1171 # define MSR_sig(context)                       REG_sig(srr1, context)  /* Machine State Register (Supervisor) */
1172 # define CTR_sig(context)                       REG_sig(ctr, context)
1173 # define XER_sig(context)                       REG_sig(xer, context) /* Link register */
1174 # define LR_sig(context)                        REG_sig(lr, context)  /* User's integer exception register */
1175 # define CR_sig(context)                        REG_sig(cr, context)  /* Condition register */
1176 /* Float Registers access */
1177 # define FLOAT_sig(reg_num, context)            FLOATREG_sig(fpregs[reg_num], context)
1178 # define FPSCR_sig(context)                     ((double)FLOATREG_sig(fpscr, context))
1179 /* Exception Registers access */
1180 # define DAR_sig(context)                       EXCEPREG_sig(dar, context)     /* Fault registers for coredump */
1181 # define DSISR_sig(context)                     EXCEPREG_sig(dsisr, context)
1182 # define TRAP_sig(context)                      EXCEPREG_sig(exception, context) /* number of powerpc exception taken */
1183 #endif /* __APPLE__ */
1184
1185 int cpu_signal_handler(int host_signum, struct siginfo *info, 
1186                        void *puc)
1187 {
1188     struct ucontext *uc = puc;
1189     unsigned long pc;
1190     int is_write;
1191
1192     pc = IAR_sig(uc);
1193     is_write = 0;
1194 #if 0
1195     /* ppc 4xx case */
1196     if (DSISR_sig(uc) & 0x00800000)
1197         is_write = 1;
1198 #else
1199     if (TRAP_sig(uc) != 0x400 && (DSISR_sig(uc) & 0x02000000))
1200         is_write = 1;
1201 #endif
1202     return handle_cpu_signal(pc, (unsigned long)info->si_addr, 
1203                              is_write, &uc->uc_sigmask, puc);
1204 }
1205
1206 #elif defined(__alpha__)
1207
1208 int cpu_signal_handler(int host_signum, struct siginfo *info, 
1209                            void *puc)
1210 {
1211     struct ucontext *uc = puc;
1212     uint32_t *pc = uc->uc_mcontext.sc_pc;
1213     uint32_t insn = *pc;
1214     int is_write = 0;
1215
1216     /* XXX: need kernel patch to get write flag faster */
1217     switch (insn >> 26) {
1218     case 0x0d: // stw
1219     case 0x0e: // stb
1220     case 0x0f: // stq_u
1221     case 0x24: // stf
1222     case 0x25: // stg
1223     case 0x26: // sts
1224     case 0x27: // stt
1225     case 0x2c: // stl
1226     case 0x2d: // stq
1227     case 0x2e: // stl_c
1228     case 0x2f: // stq_c
1229         is_write = 1;
1230     }
1231
1232     return handle_cpu_signal(pc, (unsigned long)info->si_addr, 
1233                              is_write, &uc->uc_sigmask, puc);
1234 }
1235 #elif defined(__sparc__)
1236
1237 int cpu_signal_handler(int host_signum, struct siginfo *info, 
1238                        void *puc)
1239 {
1240     uint32_t *regs = (uint32_t *)(info + 1);
1241     void *sigmask = (regs + 20);
1242     unsigned long pc;
1243     int is_write;
1244     uint32_t insn;
1245     
1246     /* XXX: is there a standard glibc define ? */
1247     pc = regs[1];
1248     /* XXX: need kernel patch to get write flag faster */
1249     is_write = 0;
1250     insn = *(uint32_t *)pc;
1251     if ((insn >> 30) == 3) {
1252       switch((insn >> 19) & 0x3f) {
1253       case 0x05: // stb
1254       case 0x06: // sth
1255       case 0x04: // st
1256       case 0x07: // std
1257       case 0x24: // stf
1258       case 0x27: // stdf
1259       case 0x25: // stfsr
1260         is_write = 1;
1261         break;
1262       }
1263     }
1264     return handle_cpu_signal(pc, (unsigned long)info->si_addr, 
1265                              is_write, sigmask, NULL);
1266 }
1267
1268 #elif defined(__arm__)
1269
1270 int cpu_signal_handler(int host_signum, struct siginfo *info, 
1271                        void *puc)
1272 {
1273     struct ucontext *uc = puc;
1274     unsigned long pc;
1275     int is_write;
1276     
1277     pc = uc->uc_mcontext.gregs[R15];
1278     /* XXX: compute is_write */
1279     is_write = 0;
1280     return handle_cpu_signal(pc, (unsigned long)info->si_addr, 
1281                              is_write,
1282                              &uc->uc_sigmask);
1283 }
1284
1285 #elif defined(__mc68000)
1286
1287 int cpu_signal_handler(int host_signum, struct siginfo *info, 
1288                        void *puc)
1289 {
1290     struct ucontext *uc = puc;
1291     unsigned long pc;
1292     int is_write;
1293     
1294     pc = uc->uc_mcontext.gregs[16];
1295     /* XXX: compute is_write */
1296     is_write = 0;
1297     return handle_cpu_signal(pc, (unsigned long)info->si_addr, 
1298                              is_write,
1299                              &uc->uc_sigmask, puc);
1300 }
1301
1302 #elif defined(__ia64)
1303
1304 #ifndef __ISR_VALID
1305   /* This ought to be in <bits/siginfo.h>... */
1306 # define __ISR_VALID    1
1307 # define si_flags       _sifields._sigfault._si_pad0
1308 #endif
1309
1310 int cpu_signal_handler(int host_signum, struct siginfo *info, void *puc)
1311 {
1312     struct ucontext *uc = puc;
1313     unsigned long ip;
1314     int is_write = 0;
1315
1316     ip = uc->uc_mcontext.sc_ip;
1317     switch (host_signum) {
1318       case SIGILL:
1319       case SIGFPE:
1320       case SIGSEGV:
1321       case SIGBUS:
1322       case SIGTRAP:
1323           if (info->si_code && (info->si_flags & __ISR_VALID))
1324               /* ISR.W (write-access) is bit 33:  */
1325               is_write = (info->si_isr >> 33) & 1;
1326           break;
1327
1328       default:
1329           break;
1330     }
1331     return handle_cpu_signal(ip, (unsigned long)info->si_addr,
1332                              is_write,
1333                              &uc->uc_sigmask, puc);
1334 }
1335
1336 #elif defined(__s390__)
1337
1338 int cpu_signal_handler(int host_signum, struct siginfo *info, 
1339                        void *puc)
1340 {
1341     struct ucontext *uc = puc;
1342     unsigned long pc;
1343     int is_write;
1344     
1345     pc = uc->uc_mcontext.psw.addr;
1346     /* XXX: compute is_write */
1347     is_write = 0;
1348     return handle_cpu_signal(pc, (unsigned long)info->si_addr, 
1349                              is_write,
1350                              &uc->uc_sigmask, puc);
1351 }
1352
1353 #else
1354
1355 #error host CPU specific signal handler needed
1356
1357 #endif
1358
1359 #endif /* !defined(CONFIG_SOFTMMU) */