]> rtime.felk.cvut.cz Git - lisovros/qemu_apohw.git/blob - cpu-exec.c
Enable -d cpu logging by default.
[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 #if defined(DEBUG_DISAS) || defined(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_M68K)
557                     cpu_m68k_flush_flags(env, env->cc_op);
558                     env->cc_op = CC_OP_FLAGS;
559                     env->sr = (env->sr & 0xffe0)
560                               | env->cc_dest | (env->cc_x << 4);
561                     log_cpu_state(env, 0);
562 #else
563                     log_cpu_state(env, 0);
564 #endif
565                 }
566 #endif /* DEBUG_DISAS || CONFIG_DEBUG_EXEC */
567                 spin_lock(&tb_lock);
568                 tb = tb_find_fast();
569                 /* Note: we do it here to avoid a gcc bug on Mac OS X when
570                    doing it in tb_find_slow */
571                 if (tb_invalidated_flag) {
572                     /* as some TB could have been invalidated because
573                        of memory exceptions while generating the code, we
574                        must recompute the hash index here */
575                     next_tb = 0;
576                     tb_invalidated_flag = 0;
577                 }
578 #ifdef CONFIG_DEBUG_EXEC
579                 qemu_log_mask(CPU_LOG_EXEC, "Trace 0x%08lx [" TARGET_FMT_lx "] %s\n",
580                              (long)tb->tc_ptr, tb->pc,
581                              lookup_symbol(tb->pc));
582 #endif
583                 /* see if we can patch the calling TB. When the TB
584                    spans two pages, we cannot safely do a direct
585                    jump. */
586                 if (next_tb != 0 && tb->page_addr[1] == -1) {
587                     tb_add_jump((TranslationBlock *)(next_tb & ~3), next_tb & 3, tb);
588                 }
589                 spin_unlock(&tb_lock);
590
591                 /* cpu_interrupt might be called while translating the
592                    TB, but before it is linked into a potentially
593                    infinite loop and becomes env->current_tb. Avoid
594                    starting execution if there is a pending interrupt. */
595                 if (!unlikely (env->exit_request)) {
596                     env->current_tb = tb;
597                     tc_ptr = tb->tc_ptr;
598                 /* execute the generated code */
599 #if defined(__sparc__) && !defined(CONFIG_SOLARIS)
600 #undef env
601                     env = cpu_single_env;
602 #define env cpu_single_env
603 #endif
604                     next_tb = tcg_qemu_tb_exec(tc_ptr);
605                     env->current_tb = NULL;
606                     if ((next_tb & 3) == 2) {
607                         /* Instruction counter expired.  */
608                         int insns_left;
609                         tb = (TranslationBlock *)(long)(next_tb & ~3);
610                         /* Restore PC.  */
611                         cpu_pc_from_tb(env, tb);
612                         insns_left = env->icount_decr.u32;
613                         if (env->icount_extra && insns_left >= 0) {
614                             /* Refill decrementer and continue execution.  */
615                             env->icount_extra += insns_left;
616                             if (env->icount_extra > 0xffff) {
617                                 insns_left = 0xffff;
618                             } else {
619                                 insns_left = env->icount_extra;
620                             }
621                             env->icount_extra -= insns_left;
622                             env->icount_decr.u16.low = insns_left;
623                         } else {
624                             if (insns_left > 0) {
625                                 /* Execute remaining instructions.  */
626                                 cpu_exec_nocache(insns_left, tb);
627                             }
628                             env->exception_index = EXCP_INTERRUPT;
629                             next_tb = 0;
630                             cpu_loop_exit();
631                         }
632                     }
633                 }
634                 /* reset soft MMU for next block (it can currently
635                    only be set by a memory fault) */
636             } /* for(;;) */
637         }
638     } /* for(;;) */
639
640
641 #if defined(TARGET_I386)
642     /* restore flags in standard format */
643     env->eflags = env->eflags | helper_cc_compute_all(CC_OP) | (DF & DF_MASK);
644 #elif defined(TARGET_ARM)
645     /* XXX: Save/restore host fpu exception state?.  */
646 #elif defined(TARGET_SPARC)
647 #elif defined(TARGET_PPC)
648 #elif defined(TARGET_M68K)
649     cpu_m68k_flush_flags(env, env->cc_op);
650     env->cc_op = CC_OP_FLAGS;
651     env->sr = (env->sr & 0xffe0)
652               | env->cc_dest | (env->cc_x << 4);
653 #elif defined(TARGET_MICROBLAZE)
654 #elif defined(TARGET_MIPS)
655 #elif defined(TARGET_SH4)
656 #elif defined(TARGET_ALPHA)
657 #elif defined(TARGET_CRIS)
658 #elif defined(TARGET_S390X)
659     /* XXXXX */
660 #else
661 #error unsupported target CPU
662 #endif
663
664     /* restore global registers */
665     asm("");
666     env = (void *) saved_env_reg;
667
668     /* fail safe : never use cpu_single_env outside cpu_exec() */
669     cpu_single_env = NULL;
670     return ret;
671 }
672
673 /* must only be called from the generated code as an exception can be
674    generated */
675 void tb_invalidate_page_range(target_ulong start, target_ulong end)
676 {
677     /* XXX: cannot enable it yet because it yields to MMU exception
678        where NIP != read address on PowerPC */
679 #if 0
680     target_ulong phys_addr;
681     phys_addr = get_phys_addr_code(env, start);
682     tb_invalidate_phys_page_range(phys_addr, phys_addr + end - start, 0);
683 #endif
684 }
685
686 #if defined(TARGET_I386) && defined(CONFIG_USER_ONLY)
687
688 void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector)
689 {
690     CPUX86State *saved_env;
691
692     saved_env = env;
693     env = s;
694     if (!(env->cr[0] & CR0_PE_MASK) || (env->eflags & VM_MASK)) {
695         selector &= 0xffff;
696         cpu_x86_load_seg_cache(env, seg_reg, selector,
697                                (selector << 4), 0xffff, 0);
698     } else {
699         helper_load_seg(seg_reg, selector);
700     }
701     env = saved_env;
702 }
703
704 void cpu_x86_fsave(CPUX86State *s, target_ulong ptr, int data32)
705 {
706     CPUX86State *saved_env;
707
708     saved_env = env;
709     env = s;
710
711     helper_fsave(ptr, data32);
712
713     env = saved_env;
714 }
715
716 void cpu_x86_frstor(CPUX86State *s, target_ulong ptr, int data32)
717 {
718     CPUX86State *saved_env;
719
720     saved_env = env;
721     env = s;
722
723     helper_frstor(ptr, data32);
724
725     env = saved_env;
726 }
727
728 #endif /* TARGET_I386 */
729
730 #if !defined(CONFIG_SOFTMMU)
731
732 #if defined(TARGET_I386)
733 #define EXCEPTION_ACTION raise_exception_err(env->exception_index, env->error_code)
734 #else
735 #define EXCEPTION_ACTION cpu_loop_exit()
736 #endif
737
738 /* 'pc' is the host PC at which the exception was raised. 'address' is
739    the effective address of the memory exception. 'is_write' is 1 if a
740    write caused the exception and otherwise 0'. 'old_set' is the
741    signal set which should be restored */
742 static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
743                                     int is_write, sigset_t *old_set,
744                                     void *puc)
745 {
746     TranslationBlock *tb;
747     int ret;
748
749     if (cpu_single_env)
750         env = cpu_single_env; /* XXX: find a correct solution for multithread */
751 #if defined(DEBUG_SIGNAL)
752     qemu_printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
753                 pc, address, is_write, *(unsigned long *)old_set);
754 #endif
755     /* XXX: locking issue */
756     if (is_write && page_unprotect(h2g(address), pc, puc)) {
757         return 1;
758     }
759
760     /* see if it is an MMU fault */
761     ret = cpu_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
762     if (ret < 0)
763         return 0; /* not an MMU fault */
764     if (ret == 0)
765         return 1; /* the MMU fault was handled without causing real CPU fault */
766     /* now we have a real cpu fault */
767     tb = tb_find_pc(pc);
768     if (tb) {
769         /* the PC is inside the translated code. It means that we have
770            a virtual CPU fault */
771         cpu_restore_state(tb, env, pc, puc);
772     }
773
774     /* we restore the process signal mask as the sigreturn should
775        do it (XXX: use sigsetjmp) */
776     sigprocmask(SIG_SETMASK, old_set, NULL);
777     EXCEPTION_ACTION;
778
779     /* never comes here */
780     return 1;
781 }
782
783 #if defined(__i386__)
784
785 #if defined(__APPLE__)
786 # include <sys/ucontext.h>
787
788 # define EIP_sig(context)  (*((unsigned long*)&(context)->uc_mcontext->ss.eip))
789 # define TRAP_sig(context)    ((context)->uc_mcontext->es.trapno)
790 # define ERROR_sig(context)   ((context)->uc_mcontext->es.err)
791 # define MASK_sig(context)    ((context)->uc_sigmask)
792 #elif defined (__NetBSD__)
793 # include <ucontext.h>
794
795 # define EIP_sig(context)     ((context)->uc_mcontext.__gregs[_REG_EIP])
796 # define TRAP_sig(context)    ((context)->uc_mcontext.__gregs[_REG_TRAPNO])
797 # define ERROR_sig(context)   ((context)->uc_mcontext.__gregs[_REG_ERR])
798 # define MASK_sig(context)    ((context)->uc_sigmask)
799 #elif defined (__FreeBSD__) || defined(__DragonFly__)
800 # include <ucontext.h>
801
802 # define EIP_sig(context)  (*((unsigned long*)&(context)->uc_mcontext.mc_eip))
803 # define TRAP_sig(context)    ((context)->uc_mcontext.mc_trapno)
804 # define ERROR_sig(context)   ((context)->uc_mcontext.mc_err)
805 # define MASK_sig(context)    ((context)->uc_sigmask)
806 #elif defined(__OpenBSD__)
807 # define EIP_sig(context)     ((context)->sc_eip)
808 # define TRAP_sig(context)    ((context)->sc_trapno)
809 # define ERROR_sig(context)   ((context)->sc_err)
810 # define MASK_sig(context)    ((context)->sc_mask)
811 #else
812 # define EIP_sig(context)     ((context)->uc_mcontext.gregs[REG_EIP])
813 # define TRAP_sig(context)    ((context)->uc_mcontext.gregs[REG_TRAPNO])
814 # define ERROR_sig(context)   ((context)->uc_mcontext.gregs[REG_ERR])
815 # define MASK_sig(context)    ((context)->uc_sigmask)
816 #endif
817
818 int cpu_signal_handler(int host_signum, void *pinfo,
819                        void *puc)
820 {
821     siginfo_t *info = pinfo;
822 #if defined(__NetBSD__) || defined (__FreeBSD__) || defined(__DragonFly__)
823     ucontext_t *uc = puc;
824 #elif defined(__OpenBSD__)
825     struct sigcontext *uc = puc;
826 #else
827     struct ucontext *uc = puc;
828 #endif
829     unsigned long pc;
830     int trapno;
831
832 #ifndef REG_EIP
833 /* for glibc 2.1 */
834 #define REG_EIP    EIP
835 #define REG_ERR    ERR
836 #define REG_TRAPNO TRAPNO
837 #endif
838     pc = EIP_sig(uc);
839     trapno = TRAP_sig(uc);
840     return handle_cpu_signal(pc, (unsigned long)info->si_addr,
841                              trapno == 0xe ?
842                              (ERROR_sig(uc) >> 1) & 1 : 0,
843                              &MASK_sig(uc), puc);
844 }
845
846 #elif defined(__x86_64__)
847
848 #ifdef __NetBSD__
849 #define PC_sig(context)       _UC_MACHINE_PC(context)
850 #define TRAP_sig(context)     ((context)->uc_mcontext.__gregs[_REG_TRAPNO])
851 #define ERROR_sig(context)    ((context)->uc_mcontext.__gregs[_REG_ERR])
852 #define MASK_sig(context)     ((context)->uc_sigmask)
853 #elif defined(__OpenBSD__)
854 #define PC_sig(context)       ((context)->sc_rip)
855 #define TRAP_sig(context)     ((context)->sc_trapno)
856 #define ERROR_sig(context)    ((context)->sc_err)
857 #define MASK_sig(context)     ((context)->sc_mask)
858 #elif defined (__FreeBSD__) || defined(__DragonFly__)
859 #include <ucontext.h>
860
861 #define PC_sig(context)  (*((unsigned long*)&(context)->uc_mcontext.mc_rip))
862 #define TRAP_sig(context)     ((context)->uc_mcontext.mc_trapno)
863 #define ERROR_sig(context)    ((context)->uc_mcontext.mc_err)
864 #define MASK_sig(context)     ((context)->uc_sigmask)
865 #else
866 #define PC_sig(context)       ((context)->uc_mcontext.gregs[REG_RIP])
867 #define TRAP_sig(context)     ((context)->uc_mcontext.gregs[REG_TRAPNO])
868 #define ERROR_sig(context)    ((context)->uc_mcontext.gregs[REG_ERR])
869 #define MASK_sig(context)     ((context)->uc_sigmask)
870 #endif
871
872 int cpu_signal_handler(int host_signum, void *pinfo,
873                        void *puc)
874 {
875     siginfo_t *info = pinfo;
876     unsigned long pc;
877 #if defined(__NetBSD__) || defined (__FreeBSD__) || defined(__DragonFly__)
878     ucontext_t *uc = puc;
879 #elif defined(__OpenBSD__)
880     struct sigcontext *uc = puc;
881 #else
882     struct ucontext *uc = puc;
883 #endif
884
885     pc = PC_sig(uc);
886     return handle_cpu_signal(pc, (unsigned long)info->si_addr,
887                              TRAP_sig(uc) == 0xe ?
888                              (ERROR_sig(uc) >> 1) & 1 : 0,
889                              &MASK_sig(uc), puc);
890 }
891
892 #elif defined(_ARCH_PPC)
893
894 /***********************************************************************
895  * signal context platform-specific definitions
896  * From Wine
897  */
898 #ifdef linux
899 /* All Registers access - only for local access */
900 # define REG_sig(reg_name, context)             ((context)->uc_mcontext.regs->reg_name)
901 /* Gpr Registers access  */
902 # define GPR_sig(reg_num, context)              REG_sig(gpr[reg_num], context)
903 # define IAR_sig(context)                       REG_sig(nip, context)   /* Program counter */
904 # define MSR_sig(context)                       REG_sig(msr, context)   /* Machine State Register (Supervisor) */
905 # define CTR_sig(context)                       REG_sig(ctr, context)   /* Count register */
906 # define XER_sig(context)                       REG_sig(xer, context) /* User's integer exception register */
907 # define LR_sig(context)                        REG_sig(link, context) /* Link register */
908 # define CR_sig(context)                        REG_sig(ccr, context) /* Condition register */
909 /* Float Registers access  */
910 # define FLOAT_sig(reg_num, context)            (((double*)((char*)((context)->uc_mcontext.regs+48*4)))[reg_num])
911 # define FPSCR_sig(context)                     (*(int*)((char*)((context)->uc_mcontext.regs+(48+32*2)*4)))
912 /* Exception Registers access */
913 # define DAR_sig(context)                       REG_sig(dar, context)
914 # define DSISR_sig(context)                     REG_sig(dsisr, context)
915 # define TRAP_sig(context)                      REG_sig(trap, context)
916 #endif /* linux */
917
918 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
919 #include <ucontext.h>
920 # define IAR_sig(context)               ((context)->uc_mcontext.mc_srr0)
921 # define MSR_sig(context)               ((context)->uc_mcontext.mc_srr1)
922 # define CTR_sig(context)               ((context)->uc_mcontext.mc_ctr)
923 # define XER_sig(context)               ((context)->uc_mcontext.mc_xer)
924 # define LR_sig(context)                ((context)->uc_mcontext.mc_lr)
925 # define CR_sig(context)                ((context)->uc_mcontext.mc_cr)
926 /* Exception Registers access */
927 # define DAR_sig(context)               ((context)->uc_mcontext.mc_dar)
928 # define DSISR_sig(context)             ((context)->uc_mcontext.mc_dsisr)
929 # define TRAP_sig(context)              ((context)->uc_mcontext.mc_exc)
930 #endif /* __FreeBSD__|| __FreeBSD_kernel__ */
931
932 #ifdef __APPLE__
933 # include <sys/ucontext.h>
934 typedef struct ucontext SIGCONTEXT;
935 /* All Registers access - only for local access */
936 # define REG_sig(reg_name, context)             ((context)->uc_mcontext->ss.reg_name)
937 # define FLOATREG_sig(reg_name, context)        ((context)->uc_mcontext->fs.reg_name)
938 # define EXCEPREG_sig(reg_name, context)        ((context)->uc_mcontext->es.reg_name)
939 # define VECREG_sig(reg_name, context)          ((context)->uc_mcontext->vs.reg_name)
940 /* Gpr Registers access */
941 # define GPR_sig(reg_num, context)              REG_sig(r##reg_num, context)
942 # define IAR_sig(context)                       REG_sig(srr0, context)  /* Program counter */
943 # define MSR_sig(context)                       REG_sig(srr1, context)  /* Machine State Register (Supervisor) */
944 # define CTR_sig(context)                       REG_sig(ctr, context)
945 # define XER_sig(context)                       REG_sig(xer, context) /* Link register */
946 # define LR_sig(context)                        REG_sig(lr, context)  /* User's integer exception register */
947 # define CR_sig(context)                        REG_sig(cr, context)  /* Condition register */
948 /* Float Registers access */
949 # define FLOAT_sig(reg_num, context)            FLOATREG_sig(fpregs[reg_num], context)
950 # define FPSCR_sig(context)                     ((double)FLOATREG_sig(fpscr, context))
951 /* Exception Registers access */
952 # define DAR_sig(context)                       EXCEPREG_sig(dar, context)     /* Fault registers for coredump */
953 # define DSISR_sig(context)                     EXCEPREG_sig(dsisr, context)
954 # define TRAP_sig(context)                      EXCEPREG_sig(exception, context) /* number of powerpc exception taken */
955 #endif /* __APPLE__ */
956
957 int cpu_signal_handler(int host_signum, void *pinfo,
958                        void *puc)
959 {
960     siginfo_t *info = pinfo;
961 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
962     ucontext_t *uc = puc;
963 #else
964     struct ucontext *uc = puc;
965 #endif
966     unsigned long pc;
967     int is_write;
968
969     pc = IAR_sig(uc);
970     is_write = 0;
971 #if 0
972     /* ppc 4xx case */
973     if (DSISR_sig(uc) & 0x00800000)
974         is_write = 1;
975 #else
976     if (TRAP_sig(uc) != 0x400 && (DSISR_sig(uc) & 0x02000000))
977         is_write = 1;
978 #endif
979     return handle_cpu_signal(pc, (unsigned long)info->si_addr,
980                              is_write, &uc->uc_sigmask, puc);
981 }
982
983 #elif defined(__alpha__)
984
985 int cpu_signal_handler(int host_signum, void *pinfo,
986                            void *puc)
987 {
988     siginfo_t *info = pinfo;
989     struct ucontext *uc = puc;
990     uint32_t *pc = uc->uc_mcontext.sc_pc;
991     uint32_t insn = *pc;
992     int is_write = 0;
993
994     /* XXX: need kernel patch to get write flag faster */
995     switch (insn >> 26) {
996     case 0x0d: // stw
997     case 0x0e: // stb
998     case 0x0f: // stq_u
999     case 0x24: // stf
1000     case 0x25: // stg
1001     case 0x26: // sts
1002     case 0x27: // stt
1003     case 0x2c: // stl
1004     case 0x2d: // stq
1005     case 0x2e: // stl_c
1006     case 0x2f: // stq_c
1007         is_write = 1;
1008     }
1009
1010     return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1011                              is_write, &uc->uc_sigmask, puc);
1012 }
1013 #elif defined(__sparc__)
1014
1015 int cpu_signal_handler(int host_signum, void *pinfo,
1016                        void *puc)
1017 {
1018     siginfo_t *info = pinfo;
1019     int is_write;
1020     uint32_t insn;
1021 #if !defined(__arch64__) || defined(CONFIG_SOLARIS)
1022     uint32_t *regs = (uint32_t *)(info + 1);
1023     void *sigmask = (regs + 20);
1024     /* XXX: is there a standard glibc define ? */
1025     unsigned long pc = regs[1];
1026 #else
1027 #ifdef __linux__
1028     struct sigcontext *sc = puc;
1029     unsigned long pc = sc->sigc_regs.tpc;
1030     void *sigmask = (void *)sc->sigc_mask;
1031 #elif defined(__OpenBSD__)
1032     struct sigcontext *uc = puc;
1033     unsigned long pc = uc->sc_pc;
1034     void *sigmask = (void *)(long)uc->sc_mask;
1035 #endif
1036 #endif
1037
1038     /* XXX: need kernel patch to get write flag faster */
1039     is_write = 0;
1040     insn = *(uint32_t *)pc;
1041     if ((insn >> 30) == 3) {
1042       switch((insn >> 19) & 0x3f) {
1043       case 0x05: // stb
1044       case 0x15: // stba
1045       case 0x06: // sth
1046       case 0x16: // stha
1047       case 0x04: // st
1048       case 0x14: // sta
1049       case 0x07: // std
1050       case 0x17: // stda
1051       case 0x0e: // stx
1052       case 0x1e: // stxa
1053       case 0x24: // stf
1054       case 0x34: // stfa
1055       case 0x27: // stdf
1056       case 0x37: // stdfa
1057       case 0x26: // stqf
1058       case 0x36: // stqfa
1059       case 0x25: // stfsr
1060       case 0x3c: // casa
1061       case 0x3e: // casxa
1062         is_write = 1;
1063         break;
1064       }
1065     }
1066     return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1067                              is_write, sigmask, NULL);
1068 }
1069
1070 #elif defined(__arm__)
1071
1072 int cpu_signal_handler(int host_signum, void *pinfo,
1073                        void *puc)
1074 {
1075     siginfo_t *info = pinfo;
1076     struct ucontext *uc = puc;
1077     unsigned long pc;
1078     int is_write;
1079
1080 #if (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ <= 3))
1081     pc = uc->uc_mcontext.gregs[R15];
1082 #else
1083     pc = uc->uc_mcontext.arm_pc;
1084 #endif
1085     /* XXX: compute is_write */
1086     is_write = 0;
1087     return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1088                              is_write,
1089                              &uc->uc_sigmask, puc);
1090 }
1091
1092 #elif defined(__mc68000)
1093
1094 int cpu_signal_handler(int host_signum, void *pinfo,
1095                        void *puc)
1096 {
1097     siginfo_t *info = pinfo;
1098     struct ucontext *uc = puc;
1099     unsigned long pc;
1100     int is_write;
1101
1102     pc = uc->uc_mcontext.gregs[16];
1103     /* XXX: compute is_write */
1104     is_write = 0;
1105     return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1106                              is_write,
1107                              &uc->uc_sigmask, puc);
1108 }
1109
1110 #elif defined(__ia64)
1111
1112 #ifndef __ISR_VALID
1113   /* This ought to be in <bits/siginfo.h>... */
1114 # define __ISR_VALID    1
1115 #endif
1116
1117 int cpu_signal_handler(int host_signum, void *pinfo, void *puc)
1118 {
1119     siginfo_t *info = pinfo;
1120     struct ucontext *uc = puc;
1121     unsigned long ip;
1122     int is_write = 0;
1123
1124     ip = uc->uc_mcontext.sc_ip;
1125     switch (host_signum) {
1126       case SIGILL:
1127       case SIGFPE:
1128       case SIGSEGV:
1129       case SIGBUS:
1130       case SIGTRAP:
1131           if (info->si_code && (info->si_segvflags & __ISR_VALID))
1132               /* ISR.W (write-access) is bit 33:  */
1133               is_write = (info->si_isr >> 33) & 1;
1134           break;
1135
1136       default:
1137           break;
1138     }
1139     return handle_cpu_signal(ip, (unsigned long)info->si_addr,
1140                              is_write,
1141                              (sigset_t *)&uc->uc_sigmask, puc);
1142 }
1143
1144 #elif defined(__s390__)
1145
1146 int cpu_signal_handler(int host_signum, void *pinfo,
1147                        void *puc)
1148 {
1149     siginfo_t *info = pinfo;
1150     struct ucontext *uc = puc;
1151     unsigned long pc;
1152     int is_write;
1153
1154     pc = uc->uc_mcontext.psw.addr;
1155     /* XXX: compute is_write */
1156     is_write = 0;
1157     return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1158                              is_write, &uc->uc_sigmask, puc);
1159 }
1160
1161 #elif defined(__mips__)
1162
1163 int cpu_signal_handler(int host_signum, void *pinfo,
1164                        void *puc)
1165 {
1166     siginfo_t *info = pinfo;
1167     struct ucontext *uc = puc;
1168     greg_t pc = uc->uc_mcontext.pc;
1169     int is_write;
1170
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(__hppa__)
1178
1179 int cpu_signal_handler(int host_signum, void *pinfo,
1180                        void *puc)
1181 {
1182     struct siginfo *info = pinfo;
1183     struct ucontext *uc = puc;
1184     unsigned long pc = uc->uc_mcontext.sc_iaoq[0];
1185     uint32_t insn = *(uint32_t *)pc;
1186     int is_write = 0;
1187
1188     /* XXX: need kernel patch to get write flag faster.  */
1189     switch (insn >> 26) {
1190     case 0x1a: /* STW */
1191     case 0x19: /* STH */
1192     case 0x18: /* STB */
1193     case 0x1b: /* STWM */
1194         is_write = 1;
1195         break;
1196
1197     case 0x09: /* CSTWX, FSTWX, FSTWS */
1198     case 0x0b: /* CSTDX, FSTDX, FSTDS */
1199         /* Distinguish from coprocessor load ... */
1200         is_write = (insn >> 9) & 1;
1201         break;
1202
1203     case 0x03:
1204         switch ((insn >> 6) & 15) {
1205         case 0xa: /* STWS */
1206         case 0x9: /* STHS */
1207         case 0x8: /* STBS */
1208         case 0xe: /* STWAS */
1209         case 0xc: /* STBYS */
1210             is_write = 1;
1211         }
1212         break;
1213     }
1214
1215     return handle_cpu_signal(pc, (unsigned long)info->si_addr, 
1216                              is_write, &uc->uc_sigmask, puc);
1217 }
1218
1219 #else
1220
1221 #error host CPU specific signal handler needed
1222
1223 #endif
1224
1225 #endif /* !defined(CONFIG_SOFTMMU) */