]> rtime.felk.cvut.cz Git - lisovros/qemu_apohw.git/blob - cpu-exec.c
tcg-hppa: Compute is_write in cpu_signal_handler.
[lisovros/qemu_apohw.git] / 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, see <http://www.gnu.org/licenses/>.
18  */
19 #include "config.h"
20 #include "exec.h"
21 #include "disas.h"
22 #include "tcg.h"
23 #include "kvm.h"
24
25 #if !defined(CONFIG_SOFTMMU)
26 #undef EAX
27 #undef ECX
28 #undef EDX
29 #undef EBX
30 #undef ESP
31 #undef EBP
32 #undef ESI
33 #undef EDI
34 #undef EIP
35 #include <signal.h>
36 #ifdef __linux__
37 #include <sys/ucontext.h>
38 #endif
39 #endif
40
41 #if defined(__sparc__) && !defined(CONFIG_SOLARIS)
42 // Work around ugly bugs in glibc that mangle global register contents
43 #undef env
44 #define env cpu_single_env
45 #endif
46
47 int tb_invalidated_flag;
48
49 //#define CONFIG_DEBUG_EXEC
50 //#define DEBUG_SIGNAL
51
52 int qemu_cpu_has_work(CPUState *env)
53 {
54     return cpu_has_work(env);
55 }
56
57 void cpu_loop_exit(void)
58 {
59     env->current_tb = NULL;
60     longjmp(env->jmp_env, 1);
61 }
62
63 /* exit the current TB from a signal handler. The host registers are
64    restored in a state compatible with the CPU emulator
65  */
66 void cpu_resume_from_signal(CPUState *env1, void *puc)
67 {
68 #if !defined(CONFIG_SOFTMMU)
69 #ifdef __linux__
70     struct ucontext *uc = puc;
71 #elif defined(__OpenBSD__)
72     struct sigcontext *uc = puc;
73 #endif
74 #endif
75
76     env = env1;
77
78     /* XXX: restore cpu registers saved in host registers */
79
80 #if !defined(CONFIG_SOFTMMU)
81     if (puc) {
82         /* XXX: use siglongjmp ? */
83 #ifdef __linux__
84 #ifdef __ia64
85         sigprocmask(SIG_SETMASK, (sigset_t *)&uc->uc_sigmask, NULL);
86 #else
87         sigprocmask(SIG_SETMASK, &uc->uc_sigmask, NULL);
88 #endif
89 #elif defined(__OpenBSD__)
90         sigprocmask(SIG_SETMASK, &uc->sc_mask, NULL);
91 #endif
92     }
93 #endif
94     env->exception_index = -1;
95     longjmp(env->jmp_env, 1);
96 }
97
98 /* Execute the code without caching the generated code. An interpreter
99    could be used if available. */
100 static void cpu_exec_nocache(int max_cycles, TranslationBlock *orig_tb)
101 {
102     unsigned long next_tb;
103     TranslationBlock *tb;
104
105     /* Should never happen.
106        We only end up here when an existing TB is too long.  */
107     if (max_cycles > CF_COUNT_MASK)
108         max_cycles = CF_COUNT_MASK;
109
110     tb = tb_gen_code(env, orig_tb->pc, orig_tb->cs_base, orig_tb->flags,
111                      max_cycles);
112     env->current_tb = tb;
113     /* execute the generated code */
114     next_tb = tcg_qemu_tb_exec(tb->tc_ptr);
115     env->current_tb = NULL;
116
117     if ((next_tb & 3) == 2) {
118         /* Restore PC.  This may happen if async event occurs before
119            the TB starts executing.  */
120         cpu_pc_from_tb(env, tb);
121     }
122     tb_phys_invalidate(tb, -1);
123     tb_free(tb);
124 }
125
126 static TranslationBlock *tb_find_slow(target_ulong pc,
127                                       target_ulong cs_base,
128                                       uint64_t flags)
129 {
130     TranslationBlock *tb, **ptb1;
131     unsigned int h;
132     tb_page_addr_t phys_pc, phys_page1, phys_page2;
133     target_ulong virt_page2;
134
135     tb_invalidated_flag = 0;
136
137     /* find translated block using physical mappings */
138     phys_pc = get_page_addr_code(env, pc);
139     phys_page1 = phys_pc & TARGET_PAGE_MASK;
140     phys_page2 = -1;
141     h = tb_phys_hash_func(phys_pc);
142     ptb1 = &tb_phys_hash[h];
143     for(;;) {
144         tb = *ptb1;
145         if (!tb)
146             goto not_found;
147         if (tb->pc == pc &&
148             tb->page_addr[0] == phys_page1 &&
149             tb->cs_base == cs_base &&
150             tb->flags == flags) {
151             /* check next page if needed */
152             if (tb->page_addr[1] != -1) {
153                 virt_page2 = (pc & TARGET_PAGE_MASK) +
154                     TARGET_PAGE_SIZE;
155                 phys_page2 = get_page_addr_code(env, virt_page2);
156                 if (tb->page_addr[1] == phys_page2)
157                     goto found;
158             } else {
159                 goto found;
160             }
161         }
162         ptb1 = &tb->phys_hash_next;
163     }
164  not_found:
165    /* if no translated code available, then translate it now */
166     tb = tb_gen_code(env, pc, cs_base, flags, 0);
167
168  found:
169     /* we add the TB in the virtual pc hash table */
170     env->tb_jmp_cache[tb_jmp_cache_hash_func(pc)] = tb;
171     return tb;
172 }
173
174 static inline TranslationBlock *tb_find_fast(void)
175 {
176     TranslationBlock *tb;
177     target_ulong cs_base, pc;
178     int flags;
179
180     /* we record a subset of the CPU state. It will
181        always be the same before a given translated block
182        is executed. */
183     cpu_get_tb_cpu_state(env, &pc, &cs_base, &flags);
184     tb = env->tb_jmp_cache[tb_jmp_cache_hash_func(pc)];
185     if (unlikely(!tb || tb->pc != pc || tb->cs_base != cs_base ||
186                  tb->flags != flags)) {
187         tb = tb_find_slow(pc, cs_base, flags);
188     }
189     return tb;
190 }
191
192 static CPUDebugExcpHandler *debug_excp_handler;
193
194 CPUDebugExcpHandler *cpu_set_debug_excp_handler(CPUDebugExcpHandler *handler)
195 {
196     CPUDebugExcpHandler *old_handler = debug_excp_handler;
197
198     debug_excp_handler = handler;
199     return old_handler;
200 }
201
202 static void cpu_handle_debug_exception(CPUState *env)
203 {
204     CPUWatchpoint *wp;
205
206     if (!env->watchpoint_hit)
207         QTAILQ_FOREACH(wp, &env->watchpoints, entry)
208             wp->flags &= ~BP_WATCHPOINT_HIT;
209
210     if (debug_excp_handler)
211         debug_excp_handler(env);
212 }
213
214 /* main execution loop */
215
216 int cpu_exec(CPUState *env1)
217 {
218     volatile host_reg_t saved_env_reg;
219     int ret, interrupt_request;
220     TranslationBlock *tb;
221     uint8_t *tc_ptr;
222     unsigned long next_tb;
223
224     if (cpu_halted(env1) == EXCP_HALTED)
225         return EXCP_HALTED;
226
227     cpu_single_env = env1;
228
229     /* the access to env below is actually saving the global register's
230        value, so that files not including target-xyz/exec.h are free to
231        use it.  */
232     QEMU_BUILD_BUG_ON (sizeof (saved_env_reg) != sizeof (env));
233     saved_env_reg = (host_reg_t) env;
234     asm("");
235     env = env1;
236
237 #if defined(TARGET_I386)
238     if (!kvm_enabled()) {
239         /* put eflags in CPU temporary format */
240         CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
241         DF = 1 - (2 * ((env->eflags >> 10) & 1));
242         CC_OP = CC_OP_EFLAGS;
243         env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
244     }
245 #elif defined(TARGET_SPARC)
246 #elif defined(TARGET_M68K)
247     env->cc_op = CC_OP_FLAGS;
248     env->cc_dest = env->sr & 0xf;
249     env->cc_x = (env->sr >> 4) & 1;
250 #elif defined(TARGET_ALPHA)
251 #elif defined(TARGET_ARM)
252 #elif defined(TARGET_PPC)
253 #elif defined(TARGET_MICROBLAZE)
254 #elif defined(TARGET_MIPS)
255 #elif defined(TARGET_SH4)
256 #elif defined(TARGET_CRIS)
257 #elif defined(TARGET_S390X)
258     /* XXXXX */
259 #else
260 #error unsupported target CPU
261 #endif
262     env->exception_index = -1;
263
264     /* prepare setjmp context for exception handling */
265     for(;;) {
266         if (setjmp(env->jmp_env) == 0) {
267 #if defined(__sparc__) && !defined(CONFIG_SOLARIS)
268 #undef env
269                     env = cpu_single_env;
270 #define env cpu_single_env
271 #endif
272             /* if an exception is pending, we execute it here */
273             if (env->exception_index >= 0) {
274                 if (env->exception_index >= EXCP_INTERRUPT) {
275                     /* exit request from the cpu execution loop */
276                     ret = env->exception_index;
277                     if (ret == EXCP_DEBUG)
278                         cpu_handle_debug_exception(env);
279                     break;
280                 } else {
281 #if defined(CONFIG_USER_ONLY)
282                     /* if user mode only, we simulate a fake exception
283                        which will be handled outside the cpu execution
284                        loop */
285 #if defined(TARGET_I386)
286                     do_interrupt_user(env->exception_index,
287                                       env->exception_is_int,
288                                       env->error_code,
289                                       env->exception_next_eip);
290                     /* successfully delivered */
291                     env->old_exception = -1;
292 #endif
293                     ret = env->exception_index;
294                     break;
295 #else
296 #if defined(TARGET_I386)
297                     /* simulate a real cpu exception. On i386, it can
298                        trigger new exceptions, but we do not handle
299                        double or triple faults yet. */
300                     do_interrupt(env->exception_index,
301                                  env->exception_is_int,
302                                  env->error_code,
303                                  env->exception_next_eip, 0);
304                     /* successfully delivered */
305                     env->old_exception = -1;
306 #elif defined(TARGET_PPC)
307                     do_interrupt(env);
308 #elif defined(TARGET_MICROBLAZE)
309                     do_interrupt(env);
310 #elif defined(TARGET_MIPS)
311                     do_interrupt(env);
312 #elif defined(TARGET_SPARC)
313                     do_interrupt(env);
314 #elif defined(TARGET_ARM)
315                     do_interrupt(env);
316 #elif defined(TARGET_SH4)
317                     do_interrupt(env);
318 #elif defined(TARGET_ALPHA)
319                     do_interrupt(env);
320 #elif defined(TARGET_CRIS)
321                     do_interrupt(env);
322 #elif defined(TARGET_M68K)
323                     do_interrupt(0);
324 #endif
325                     env->exception_index = -1;
326 #endif
327                 }
328             }
329
330             if (kvm_enabled()) {
331                 kvm_cpu_exec(env);
332                 longjmp(env->jmp_env, 1);
333             }
334
335             next_tb = 0; /* force lookup of first TB */
336             for(;;) {
337                 interrupt_request = env->interrupt_request;
338                 if (unlikely(interrupt_request)) {
339                     if (unlikely(env->singlestep_enabled & SSTEP_NOIRQ)) {
340                         /* Mask out external interrupts for this step. */
341                         interrupt_request &= ~(CPU_INTERRUPT_HARD |
342                                                CPU_INTERRUPT_FIQ |
343                                                CPU_INTERRUPT_SMI |
344                                                CPU_INTERRUPT_NMI);
345                     }
346                     if (interrupt_request & CPU_INTERRUPT_DEBUG) {
347                         env->interrupt_request &= ~CPU_INTERRUPT_DEBUG;
348                         env->exception_index = EXCP_DEBUG;
349                         cpu_loop_exit();
350                     }
351 #if defined(TARGET_ARM) || defined(TARGET_SPARC) || defined(TARGET_MIPS) || \
352     defined(TARGET_PPC) || defined(TARGET_ALPHA) || defined(TARGET_CRIS) || \
353     defined(TARGET_MICROBLAZE)
354                     if (interrupt_request & CPU_INTERRUPT_HALT) {
355                         env->interrupt_request &= ~CPU_INTERRUPT_HALT;
356                         env->halted = 1;
357                         env->exception_index = EXCP_HLT;
358                         cpu_loop_exit();
359                     }
360 #endif
361 #if defined(TARGET_I386)
362                     if (interrupt_request & CPU_INTERRUPT_INIT) {
363                             svm_check_intercept(SVM_EXIT_INIT);
364                             do_cpu_init(env);
365                             env->exception_index = EXCP_HALTED;
366                             cpu_loop_exit();
367                     } else if (interrupt_request & CPU_INTERRUPT_SIPI) {
368                             do_cpu_sipi(env);
369                     } else if (env->hflags2 & HF2_GIF_MASK) {
370                         if ((interrupt_request & CPU_INTERRUPT_SMI) &&
371                             !(env->hflags & HF_SMM_MASK)) {
372                             svm_check_intercept(SVM_EXIT_SMI);
373                             env->interrupt_request &= ~CPU_INTERRUPT_SMI;
374                             do_smm_enter();
375                             next_tb = 0;
376                         } else if ((interrupt_request & CPU_INTERRUPT_NMI) &&
377                                    !(env->hflags2 & HF2_NMI_MASK)) {
378                             env->interrupt_request &= ~CPU_INTERRUPT_NMI;
379                             env->hflags2 |= HF2_NMI_MASK;
380                             do_interrupt(EXCP02_NMI, 0, 0, 0, 1);
381                             next_tb = 0;
382                         } else if (interrupt_request & CPU_INTERRUPT_MCE) {
383                             env->interrupt_request &= ~CPU_INTERRUPT_MCE;
384                             do_interrupt(EXCP12_MCHK, 0, 0, 0, 0);
385                             next_tb = 0;
386                         } else if ((interrupt_request & CPU_INTERRUPT_HARD) &&
387                                    (((env->hflags2 & HF2_VINTR_MASK) && 
388                                      (env->hflags2 & HF2_HIF_MASK)) ||
389                                     (!(env->hflags2 & HF2_VINTR_MASK) && 
390                                      (env->eflags & IF_MASK && 
391                                       !(env->hflags & HF_INHIBIT_IRQ_MASK))))) {
392                             int intno;
393                             svm_check_intercept(SVM_EXIT_INTR);
394                             env->interrupt_request &= ~(CPU_INTERRUPT_HARD | CPU_INTERRUPT_VIRQ);
395                             intno = cpu_get_pic_interrupt(env);
396                             qemu_log_mask(CPU_LOG_TB_IN_ASM, "Servicing hardware INT=0x%02x\n", intno);
397 #if defined(__sparc__) && !defined(CONFIG_SOLARIS)
398 #undef env
399                     env = cpu_single_env;
400 #define env cpu_single_env
401 #endif
402                             do_interrupt(intno, 0, 0, 0, 1);
403                             /* ensure that no TB jump will be modified as
404                                the program flow was changed */
405                             next_tb = 0;
406 #if !defined(CONFIG_USER_ONLY)
407                         } else if ((interrupt_request & CPU_INTERRUPT_VIRQ) &&
408                                    (env->eflags & IF_MASK) && 
409                                    !(env->hflags & HF_INHIBIT_IRQ_MASK)) {
410                             int intno;
411                             /* FIXME: this should respect TPR */
412                             svm_check_intercept(SVM_EXIT_VINTR);
413                             intno = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_vector));
414                             qemu_log_mask(CPU_LOG_TB_IN_ASM, "Servicing virtual hardware INT=0x%02x\n", intno);
415                             do_interrupt(intno, 0, 0, 0, 1);
416                             env->interrupt_request &= ~CPU_INTERRUPT_VIRQ;
417                             next_tb = 0;
418 #endif
419                         }
420                     }
421 #elif defined(TARGET_PPC)
422 #if 0
423                     if ((interrupt_request & CPU_INTERRUPT_RESET)) {
424                         cpu_reset(env);
425                     }
426 #endif
427                     if (interrupt_request & CPU_INTERRUPT_HARD) {
428                         ppc_hw_interrupt(env);
429                         if (env->pending_interrupts == 0)
430                             env->interrupt_request &= ~CPU_INTERRUPT_HARD;
431                         next_tb = 0;
432                     }
433 #elif defined(TARGET_MICROBLAZE)
434                     if ((interrupt_request & CPU_INTERRUPT_HARD)
435                         && (env->sregs[SR_MSR] & MSR_IE)
436                         && !(env->sregs[SR_MSR] & (MSR_EIP | MSR_BIP))
437                         && !(env->iflags & (D_FLAG | IMM_FLAG))) {
438                         env->exception_index = EXCP_IRQ;
439                         do_interrupt(env);
440                         next_tb = 0;
441                     }
442 #elif defined(TARGET_MIPS)
443                     if ((interrupt_request & CPU_INTERRUPT_HARD) &&
444                         (env->CP0_Status & env->CP0_Cause & CP0Ca_IP_mask) &&
445                         (env->CP0_Status & (1 << CP0St_IE)) &&
446                         !(env->CP0_Status & (1 << CP0St_EXL)) &&
447                         !(env->CP0_Status & (1 << CP0St_ERL)) &&
448                         !(env->hflags & MIPS_HFLAG_DM)) {
449                         /* Raise it */
450                         env->exception_index = EXCP_EXT_INTERRUPT;
451                         env->error_code = 0;
452                         do_interrupt(env);
453                         next_tb = 0;
454                     }
455 #elif defined(TARGET_SPARC)
456                     if (interrupt_request & CPU_INTERRUPT_HARD) {
457                         if (cpu_interrupts_enabled(env) &&
458                             env->interrupt_index > 0) {
459                             int pil = env->interrupt_index & 0xf;
460                             int type = env->interrupt_index & 0xf0;
461
462                             if (((type == TT_EXTINT) &&
463                                   cpu_pil_allowed(env, pil)) ||
464                                   type != TT_EXTINT) {
465                                 env->exception_index = env->interrupt_index;
466                                 do_interrupt(env);
467                                 next_tb = 0;
468                             }
469                         }
470                     } else if (interrupt_request & CPU_INTERRUPT_TIMER) {
471                         //do_interrupt(0, 0, 0, 0, 0);
472                         env->interrupt_request &= ~CPU_INTERRUPT_TIMER;
473                     }
474 #elif defined(TARGET_ARM)
475                     if (interrupt_request & CPU_INTERRUPT_FIQ
476                         && !(env->uncached_cpsr & CPSR_F)) {
477                         env->exception_index = EXCP_FIQ;
478                         do_interrupt(env);
479                         next_tb = 0;
480                     }
481                     /* ARMv7-M interrupt return works by loading a magic value
482                        into the PC.  On real hardware the load causes the
483                        return to occur.  The qemu implementation performs the
484                        jump normally, then does the exception return when the
485                        CPU tries to execute code at the magic address.
486                        This will cause the magic PC value to be pushed to
487                        the stack if an interrupt occured at the wrong time.
488                        We avoid this by disabling interrupts when
489                        pc contains a magic address.  */
490                     if (interrupt_request & CPU_INTERRUPT_HARD
491                         && ((IS_M(env) && env->regs[15] < 0xfffffff0)
492                             || !(env->uncached_cpsr & CPSR_I))) {
493                         env->exception_index = EXCP_IRQ;
494                         do_interrupt(env);
495                         next_tb = 0;
496                     }
497 #elif defined(TARGET_SH4)
498                     if (interrupt_request & CPU_INTERRUPT_HARD) {
499                         do_interrupt(env);
500                         next_tb = 0;
501                     }
502 #elif defined(TARGET_ALPHA)
503                     if (interrupt_request & CPU_INTERRUPT_HARD) {
504                         do_interrupt(env);
505                         next_tb = 0;
506                     }
507 #elif defined(TARGET_CRIS)
508                     if (interrupt_request & CPU_INTERRUPT_HARD
509                         && (env->pregs[PR_CCS] & I_FLAG)
510                         && !env->locked_irq) {
511                         env->exception_index = EXCP_IRQ;
512                         do_interrupt(env);
513                         next_tb = 0;
514                     }
515                     if (interrupt_request & CPU_INTERRUPT_NMI
516                         && (env->pregs[PR_CCS] & M_FLAG)) {
517                         env->exception_index = EXCP_NMI;
518                         do_interrupt(env);
519                         next_tb = 0;
520                     }
521 #elif defined(TARGET_M68K)
522                     if (interrupt_request & CPU_INTERRUPT_HARD
523                         && ((env->sr & SR_I) >> SR_I_SHIFT)
524                             < env->pending_level) {
525                         /* Real hardware gets the interrupt vector via an
526                            IACK cycle at this point.  Current emulated
527                            hardware doesn't rely on this, so we
528                            provide/save the vector when the interrupt is
529                            first signalled.  */
530                         env->exception_index = env->pending_vector;
531                         do_interrupt(1);
532                         next_tb = 0;
533                     }
534 #endif
535                    /* Don't use the cached interupt_request value,
536                       do_interrupt may have updated the EXITTB flag. */
537                     if (env->interrupt_request & CPU_INTERRUPT_EXITTB) {
538                         env->interrupt_request &= ~CPU_INTERRUPT_EXITTB;
539                         /* ensure that no TB jump will be modified as
540                            the program flow was changed */
541                         next_tb = 0;
542                     }
543                 }
544                 if (unlikely(env->exit_request)) {
545                     env->exit_request = 0;
546                     env->exception_index = EXCP_INTERRUPT;
547                     cpu_loop_exit();
548                 }
549 #ifdef CONFIG_DEBUG_EXEC
550                 if (qemu_loglevel_mask(CPU_LOG_TB_CPU)) {
551                     /* restore flags in standard format */
552 #if defined(TARGET_I386)
553                     env->eflags = env->eflags | helper_cc_compute_all(CC_OP) | (DF & DF_MASK);
554                     log_cpu_state(env, X86_DUMP_CCOP);
555                     env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
556 #elif defined(TARGET_ARM)
557                     log_cpu_state(env, 0);
558 #elif defined(TARGET_SPARC)
559                     log_cpu_state(env, 0);
560 #elif defined(TARGET_PPC)
561                     log_cpu_state(env, 0);
562 #elif defined(TARGET_M68K)
563                     cpu_m68k_flush_flags(env, env->cc_op);
564                     env->cc_op = CC_OP_FLAGS;
565                     env->sr = (env->sr & 0xffe0)
566                               | env->cc_dest | (env->cc_x << 4);
567                     log_cpu_state(env, 0);
568 #elif defined(TARGET_MICROBLAZE)
569                     log_cpu_state(env, 0);
570 #elif defined(TARGET_MIPS)
571                     log_cpu_state(env, 0);
572 #elif defined(TARGET_SH4)
573                     log_cpu_state(env, 0);
574 #elif defined(TARGET_ALPHA)
575                     log_cpu_state(env, 0);
576 #elif defined(TARGET_CRIS)
577                     log_cpu_state(env, 0);
578 #else
579 #error unsupported target CPU
580 #endif
581                 }
582 #endif
583                 spin_lock(&tb_lock);
584                 tb = tb_find_fast();
585                 /* Note: we do it here to avoid a gcc bug on Mac OS X when
586                    doing it in tb_find_slow */
587                 if (tb_invalidated_flag) {
588                     /* as some TB could have been invalidated because
589                        of memory exceptions while generating the code, we
590                        must recompute the hash index here */
591                     next_tb = 0;
592                     tb_invalidated_flag = 0;
593                 }
594 #ifdef CONFIG_DEBUG_EXEC
595                 qemu_log_mask(CPU_LOG_EXEC, "Trace 0x%08lx [" TARGET_FMT_lx "] %s\n",
596                              (long)tb->tc_ptr, tb->pc,
597                              lookup_symbol(tb->pc));
598 #endif
599                 /* see if we can patch the calling TB. When the TB
600                    spans two pages, we cannot safely do a direct
601                    jump. */
602                 if (next_tb != 0 && tb->page_addr[1] == -1) {
603                     tb_add_jump((TranslationBlock *)(next_tb & ~3), next_tb & 3, tb);
604                 }
605                 spin_unlock(&tb_lock);
606
607                 /* cpu_interrupt might be called while translating the
608                    TB, but before it is linked into a potentially
609                    infinite loop and becomes env->current_tb. Avoid
610                    starting execution if there is a pending interrupt. */
611                 if (!unlikely (env->exit_request)) {
612                     env->current_tb = tb;
613                     tc_ptr = tb->tc_ptr;
614                 /* execute the generated code */
615 #if defined(__sparc__) && !defined(CONFIG_SOLARIS)
616 #undef env
617                     env = cpu_single_env;
618 #define env cpu_single_env
619 #endif
620                     next_tb = tcg_qemu_tb_exec(tc_ptr);
621                     env->current_tb = NULL;
622                     if ((next_tb & 3) == 2) {
623                         /* Instruction counter expired.  */
624                         int insns_left;
625                         tb = (TranslationBlock *)(long)(next_tb & ~3);
626                         /* Restore PC.  */
627                         cpu_pc_from_tb(env, tb);
628                         insns_left = env->icount_decr.u32;
629                         if (env->icount_extra && insns_left >= 0) {
630                             /* Refill decrementer and continue execution.  */
631                             env->icount_extra += insns_left;
632                             if (env->icount_extra > 0xffff) {
633                                 insns_left = 0xffff;
634                             } else {
635                                 insns_left = env->icount_extra;
636                             }
637                             env->icount_extra -= insns_left;
638                             env->icount_decr.u16.low = insns_left;
639                         } else {
640                             if (insns_left > 0) {
641                                 /* Execute remaining instructions.  */
642                                 cpu_exec_nocache(insns_left, tb);
643                             }
644                             env->exception_index = EXCP_INTERRUPT;
645                             next_tb = 0;
646                             cpu_loop_exit();
647                         }
648                     }
649                 }
650                 /* reset soft MMU for next block (it can currently
651                    only be set by a memory fault) */
652             } /* for(;;) */
653         }
654     } /* for(;;) */
655
656
657 #if defined(TARGET_I386)
658     /* restore flags in standard format */
659     env->eflags = env->eflags | helper_cc_compute_all(CC_OP) | (DF & DF_MASK);
660 #elif defined(TARGET_ARM)
661     /* XXX: Save/restore host fpu exception state?.  */
662 #elif defined(TARGET_SPARC)
663 #elif defined(TARGET_PPC)
664 #elif defined(TARGET_M68K)
665     cpu_m68k_flush_flags(env, env->cc_op);
666     env->cc_op = CC_OP_FLAGS;
667     env->sr = (env->sr & 0xffe0)
668               | env->cc_dest | (env->cc_x << 4);
669 #elif defined(TARGET_MICROBLAZE)
670 #elif defined(TARGET_MIPS)
671 #elif defined(TARGET_SH4)
672 #elif defined(TARGET_ALPHA)
673 #elif defined(TARGET_CRIS)
674 #elif defined(TARGET_S390X)
675     /* XXXXX */
676 #else
677 #error unsupported target CPU
678 #endif
679
680     /* restore global registers */
681     asm("");
682     env = (void *) saved_env_reg;
683
684     /* fail safe : never use cpu_single_env outside cpu_exec() */
685     cpu_single_env = NULL;
686     return ret;
687 }
688
689 /* must only be called from the generated code as an exception can be
690    generated */
691 void tb_invalidate_page_range(target_ulong start, target_ulong end)
692 {
693     /* XXX: cannot enable it yet because it yields to MMU exception
694        where NIP != read address on PowerPC */
695 #if 0
696     target_ulong phys_addr;
697     phys_addr = get_phys_addr_code(env, start);
698     tb_invalidate_phys_page_range(phys_addr, phys_addr + end - start, 0);
699 #endif
700 }
701
702 #if defined(TARGET_I386) && defined(CONFIG_USER_ONLY)
703
704 void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector)
705 {
706     CPUX86State *saved_env;
707
708     saved_env = env;
709     env = s;
710     if (!(env->cr[0] & CR0_PE_MASK) || (env->eflags & VM_MASK)) {
711         selector &= 0xffff;
712         cpu_x86_load_seg_cache(env, seg_reg, selector,
713                                (selector << 4), 0xffff, 0);
714     } else {
715         helper_load_seg(seg_reg, selector);
716     }
717     env = saved_env;
718 }
719
720 void cpu_x86_fsave(CPUX86State *s, target_ulong ptr, int data32)
721 {
722     CPUX86State *saved_env;
723
724     saved_env = env;
725     env = s;
726
727     helper_fsave(ptr, data32);
728
729     env = saved_env;
730 }
731
732 void cpu_x86_frstor(CPUX86State *s, target_ulong ptr, int data32)
733 {
734     CPUX86State *saved_env;
735
736     saved_env = env;
737     env = s;
738
739     helper_frstor(ptr, data32);
740
741     env = saved_env;
742 }
743
744 #endif /* TARGET_I386 */
745
746 #if !defined(CONFIG_SOFTMMU)
747
748 #if defined(TARGET_I386)
749 #define EXCEPTION_ACTION raise_exception_err(env->exception_index, env->error_code)
750 #else
751 #define EXCEPTION_ACTION cpu_loop_exit()
752 #endif
753
754 /* 'pc' is the host PC at which the exception was raised. 'address' is
755    the effective address of the memory exception. 'is_write' is 1 if a
756    write caused the exception and otherwise 0'. 'old_set' is the
757    signal set which should be restored */
758 static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
759                                     int is_write, sigset_t *old_set,
760                                     void *puc)
761 {
762     TranslationBlock *tb;
763     int ret;
764
765     if (cpu_single_env)
766         env = cpu_single_env; /* XXX: find a correct solution for multithread */
767 #if defined(DEBUG_SIGNAL)
768     qemu_printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
769                 pc, address, is_write, *(unsigned long *)old_set);
770 #endif
771     /* XXX: locking issue */
772     if (is_write && page_unprotect(h2g(address), pc, puc)) {
773         return 1;
774     }
775
776     /* see if it is an MMU fault */
777     ret = cpu_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
778     if (ret < 0)
779         return 0; /* not an MMU fault */
780     if (ret == 0)
781         return 1; /* the MMU fault was handled without causing real CPU fault */
782     /* now we have a real cpu fault */
783     tb = tb_find_pc(pc);
784     if (tb) {
785         /* the PC is inside the translated code. It means that we have
786            a virtual CPU fault */
787         cpu_restore_state(tb, env, pc, puc);
788     }
789
790     /* we restore the process signal mask as the sigreturn should
791        do it (XXX: use sigsetjmp) */
792     sigprocmask(SIG_SETMASK, old_set, NULL);
793     EXCEPTION_ACTION;
794
795     /* never comes here */
796     return 1;
797 }
798
799 #if defined(__i386__)
800
801 #if defined(__APPLE__)
802 # include <sys/ucontext.h>
803
804 # define EIP_sig(context)  (*((unsigned long*)&(context)->uc_mcontext->ss.eip))
805 # define TRAP_sig(context)    ((context)->uc_mcontext->es.trapno)
806 # define ERROR_sig(context)   ((context)->uc_mcontext->es.err)
807 # define MASK_sig(context)    ((context)->uc_sigmask)
808 #elif defined (__NetBSD__)
809 # include <ucontext.h>
810
811 # define EIP_sig(context)     ((context)->uc_mcontext.__gregs[_REG_EIP])
812 # define TRAP_sig(context)    ((context)->uc_mcontext.__gregs[_REG_TRAPNO])
813 # define ERROR_sig(context)   ((context)->uc_mcontext.__gregs[_REG_ERR])
814 # define MASK_sig(context)    ((context)->uc_sigmask)
815 #elif defined (__FreeBSD__) || defined(__DragonFly__)
816 # include <ucontext.h>
817
818 # define EIP_sig(context)  (*((unsigned long*)&(context)->uc_mcontext.mc_eip))
819 # define TRAP_sig(context)    ((context)->uc_mcontext.mc_trapno)
820 # define ERROR_sig(context)   ((context)->uc_mcontext.mc_err)
821 # define MASK_sig(context)    ((context)->uc_sigmask)
822 #elif defined(__OpenBSD__)
823 # define EIP_sig(context)     ((context)->sc_eip)
824 # define TRAP_sig(context)    ((context)->sc_trapno)
825 # define ERROR_sig(context)   ((context)->sc_err)
826 # define MASK_sig(context)    ((context)->sc_mask)
827 #else
828 # define EIP_sig(context)     ((context)->uc_mcontext.gregs[REG_EIP])
829 # define TRAP_sig(context)    ((context)->uc_mcontext.gregs[REG_TRAPNO])
830 # define ERROR_sig(context)   ((context)->uc_mcontext.gregs[REG_ERR])
831 # define MASK_sig(context)    ((context)->uc_sigmask)
832 #endif
833
834 int cpu_signal_handler(int host_signum, void *pinfo,
835                        void *puc)
836 {
837     siginfo_t *info = pinfo;
838 #if defined(__NetBSD__) || defined (__FreeBSD__) || defined(__DragonFly__)
839     ucontext_t *uc = puc;
840 #elif defined(__OpenBSD__)
841     struct sigcontext *uc = puc;
842 #else
843     struct ucontext *uc = puc;
844 #endif
845     unsigned long pc;
846     int trapno;
847
848 #ifndef REG_EIP
849 /* for glibc 2.1 */
850 #define REG_EIP    EIP
851 #define REG_ERR    ERR
852 #define REG_TRAPNO TRAPNO
853 #endif
854     pc = EIP_sig(uc);
855     trapno = TRAP_sig(uc);
856     return handle_cpu_signal(pc, (unsigned long)info->si_addr,
857                              trapno == 0xe ?
858                              (ERROR_sig(uc) >> 1) & 1 : 0,
859                              &MASK_sig(uc), puc);
860 }
861
862 #elif defined(__x86_64__)
863
864 #ifdef __NetBSD__
865 #define PC_sig(context)       _UC_MACHINE_PC(context)
866 #define TRAP_sig(context)     ((context)->uc_mcontext.__gregs[_REG_TRAPNO])
867 #define ERROR_sig(context)    ((context)->uc_mcontext.__gregs[_REG_ERR])
868 #define MASK_sig(context)     ((context)->uc_sigmask)
869 #elif defined(__OpenBSD__)
870 #define PC_sig(context)       ((context)->sc_rip)
871 #define TRAP_sig(context)     ((context)->sc_trapno)
872 #define ERROR_sig(context)    ((context)->sc_err)
873 #define MASK_sig(context)     ((context)->sc_mask)
874 #elif defined (__FreeBSD__) || defined(__DragonFly__)
875 #include <ucontext.h>
876
877 #define PC_sig(context)  (*((unsigned long*)&(context)->uc_mcontext.mc_rip))
878 #define TRAP_sig(context)     ((context)->uc_mcontext.mc_trapno)
879 #define ERROR_sig(context)    ((context)->uc_mcontext.mc_err)
880 #define MASK_sig(context)     ((context)->uc_sigmask)
881 #else
882 #define PC_sig(context)       ((context)->uc_mcontext.gregs[REG_RIP])
883 #define TRAP_sig(context)     ((context)->uc_mcontext.gregs[REG_TRAPNO])
884 #define ERROR_sig(context)    ((context)->uc_mcontext.gregs[REG_ERR])
885 #define MASK_sig(context)     ((context)->uc_sigmask)
886 #endif
887
888 int cpu_signal_handler(int host_signum, void *pinfo,
889                        void *puc)
890 {
891     siginfo_t *info = pinfo;
892     unsigned long pc;
893 #if defined(__NetBSD__) || defined (__FreeBSD__) || defined(__DragonFly__)
894     ucontext_t *uc = puc;
895 #elif defined(__OpenBSD__)
896     struct sigcontext *uc = puc;
897 #else
898     struct ucontext *uc = puc;
899 #endif
900
901     pc = PC_sig(uc);
902     return handle_cpu_signal(pc, (unsigned long)info->si_addr,
903                              TRAP_sig(uc) == 0xe ?
904                              (ERROR_sig(uc) >> 1) & 1 : 0,
905                              &MASK_sig(uc), puc);
906 }
907
908 #elif defined(_ARCH_PPC)
909
910 /***********************************************************************
911  * signal context platform-specific definitions
912  * From Wine
913  */
914 #ifdef linux
915 /* All Registers access - only for local access */
916 # define REG_sig(reg_name, context)             ((context)->uc_mcontext.regs->reg_name)
917 /* Gpr Registers access  */
918 # define GPR_sig(reg_num, context)              REG_sig(gpr[reg_num], context)
919 # define IAR_sig(context)                       REG_sig(nip, context)   /* Program counter */
920 # define MSR_sig(context)                       REG_sig(msr, context)   /* Machine State Register (Supervisor) */
921 # define CTR_sig(context)                       REG_sig(ctr, context)   /* Count register */
922 # define XER_sig(context)                       REG_sig(xer, context) /* User's integer exception register */
923 # define LR_sig(context)                        REG_sig(link, context) /* Link register */
924 # define CR_sig(context)                        REG_sig(ccr, context) /* Condition register */
925 /* Float Registers access  */
926 # define FLOAT_sig(reg_num, context)            (((double*)((char*)((context)->uc_mcontext.regs+48*4)))[reg_num])
927 # define FPSCR_sig(context)                     (*(int*)((char*)((context)->uc_mcontext.regs+(48+32*2)*4)))
928 /* Exception Registers access */
929 # define DAR_sig(context)                       REG_sig(dar, context)
930 # define DSISR_sig(context)                     REG_sig(dsisr, context)
931 # define TRAP_sig(context)                      REG_sig(trap, context)
932 #endif /* linux */
933
934 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
935 #include <ucontext.h>
936 # define IAR_sig(context)               ((context)->uc_mcontext.mc_srr0)
937 # define MSR_sig(context)               ((context)->uc_mcontext.mc_srr1)
938 # define CTR_sig(context)               ((context)->uc_mcontext.mc_ctr)
939 # define XER_sig(context)               ((context)->uc_mcontext.mc_xer)
940 # define LR_sig(context)                ((context)->uc_mcontext.mc_lr)
941 # define CR_sig(context)                ((context)->uc_mcontext.mc_cr)
942 /* Exception Registers access */
943 # define DAR_sig(context)               ((context)->uc_mcontext.mc_dar)
944 # define DSISR_sig(context)             ((context)->uc_mcontext.mc_dsisr)
945 # define TRAP_sig(context)              ((context)->uc_mcontext.mc_exc)
946 #endif /* __FreeBSD__|| __FreeBSD_kernel__ */
947
948 #ifdef __APPLE__
949 # include <sys/ucontext.h>
950 typedef struct ucontext SIGCONTEXT;
951 /* All Registers access - only for local access */
952 # define REG_sig(reg_name, context)             ((context)->uc_mcontext->ss.reg_name)
953 # define FLOATREG_sig(reg_name, context)        ((context)->uc_mcontext->fs.reg_name)
954 # define EXCEPREG_sig(reg_name, context)        ((context)->uc_mcontext->es.reg_name)
955 # define VECREG_sig(reg_name, context)          ((context)->uc_mcontext->vs.reg_name)
956 /* Gpr Registers access */
957 # define GPR_sig(reg_num, context)              REG_sig(r##reg_num, context)
958 # define IAR_sig(context)                       REG_sig(srr0, context)  /* Program counter */
959 # define MSR_sig(context)                       REG_sig(srr1, context)  /* Machine State Register (Supervisor) */
960 # define CTR_sig(context)                       REG_sig(ctr, context)
961 # define XER_sig(context)                       REG_sig(xer, context) /* Link register */
962 # define LR_sig(context)                        REG_sig(lr, context)  /* User's integer exception register */
963 # define CR_sig(context)                        REG_sig(cr, context)  /* Condition register */
964 /* Float Registers access */
965 # define FLOAT_sig(reg_num, context)            FLOATREG_sig(fpregs[reg_num], context)
966 # define FPSCR_sig(context)                     ((double)FLOATREG_sig(fpscr, context))
967 /* Exception Registers access */
968 # define DAR_sig(context)                       EXCEPREG_sig(dar, context)     /* Fault registers for coredump */
969 # define DSISR_sig(context)                     EXCEPREG_sig(dsisr, context)
970 # define TRAP_sig(context)                      EXCEPREG_sig(exception, context) /* number of powerpc exception taken */
971 #endif /* __APPLE__ */
972
973 int cpu_signal_handler(int host_signum, void *pinfo,
974                        void *puc)
975 {
976     siginfo_t *info = pinfo;
977 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
978     ucontext_t *uc = puc;
979 #else
980     struct ucontext *uc = puc;
981 #endif
982     unsigned long pc;
983     int is_write;
984
985     pc = IAR_sig(uc);
986     is_write = 0;
987 #if 0
988     /* ppc 4xx case */
989     if (DSISR_sig(uc) & 0x00800000)
990         is_write = 1;
991 #else
992     if (TRAP_sig(uc) != 0x400 && (DSISR_sig(uc) & 0x02000000))
993         is_write = 1;
994 #endif
995     return handle_cpu_signal(pc, (unsigned long)info->si_addr,
996                              is_write, &uc->uc_sigmask, puc);
997 }
998
999 #elif defined(__alpha__)
1000
1001 int cpu_signal_handler(int host_signum, void *pinfo,
1002                            void *puc)
1003 {
1004     siginfo_t *info = pinfo;
1005     struct ucontext *uc = puc;
1006     uint32_t *pc = uc->uc_mcontext.sc_pc;
1007     uint32_t insn = *pc;
1008     int is_write = 0;
1009
1010     /* XXX: need kernel patch to get write flag faster */
1011     switch (insn >> 26) {
1012     case 0x0d: // stw
1013     case 0x0e: // stb
1014     case 0x0f: // stq_u
1015     case 0x24: // stf
1016     case 0x25: // stg
1017     case 0x26: // sts
1018     case 0x27: // stt
1019     case 0x2c: // stl
1020     case 0x2d: // stq
1021     case 0x2e: // stl_c
1022     case 0x2f: // stq_c
1023         is_write = 1;
1024     }
1025
1026     return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1027                              is_write, &uc->uc_sigmask, puc);
1028 }
1029 #elif defined(__sparc__)
1030
1031 int cpu_signal_handler(int host_signum, void *pinfo,
1032                        void *puc)
1033 {
1034     siginfo_t *info = pinfo;
1035     int is_write;
1036     uint32_t insn;
1037 #if !defined(__arch64__) || defined(CONFIG_SOLARIS)
1038     uint32_t *regs = (uint32_t *)(info + 1);
1039     void *sigmask = (regs + 20);
1040     /* XXX: is there a standard glibc define ? */
1041     unsigned long pc = regs[1];
1042 #else
1043 #ifdef __linux__
1044     struct sigcontext *sc = puc;
1045     unsigned long pc = sc->sigc_regs.tpc;
1046     void *sigmask = (void *)sc->sigc_mask;
1047 #elif defined(__OpenBSD__)
1048     struct sigcontext *uc = puc;
1049     unsigned long pc = uc->sc_pc;
1050     void *sigmask = (void *)(long)uc->sc_mask;
1051 #endif
1052 #endif
1053
1054     /* XXX: need kernel patch to get write flag faster */
1055     is_write = 0;
1056     insn = *(uint32_t *)pc;
1057     if ((insn >> 30) == 3) {
1058       switch((insn >> 19) & 0x3f) {
1059       case 0x05: // stb
1060       case 0x15: // stba
1061       case 0x06: // sth
1062       case 0x16: // stha
1063       case 0x04: // st
1064       case 0x14: // sta
1065       case 0x07: // std
1066       case 0x17: // stda
1067       case 0x0e: // stx
1068       case 0x1e: // stxa
1069       case 0x24: // stf
1070       case 0x34: // stfa
1071       case 0x27: // stdf
1072       case 0x37: // stdfa
1073       case 0x26: // stqf
1074       case 0x36: // stqfa
1075       case 0x25: // stfsr
1076       case 0x3c: // casa
1077       case 0x3e: // casxa
1078         is_write = 1;
1079         break;
1080       }
1081     }
1082     return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1083                              is_write, sigmask, NULL);
1084 }
1085
1086 #elif defined(__arm__)
1087
1088 int cpu_signal_handler(int host_signum, void *pinfo,
1089                        void *puc)
1090 {
1091     siginfo_t *info = pinfo;
1092     struct ucontext *uc = puc;
1093     unsigned long pc;
1094     int is_write;
1095
1096 #if (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ <= 3))
1097     pc = uc->uc_mcontext.gregs[R15];
1098 #else
1099     pc = uc->uc_mcontext.arm_pc;
1100 #endif
1101     /* XXX: compute is_write */
1102     is_write = 0;
1103     return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1104                              is_write,
1105                              &uc->uc_sigmask, puc);
1106 }
1107
1108 #elif defined(__mc68000)
1109
1110 int cpu_signal_handler(int host_signum, void *pinfo,
1111                        void *puc)
1112 {
1113     siginfo_t *info = pinfo;
1114     struct ucontext *uc = puc;
1115     unsigned long pc;
1116     int is_write;
1117
1118     pc = uc->uc_mcontext.gregs[16];
1119     /* XXX: compute is_write */
1120     is_write = 0;
1121     return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1122                              is_write,
1123                              &uc->uc_sigmask, puc);
1124 }
1125
1126 #elif defined(__ia64)
1127
1128 #ifndef __ISR_VALID
1129   /* This ought to be in <bits/siginfo.h>... */
1130 # define __ISR_VALID    1
1131 #endif
1132
1133 int cpu_signal_handler(int host_signum, void *pinfo, void *puc)
1134 {
1135     siginfo_t *info = pinfo;
1136     struct ucontext *uc = puc;
1137     unsigned long ip;
1138     int is_write = 0;
1139
1140     ip = uc->uc_mcontext.sc_ip;
1141     switch (host_signum) {
1142       case SIGILL:
1143       case SIGFPE:
1144       case SIGSEGV:
1145       case SIGBUS:
1146       case SIGTRAP:
1147           if (info->si_code && (info->si_segvflags & __ISR_VALID))
1148               /* ISR.W (write-access) is bit 33:  */
1149               is_write = (info->si_isr >> 33) & 1;
1150           break;
1151
1152       default:
1153           break;
1154     }
1155     return handle_cpu_signal(ip, (unsigned long)info->si_addr,
1156                              is_write,
1157                              (sigset_t *)&uc->uc_sigmask, puc);
1158 }
1159
1160 #elif defined(__s390__)
1161
1162 int cpu_signal_handler(int host_signum, void *pinfo,
1163                        void *puc)
1164 {
1165     siginfo_t *info = pinfo;
1166     struct ucontext *uc = puc;
1167     unsigned long pc;
1168     int is_write;
1169
1170     pc = uc->uc_mcontext.psw.addr;
1171     /* XXX: compute is_write */
1172     is_write = 0;
1173     return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1174                              is_write, &uc->uc_sigmask, puc);
1175 }
1176
1177 #elif defined(__mips__)
1178
1179 int cpu_signal_handler(int host_signum, void *pinfo,
1180                        void *puc)
1181 {
1182     siginfo_t *info = pinfo;
1183     struct ucontext *uc = puc;
1184     greg_t pc = uc->uc_mcontext.pc;
1185     int is_write;
1186
1187     /* XXX: compute is_write */
1188     is_write = 0;
1189     return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1190                              is_write, &uc->uc_sigmask, puc);
1191 }
1192
1193 #elif defined(__hppa__)
1194
1195 int cpu_signal_handler(int host_signum, void *pinfo,
1196                        void *puc)
1197 {
1198     struct siginfo *info = pinfo;
1199     struct ucontext *uc = puc;
1200     unsigned long pc = uc->uc_mcontext.sc_iaoq[0];
1201     uint32_t insn = *(uint32_t *)pc;
1202     int is_write = 0;
1203
1204     /* XXX: need kernel patch to get write flag faster.  */
1205     switch (insn >> 26) {
1206     case 0x1a: /* STW */
1207     case 0x19: /* STH */
1208     case 0x18: /* STB */
1209     case 0x1b: /* STWM */
1210         is_write = 1;
1211         break;
1212
1213     case 0x09: /* CSTWX, FSTWX, FSTWS */
1214     case 0x0b: /* CSTDX, FSTDX, FSTDS */
1215         /* Distinguish from coprocessor load ... */
1216         is_write = (insn >> 9) & 1;
1217         break;
1218
1219     case 0x03:
1220         switch ((insn >> 6) & 15) {
1221         case 0xa: /* STWS */
1222         case 0x9: /* STHS */
1223         case 0x8: /* STBS */
1224         case 0xe: /* STWAS */
1225         case 0xc: /* STBYS */
1226             is_write = 1;
1227         }
1228         break;
1229     }
1230
1231     return handle_cpu_signal(pc, (unsigned long)info->si_addr, 
1232                              is_write, &uc->uc_sigmask, puc);
1233 }
1234
1235 #else
1236
1237 #error host CPU specific signal handler needed
1238
1239 #endif
1240
1241 #endif /* !defined(CONFIG_SOFTMMU) */