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