tcg: kill two warnings
[qemu/mini2440/sniper_sniper_test.git] / cpu-exec.c
blobed1545b5e15064d4f7124c28b75644d5ac20f11b
1 /*
2 * i386 emulator main execution loop
4 * Copyright (c) 2003-2005 Fabrice Bellard
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.
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.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 #include "config.h"
21 #define CPU_NO_GLOBAL_REGS
22 #include "exec.h"
23 #include "disas.h"
24 #include "tcg.h"
25 #include "kvm.h"
27 #if !defined(CONFIG_SOFTMMU)
28 #undef EAX
29 #undef ECX
30 #undef EDX
31 #undef EBX
32 #undef ESP
33 #undef EBP
34 #undef ESI
35 #undef EDI
36 #undef EIP
37 #include <signal.h>
38 #ifdef __linux__
39 #include <sys/ucontext.h>
40 #endif
41 #endif
43 #if defined(__sparc__) && !defined(HOST_SOLARIS)
44 // Work around ugly bugs in glibc that mangle global register contents
45 #undef env
46 #define env cpu_single_env
47 #endif
49 int tb_invalidated_flag;
51 //#define DEBUG_EXEC
52 //#define DEBUG_SIGNAL
54 void cpu_loop_exit(void)
56 /* NOTE: the register at this point must be saved by hand because
57 longjmp restore them */
58 regs_to_env();
59 longjmp(env->jmp_env, 1);
62 /* exit the current TB from a signal handler. The host registers are
63 restored in a state compatible with the CPU emulator
65 void cpu_resume_from_signal(CPUState *env1, void *puc)
67 #if !defined(CONFIG_SOFTMMU)
68 #ifdef __linux__
69 struct ucontext *uc = puc;
70 #elif defined(__OpenBSD__)
71 struct sigcontext *uc = puc;
72 #endif
73 #endif
75 env = env1;
77 /* XXX: restore cpu registers saved in host registers */
79 #if !defined(CONFIG_SOFTMMU)
80 if (puc) {
81 /* XXX: use siglongjmp ? */
82 #ifdef __linux__
83 sigprocmask(SIG_SETMASK, &uc->uc_sigmask, NULL);
84 #elif defined(__OpenBSD__)
85 sigprocmask(SIG_SETMASK, &uc->sc_mask, NULL);
86 #endif
88 #endif
89 longjmp(env->jmp_env, 1);
92 /* Execute the code without caching the generated code. An interpreter
93 could be used if available. */
94 static void cpu_exec_nocache(int max_cycles, TranslationBlock *orig_tb)
96 unsigned long next_tb;
97 TranslationBlock *tb;
99 /* Should never happen.
100 We only end up here when an existing TB is too long. */
101 if (max_cycles > CF_COUNT_MASK)
102 max_cycles = CF_COUNT_MASK;
104 tb = tb_gen_code(env, orig_tb->pc, orig_tb->cs_base, orig_tb->flags,
105 max_cycles);
106 env->current_tb = tb;
107 /* execute the generated code */
108 next_tb = tcg_qemu_tb_exec(tb->tc_ptr);
110 if ((next_tb & 3) == 2) {
111 /* Restore PC. This may happen if async event occurs before
112 the TB starts executing. */
113 cpu_pc_from_tb(env, tb);
115 tb_phys_invalidate(tb, -1);
116 tb_free(tb);
119 static TranslationBlock *tb_find_slow(target_ulong pc,
120 target_ulong cs_base,
121 uint64_t flags)
123 TranslationBlock *tb, **ptb1;
124 unsigned int h;
125 target_ulong phys_pc, phys_page1, phys_page2, virt_page2;
127 tb_invalidated_flag = 0;
129 regs_to_env(); /* XXX: do it just before cpu_gen_code() */
131 /* find translated block using physical mappings */
132 phys_pc = get_phys_addr_code(env, pc);
133 phys_page1 = phys_pc & TARGET_PAGE_MASK;
134 phys_page2 = -1;
135 h = tb_phys_hash_func(phys_pc);
136 ptb1 = &tb_phys_hash[h];
137 for(;;) {
138 tb = *ptb1;
139 if (!tb)
140 goto not_found;
141 if (tb->pc == pc &&
142 tb->page_addr[0] == phys_page1 &&
143 tb->cs_base == cs_base &&
144 tb->flags == flags) {
145 /* check next page if needed */
146 if (tb->page_addr[1] != -1) {
147 virt_page2 = (pc & TARGET_PAGE_MASK) +
148 TARGET_PAGE_SIZE;
149 phys_page2 = get_phys_addr_code(env, virt_page2);
150 if (tb->page_addr[1] == phys_page2)
151 goto found;
152 } else {
153 goto found;
156 ptb1 = &tb->phys_hash_next;
158 not_found:
159 /* if no translated code available, then translate it now */
160 tb = tb_gen_code(env, pc, cs_base, flags, 0);
162 found:
163 /* we add the TB in the virtual pc hash table */
164 env->tb_jmp_cache[tb_jmp_cache_hash_func(pc)] = tb;
165 return tb;
168 static inline TranslationBlock *tb_find_fast(void)
170 TranslationBlock *tb;
171 target_ulong cs_base, pc;
172 int flags;
174 /* we record a subset of the CPU state. It will
175 always be the same before a given translated block
176 is executed. */
177 cpu_get_tb_cpu_state(env, &pc, &cs_base, &flags);
178 tb = env->tb_jmp_cache[tb_jmp_cache_hash_func(pc)];
179 if (unlikely(!tb || tb->pc != pc || tb->cs_base != cs_base ||
180 tb->flags != flags)) {
181 tb = tb_find_slow(pc, cs_base, flags);
183 return tb;
186 static CPUDebugExcpHandler *debug_excp_handler;
188 CPUDebugExcpHandler *cpu_set_debug_excp_handler(CPUDebugExcpHandler *handler)
190 CPUDebugExcpHandler *old_handler = debug_excp_handler;
192 debug_excp_handler = handler;
193 return old_handler;
196 static void cpu_handle_debug_exception(CPUState *env)
198 CPUWatchpoint *wp;
200 if (!env->watchpoint_hit)
201 TAILQ_FOREACH(wp, &env->watchpoints, entry)
202 wp->flags &= ~BP_WATCHPOINT_HIT;
204 if (debug_excp_handler)
205 debug_excp_handler(env);
208 /* main execution loop */
210 int cpu_exec(CPUState *env1)
212 #define DECLARE_HOST_REGS 1
213 #include "hostregs_helper.h"
214 int ret, interrupt_request;
215 TranslationBlock *tb;
216 uint8_t *tc_ptr;
217 unsigned long next_tb;
219 if (cpu_halted(env1) == EXCP_HALTED)
220 return EXCP_HALTED;
222 cpu_single_env = env1;
224 /* first we save global registers */
225 #define SAVE_HOST_REGS 1
226 #include "hostregs_helper.h"
227 env = env1;
229 env_to_regs();
230 #if defined(TARGET_I386)
231 /* put eflags in CPU temporary format */
232 CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
233 DF = 1 - (2 * ((env->eflags >> 10) & 1));
234 CC_OP = CC_OP_EFLAGS;
235 env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
236 #elif defined(TARGET_SPARC)
237 #elif defined(TARGET_M68K)
238 env->cc_op = CC_OP_FLAGS;
239 env->cc_dest = env->sr & 0xf;
240 env->cc_x = (env->sr >> 4) & 1;
241 #elif defined(TARGET_ALPHA)
242 #elif defined(TARGET_ARM)
243 #elif defined(TARGET_PPC)
244 #elif defined(TARGET_MIPS)
245 #elif defined(TARGET_SH4)
246 #elif defined(TARGET_CRIS)
247 /* XXXXX */
248 #else
249 #error unsupported target CPU
250 #endif
251 env->exception_index = -1;
253 /* prepare setjmp context for exception handling */
254 for(;;) {
255 if (setjmp(env->jmp_env) == 0) {
256 env->current_tb = NULL;
257 /* if an exception is pending, we execute it here */
258 if (env->exception_index >= 0) {
259 if (env->exception_index >= EXCP_INTERRUPT) {
260 /* exit request from the cpu execution loop */
261 ret = env->exception_index;
262 if (ret == EXCP_DEBUG)
263 cpu_handle_debug_exception(env);
264 break;
265 } else if (env->user_mode_only) {
266 /* if user mode only, we simulate a fake exception
267 which will be handled outside the cpu execution
268 loop */
269 #if defined(TARGET_I386)
270 do_interrupt_user(env->exception_index,
271 env->exception_is_int,
272 env->error_code,
273 env->exception_next_eip);
274 /* successfully delivered */
275 env->old_exception = -1;
276 #endif
277 ret = env->exception_index;
278 break;
279 } else {
280 #if defined(TARGET_I386)
281 /* simulate a real cpu exception. On i386, it can
282 trigger new exceptions, but we do not handle
283 double or triple faults yet. */
284 do_interrupt(env->exception_index,
285 env->exception_is_int,
286 env->error_code,
287 env->exception_next_eip, 0);
288 /* successfully delivered */
289 env->old_exception = -1;
290 #elif defined(TARGET_PPC)
291 do_interrupt(env);
292 #elif defined(TARGET_MIPS)
293 do_interrupt(env);
294 #elif defined(TARGET_SPARC)
295 do_interrupt(env);
296 #elif defined(TARGET_ARM)
297 do_interrupt(env);
298 #elif defined(TARGET_SH4)
299 do_interrupt(env);
300 #elif defined(TARGET_ALPHA)
301 do_interrupt(env);
302 #elif defined(TARGET_CRIS)
303 do_interrupt(env);
304 #elif defined(TARGET_M68K)
305 do_interrupt(0);
306 #endif
308 env->exception_index = -1;
310 #ifdef USE_KQEMU
311 if (kqemu_is_ok(env) && env->interrupt_request == 0) {
312 int ret;
313 env->eflags = env->eflags | helper_cc_compute_all(CC_OP) | (DF & DF_MASK);
314 ret = kqemu_cpu_exec(env);
315 /* put eflags in CPU temporary format */
316 CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
317 DF = 1 - (2 * ((env->eflags >> 10) & 1));
318 CC_OP = CC_OP_EFLAGS;
319 env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
320 if (ret == 1) {
321 /* exception */
322 longjmp(env->jmp_env, 1);
323 } else if (ret == 2) {
324 /* softmmu execution needed */
325 } else {
326 if (env->interrupt_request != 0) {
327 /* hardware interrupt will be executed just after */
328 } else {
329 /* otherwise, we restart */
330 longjmp(env->jmp_env, 1);
334 #endif
336 if (kvm_enabled()) {
337 kvm_cpu_exec(env);
338 longjmp(env->jmp_env, 1);
341 next_tb = 0; /* force lookup of first TB */
342 for(;;) {
343 interrupt_request = env->interrupt_request;
344 if (unlikely(interrupt_request)) {
345 if (unlikely(env->singlestep_enabled & SSTEP_NOIRQ)) {
346 /* Mask out external interrupts for this step. */
347 interrupt_request &= ~(CPU_INTERRUPT_HARD |
348 CPU_INTERRUPT_FIQ |
349 CPU_INTERRUPT_SMI |
350 CPU_INTERRUPT_NMI);
352 if (interrupt_request & CPU_INTERRUPT_DEBUG) {
353 env->interrupt_request &= ~CPU_INTERRUPT_DEBUG;
354 env->exception_index = EXCP_DEBUG;
355 cpu_loop_exit();
357 #if defined(TARGET_ARM) || defined(TARGET_SPARC) || defined(TARGET_MIPS) || \
358 defined(TARGET_PPC) || defined(TARGET_ALPHA) || defined(TARGET_CRIS)
359 if (interrupt_request & CPU_INTERRUPT_HALT) {
360 env->interrupt_request &= ~CPU_INTERRUPT_HALT;
361 env->halted = 1;
362 env->exception_index = EXCP_HLT;
363 cpu_loop_exit();
365 #endif
366 #if defined(TARGET_I386)
367 if (env->hflags2 & HF2_GIF_MASK) {
368 if ((interrupt_request & CPU_INTERRUPT_SMI) &&
369 !(env->hflags & HF_SMM_MASK)) {
370 svm_check_intercept(SVM_EXIT_SMI);
371 env->interrupt_request &= ~CPU_INTERRUPT_SMI;
372 do_smm_enter();
373 next_tb = 0;
374 } else if ((interrupt_request & CPU_INTERRUPT_NMI) &&
375 !(env->hflags2 & HF2_NMI_MASK)) {
376 env->interrupt_request &= ~CPU_INTERRUPT_NMI;
377 env->hflags2 |= HF2_NMI_MASK;
378 do_interrupt(EXCP02_NMI, 0, 0, 0, 1);
379 next_tb = 0;
380 } else if ((interrupt_request & CPU_INTERRUPT_HARD) &&
381 (((env->hflags2 & HF2_VINTR_MASK) &&
382 (env->hflags2 & HF2_HIF_MASK)) ||
383 (!(env->hflags2 & HF2_VINTR_MASK) &&
384 (env->eflags & IF_MASK &&
385 !(env->hflags & HF_INHIBIT_IRQ_MASK))))) {
386 int intno;
387 svm_check_intercept(SVM_EXIT_INTR);
388 env->interrupt_request &= ~(CPU_INTERRUPT_HARD | CPU_INTERRUPT_VIRQ);
389 intno = cpu_get_pic_interrupt(env);
390 if (loglevel & CPU_LOG_TB_IN_ASM) {
391 fprintf(logfile, "Servicing hardware INT=0x%02x\n", intno);
393 do_interrupt(intno, 0, 0, 0, 1);
394 /* ensure that no TB jump will be modified as
395 the program flow was changed */
396 next_tb = 0;
397 #if !defined(CONFIG_USER_ONLY)
398 } else if ((interrupt_request & CPU_INTERRUPT_VIRQ) &&
399 (env->eflags & IF_MASK) &&
400 !(env->hflags & HF_INHIBIT_IRQ_MASK)) {
401 int intno;
402 /* FIXME: this should respect TPR */
403 svm_check_intercept(SVM_EXIT_VINTR);
404 intno = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_vector));
405 if (loglevel & CPU_LOG_TB_IN_ASM)
406 fprintf(logfile, "Servicing virtual hardware INT=0x%02x\n", intno);
407 do_interrupt(intno, 0, 0, 0, 1);
408 env->interrupt_request &= ~CPU_INTERRUPT_VIRQ;
409 next_tb = 0;
410 #endif
413 #elif defined(TARGET_PPC)
414 #if 0
415 if ((interrupt_request & CPU_INTERRUPT_RESET)) {
416 cpu_ppc_reset(env);
418 #endif
419 if (interrupt_request & CPU_INTERRUPT_HARD) {
420 ppc_hw_interrupt(env);
421 if (env->pending_interrupts == 0)
422 env->interrupt_request &= ~CPU_INTERRUPT_HARD;
423 next_tb = 0;
425 #elif defined(TARGET_MIPS)
426 if ((interrupt_request & CPU_INTERRUPT_HARD) &&
427 (env->CP0_Status & env->CP0_Cause & CP0Ca_IP_mask) &&
428 (env->CP0_Status & (1 << CP0St_IE)) &&
429 !(env->CP0_Status & (1 << CP0St_EXL)) &&
430 !(env->CP0_Status & (1 << CP0St_ERL)) &&
431 !(env->hflags & MIPS_HFLAG_DM)) {
432 /* Raise it */
433 env->exception_index = EXCP_EXT_INTERRUPT;
434 env->error_code = 0;
435 do_interrupt(env);
436 next_tb = 0;
438 #elif defined(TARGET_SPARC)
439 if ((interrupt_request & CPU_INTERRUPT_HARD) &&
440 (env->psret != 0)) {
441 int pil = env->interrupt_index & 15;
442 int type = env->interrupt_index & 0xf0;
444 if (((type == TT_EXTINT) &&
445 (pil == 15 || pil > env->psrpil)) ||
446 type != TT_EXTINT) {
447 env->interrupt_request &= ~CPU_INTERRUPT_HARD;
448 env->exception_index = env->interrupt_index;
449 do_interrupt(env);
450 env->interrupt_index = 0;
451 #if !defined(TARGET_SPARC64) && !defined(CONFIG_USER_ONLY)
452 cpu_check_irqs(env);
453 #endif
454 next_tb = 0;
456 } else if (interrupt_request & CPU_INTERRUPT_TIMER) {
457 //do_interrupt(0, 0, 0, 0, 0);
458 env->interrupt_request &= ~CPU_INTERRUPT_TIMER;
460 #elif defined(TARGET_ARM)
461 if (interrupt_request & CPU_INTERRUPT_FIQ
462 && !(env->uncached_cpsr & CPSR_F)) {
463 env->exception_index = EXCP_FIQ;
464 do_interrupt(env);
465 next_tb = 0;
467 /* ARMv7-M interrupt return works by loading a magic value
468 into the PC. On real hardware the load causes the
469 return to occur. The qemu implementation performs the
470 jump normally, then does the exception return when the
471 CPU tries to execute code at the magic address.
472 This will cause the magic PC value to be pushed to
473 the stack if an interrupt occured at the wrong time.
474 We avoid this by disabling interrupts when
475 pc contains a magic address. */
476 if (interrupt_request & CPU_INTERRUPT_HARD
477 && ((IS_M(env) && env->regs[15] < 0xfffffff0)
478 || !(env->uncached_cpsr & CPSR_I))) {
479 env->exception_index = EXCP_IRQ;
480 do_interrupt(env);
481 next_tb = 0;
483 #elif defined(TARGET_SH4)
484 if (interrupt_request & CPU_INTERRUPT_HARD) {
485 do_interrupt(env);
486 next_tb = 0;
488 #elif defined(TARGET_ALPHA)
489 if (interrupt_request & CPU_INTERRUPT_HARD) {
490 do_interrupt(env);
491 next_tb = 0;
493 #elif defined(TARGET_CRIS)
494 if (interrupt_request & CPU_INTERRUPT_HARD
495 && (env->pregs[PR_CCS] & I_FLAG)) {
496 env->exception_index = EXCP_IRQ;
497 do_interrupt(env);
498 next_tb = 0;
500 if (interrupt_request & CPU_INTERRUPT_NMI
501 && (env->pregs[PR_CCS] & M_FLAG)) {
502 env->exception_index = EXCP_NMI;
503 do_interrupt(env);
504 next_tb = 0;
506 #elif defined(TARGET_M68K)
507 if (interrupt_request & CPU_INTERRUPT_HARD
508 && ((env->sr & SR_I) >> SR_I_SHIFT)
509 < env->pending_level) {
510 /* Real hardware gets the interrupt vector via an
511 IACK cycle at this point. Current emulated
512 hardware doesn't rely on this, so we
513 provide/save the vector when the interrupt is
514 first signalled. */
515 env->exception_index = env->pending_vector;
516 do_interrupt(1);
517 next_tb = 0;
519 #endif
520 /* Don't use the cached interupt_request value,
521 do_interrupt may have updated the EXITTB flag. */
522 if (env->interrupt_request & CPU_INTERRUPT_EXITTB) {
523 env->interrupt_request &= ~CPU_INTERRUPT_EXITTB;
524 /* ensure that no TB jump will be modified as
525 the program flow was changed */
526 next_tb = 0;
528 if (interrupt_request & CPU_INTERRUPT_EXIT) {
529 env->interrupt_request &= ~CPU_INTERRUPT_EXIT;
530 env->exception_index = EXCP_INTERRUPT;
531 cpu_loop_exit();
534 #ifdef DEBUG_EXEC
535 if ((loglevel & CPU_LOG_TB_CPU)) {
536 /* restore flags in standard format */
537 regs_to_env();
538 #if defined(TARGET_I386)
539 env->eflags = env->eflags | helper_cc_compute_all(CC_OP) | (DF & DF_MASK);
540 cpu_dump_state(env, logfile, fprintf, X86_DUMP_CCOP);
541 env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
542 #elif defined(TARGET_ARM)
543 cpu_dump_state(env, logfile, fprintf, 0);
544 #elif defined(TARGET_SPARC)
545 cpu_dump_state(env, logfile, fprintf, 0);
546 #elif defined(TARGET_PPC)
547 cpu_dump_state(env, logfile, fprintf, 0);
548 #elif defined(TARGET_M68K)
549 cpu_m68k_flush_flags(env, env->cc_op);
550 env->cc_op = CC_OP_FLAGS;
551 env->sr = (env->sr & 0xffe0)
552 | env->cc_dest | (env->cc_x << 4);
553 cpu_dump_state(env, logfile, fprintf, 0);
554 #elif defined(TARGET_MIPS)
555 cpu_dump_state(env, logfile, fprintf, 0);
556 #elif defined(TARGET_SH4)
557 cpu_dump_state(env, logfile, fprintf, 0);
558 #elif defined(TARGET_ALPHA)
559 cpu_dump_state(env, logfile, fprintf, 0);
560 #elif defined(TARGET_CRIS)
561 cpu_dump_state(env, logfile, fprintf, 0);
562 #else
563 #error unsupported target CPU
564 #endif
566 #endif
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;
578 #ifdef DEBUG_EXEC
579 if ((loglevel & CPU_LOG_EXEC)) {
580 fprintf(logfile, "Trace 0x%08lx [" TARGET_FMT_lx "] %s\n",
581 (long)tb->tc_ptr, tb->pc,
582 lookup_symbol(tb->pc));
584 #endif
585 /* see if we can patch the calling TB. When the TB
586 spans two pages, we cannot safely do a direct
587 jump. */
589 if (next_tb != 0 &&
590 #ifdef USE_KQEMU
591 (env->kqemu_enabled != 2) &&
592 #endif
593 tb->page_addr[1] == -1) {
594 tb_add_jump((TranslationBlock *)(next_tb & ~3), next_tb & 3, tb);
597 spin_unlock(&tb_lock);
598 env->current_tb = tb;
600 /* cpu_interrupt might be called while translating the
601 TB, but before it is linked into a potentially
602 infinite loop and becomes env->current_tb. Avoid
603 starting execution if there is a pending interrupt. */
604 if (unlikely (env->interrupt_request & CPU_INTERRUPT_EXIT))
605 env->current_tb = NULL;
607 while (env->current_tb) {
608 tc_ptr = tb->tc_ptr;
609 /* execute the generated code */
610 #if defined(__sparc__) && !defined(HOST_SOLARIS)
611 #undef env
612 env = cpu_single_env;
613 #define env cpu_single_env
614 #endif
615 next_tb = tcg_qemu_tb_exec(tc_ptr);
616 env->current_tb = NULL;
617 if ((next_tb & 3) == 2) {
618 /* Instruction counter expired. */
619 int insns_left;
620 tb = (TranslationBlock *)(long)(next_tb & ~3);
621 /* Restore PC. */
622 cpu_pc_from_tb(env, tb);
623 insns_left = env->icount_decr.u32;
624 if (env->icount_extra && insns_left >= 0) {
625 /* Refill decrementer and continue execution. */
626 env->icount_extra += insns_left;
627 if (env->icount_extra > 0xffff) {
628 insns_left = 0xffff;
629 } else {
630 insns_left = env->icount_extra;
632 env->icount_extra -= insns_left;
633 env->icount_decr.u16.low = insns_left;
634 } else {
635 if (insns_left > 0) {
636 /* Execute remaining instructions. */
637 cpu_exec_nocache(insns_left, tb);
639 env->exception_index = EXCP_INTERRUPT;
640 next_tb = 0;
641 cpu_loop_exit();
645 /* reset soft MMU for next block (it can currently
646 only be set by a memory fault) */
647 #if defined(USE_KQEMU)
648 #define MIN_CYCLE_BEFORE_SWITCH (100 * 1000)
649 if (kqemu_is_ok(env) &&
650 (cpu_get_time_fast() - env->last_io_time) >= MIN_CYCLE_BEFORE_SWITCH) {
651 cpu_loop_exit();
653 #endif
654 } /* for(;;) */
655 } else {
656 env_to_regs();
658 } /* for(;;) */
661 #if defined(TARGET_I386)
662 /* restore flags in standard format */
663 env->eflags = env->eflags | helper_cc_compute_all(CC_OP) | (DF & DF_MASK);
664 #elif defined(TARGET_ARM)
665 /* XXX: Save/restore host fpu exception state?. */
666 #elif defined(TARGET_SPARC)
667 #elif defined(TARGET_PPC)
668 #elif defined(TARGET_M68K)
669 cpu_m68k_flush_flags(env, env->cc_op);
670 env->cc_op = CC_OP_FLAGS;
671 env->sr = (env->sr & 0xffe0)
672 | env->cc_dest | (env->cc_x << 4);
673 #elif defined(TARGET_MIPS)
674 #elif defined(TARGET_SH4)
675 #elif defined(TARGET_ALPHA)
676 #elif defined(TARGET_CRIS)
677 /* XXXXX */
678 #else
679 #error unsupported target CPU
680 #endif
682 /* restore global registers */
683 #include "hostregs_helper.h"
685 /* fail safe : never use cpu_single_env outside cpu_exec() */
686 cpu_single_env = NULL;
687 return ret;
690 /* must only be called from the generated code as an exception can be
691 generated */
692 void tb_invalidate_page_range(target_ulong start, target_ulong end)
694 /* XXX: cannot enable it yet because it yields to MMU exception
695 where NIP != read address on PowerPC */
696 #if 0
697 target_ulong phys_addr;
698 phys_addr = get_phys_addr_code(env, start);
699 tb_invalidate_phys_page_range(phys_addr, phys_addr + end - start, 0);
700 #endif
703 #if defined(TARGET_I386) && defined(CONFIG_USER_ONLY)
705 void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector)
707 CPUX86State *saved_env;
709 saved_env = env;
710 env = s;
711 if (!(env->cr[0] & CR0_PE_MASK) || (env->eflags & VM_MASK)) {
712 selector &= 0xffff;
713 cpu_x86_load_seg_cache(env, seg_reg, selector,
714 (selector << 4), 0xffff, 0);
715 } else {
716 helper_load_seg(seg_reg, selector);
718 env = saved_env;
721 void cpu_x86_fsave(CPUX86State *s, target_ulong ptr, int data32)
723 CPUX86State *saved_env;
725 saved_env = env;
726 env = s;
728 helper_fsave(ptr, data32);
730 env = saved_env;
733 void cpu_x86_frstor(CPUX86State *s, target_ulong ptr, int data32)
735 CPUX86State *saved_env;
737 saved_env = env;
738 env = s;
740 helper_frstor(ptr, data32);
742 env = saved_env;
745 #endif /* TARGET_I386 */
747 #if !defined(CONFIG_SOFTMMU)
749 #if defined(TARGET_I386)
751 /* 'pc' is the host PC at which the exception was raised. 'address' is
752 the effective address of the memory exception. 'is_write' is 1 if a
753 write caused the exception and otherwise 0'. 'old_set' is the
754 signal set which should be restored */
755 static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
756 int is_write, sigset_t *old_set,
757 void *puc)
759 TranslationBlock *tb;
760 int ret;
762 if (cpu_single_env)
763 env = cpu_single_env; /* XXX: find a correct solution for multithread */
764 #if defined(DEBUG_SIGNAL)
765 qemu_printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
766 pc, address, is_write, *(unsigned long *)old_set);
767 #endif
768 /* XXX: locking issue */
769 if (is_write && page_unprotect(h2g(address), pc, puc)) {
770 return 1;
773 /* see if it is an MMU fault */
774 ret = cpu_x86_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
775 if (ret < 0)
776 return 0; /* not an MMU fault */
777 if (ret == 0)
778 return 1; /* the MMU fault was handled without causing real CPU fault */
779 /* now we have a real cpu fault */
780 tb = tb_find_pc(pc);
781 if (tb) {
782 /* the PC is inside the translated code. It means that we have
783 a virtual CPU fault */
784 cpu_restore_state(tb, env, pc, puc);
786 if (ret == 1) {
787 #if 0
788 printf("PF exception: EIP=0x%08x CR2=0x%08x error=0x%x\n",
789 env->eip, env->cr[2], env->error_code);
790 #endif
791 /* we restore the process signal mask as the sigreturn should
792 do it (XXX: use sigsetjmp) */
793 sigprocmask(SIG_SETMASK, old_set, NULL);
794 raise_exception_err(env->exception_index, env->error_code);
795 } else {
796 /* activate soft MMU for this block */
797 env->hflags |= HF_SOFTMMU_MASK;
798 cpu_resume_from_signal(env, puc);
800 /* never comes here */
801 return 1;
804 #elif defined(TARGET_ARM)
805 static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
806 int is_write, sigset_t *old_set,
807 void *puc)
809 TranslationBlock *tb;
810 int ret;
812 if (cpu_single_env)
813 env = cpu_single_env; /* XXX: find a correct solution for multithread */
814 #if defined(DEBUG_SIGNAL)
815 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
816 pc, address, is_write, *(unsigned long *)old_set);
817 #endif
818 /* XXX: locking issue */
819 if (is_write && page_unprotect(h2g(address), pc, puc)) {
820 return 1;
822 /* see if it is an MMU fault */
823 ret = cpu_arm_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
824 if (ret < 0)
825 return 0; /* not an MMU fault */
826 if (ret == 0)
827 return 1; /* the MMU fault was handled without causing real CPU fault */
828 /* now we have a real cpu fault */
829 tb = tb_find_pc(pc);
830 if (tb) {
831 /* the PC is inside the translated code. It means that we have
832 a virtual CPU fault */
833 cpu_restore_state(tb, env, pc, puc);
835 /* we restore the process signal mask as the sigreturn should
836 do it (XXX: use sigsetjmp) */
837 sigprocmask(SIG_SETMASK, old_set, NULL);
838 cpu_loop_exit();
839 /* never comes here */
840 return 1;
842 #elif defined(TARGET_SPARC)
843 static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
844 int is_write, sigset_t *old_set,
845 void *puc)
847 TranslationBlock *tb;
848 int ret;
850 if (cpu_single_env)
851 env = cpu_single_env; /* XXX: find a correct solution for multithread */
852 #if defined(DEBUG_SIGNAL)
853 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
854 pc, address, is_write, *(unsigned long *)old_set);
855 #endif
856 /* XXX: locking issue */
857 if (is_write && page_unprotect(h2g(address), pc, puc)) {
858 return 1;
860 /* see if it is an MMU fault */
861 ret = cpu_sparc_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
862 if (ret < 0)
863 return 0; /* not an MMU fault */
864 if (ret == 0)
865 return 1; /* the MMU fault was handled without causing real CPU fault */
866 /* now we have a real cpu fault */
867 tb = tb_find_pc(pc);
868 if (tb) {
869 /* the PC is inside the translated code. It means that we have
870 a virtual CPU fault */
871 cpu_restore_state(tb, env, pc, puc);
873 /* we restore the process signal mask as the sigreturn should
874 do it (XXX: use sigsetjmp) */
875 sigprocmask(SIG_SETMASK, old_set, NULL);
876 cpu_loop_exit();
877 /* never comes here */
878 return 1;
880 #elif defined (TARGET_PPC)
881 static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
882 int is_write, sigset_t *old_set,
883 void *puc)
885 TranslationBlock *tb;
886 int ret;
888 if (cpu_single_env)
889 env = cpu_single_env; /* XXX: find a correct solution for multithread */
890 #if defined(DEBUG_SIGNAL)
891 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
892 pc, address, is_write, *(unsigned long *)old_set);
893 #endif
894 /* XXX: locking issue */
895 if (is_write && page_unprotect(h2g(address), pc, puc)) {
896 return 1;
899 /* see if it is an MMU fault */
900 ret = cpu_ppc_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
901 if (ret < 0)
902 return 0; /* not an MMU fault */
903 if (ret == 0)
904 return 1; /* the MMU fault was handled without causing real CPU fault */
906 /* now we have a real cpu fault */
907 tb = tb_find_pc(pc);
908 if (tb) {
909 /* the PC is inside the translated code. It means that we have
910 a virtual CPU fault */
911 cpu_restore_state(tb, env, pc, puc);
913 if (ret == 1) {
914 #if 0
915 printf("PF exception: NIP=0x%08x error=0x%x %p\n",
916 env->nip, env->error_code, tb);
917 #endif
918 /* we restore the process signal mask as the sigreturn should
919 do it (XXX: use sigsetjmp) */
920 sigprocmask(SIG_SETMASK, old_set, NULL);
921 cpu_loop_exit();
922 } else {
923 /* activate soft MMU for this block */
924 cpu_resume_from_signal(env, puc);
926 /* never comes here */
927 return 1;
930 #elif defined(TARGET_M68K)
931 static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
932 int is_write, sigset_t *old_set,
933 void *puc)
935 TranslationBlock *tb;
936 int ret;
938 if (cpu_single_env)
939 env = cpu_single_env; /* XXX: find a correct solution for multithread */
940 #if defined(DEBUG_SIGNAL)
941 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
942 pc, address, is_write, *(unsigned long *)old_set);
943 #endif
944 /* XXX: locking issue */
945 if (is_write && page_unprotect(address, pc, puc)) {
946 return 1;
948 /* see if it is an MMU fault */
949 ret = cpu_m68k_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
950 if (ret < 0)
951 return 0; /* not an MMU fault */
952 if (ret == 0)
953 return 1; /* the MMU fault was handled without causing real CPU fault */
954 /* now we have a real cpu fault */
955 tb = tb_find_pc(pc);
956 if (tb) {
957 /* the PC is inside the translated code. It means that we have
958 a virtual CPU fault */
959 cpu_restore_state(tb, env, pc, puc);
961 /* we restore the process signal mask as the sigreturn should
962 do it (XXX: use sigsetjmp) */
963 sigprocmask(SIG_SETMASK, old_set, NULL);
964 cpu_loop_exit();
965 /* never comes here */
966 return 1;
969 #elif defined (TARGET_MIPS)
970 static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
971 int is_write, sigset_t *old_set,
972 void *puc)
974 TranslationBlock *tb;
975 int ret;
977 if (cpu_single_env)
978 env = cpu_single_env; /* XXX: find a correct solution for multithread */
979 #if defined(DEBUG_SIGNAL)
980 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
981 pc, address, is_write, *(unsigned long *)old_set);
982 #endif
983 /* XXX: locking issue */
984 if (is_write && page_unprotect(h2g(address), pc, puc)) {
985 return 1;
988 /* see if it is an MMU fault */
989 ret = cpu_mips_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
990 if (ret < 0)
991 return 0; /* not an MMU fault */
992 if (ret == 0)
993 return 1; /* the MMU fault was handled without causing real CPU fault */
995 /* now we have a real cpu fault */
996 tb = tb_find_pc(pc);
997 if (tb) {
998 /* the PC is inside the translated code. It means that we have
999 a virtual CPU fault */
1000 cpu_restore_state(tb, env, pc, puc);
1002 if (ret == 1) {
1003 #if 0
1004 printf("PF exception: PC=0x" TARGET_FMT_lx " error=0x%x %p\n",
1005 env->PC, env->error_code, tb);
1006 #endif
1007 /* we restore the process signal mask as the sigreturn should
1008 do it (XXX: use sigsetjmp) */
1009 sigprocmask(SIG_SETMASK, old_set, NULL);
1010 do_raise_exception_err(env->exception_index, env->error_code);
1011 } else {
1012 /* activate soft MMU for this block */
1013 cpu_resume_from_signal(env, puc);
1015 /* never comes here */
1016 return 1;
1019 #elif defined (TARGET_SH4)
1020 static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
1021 int is_write, sigset_t *old_set,
1022 void *puc)
1024 TranslationBlock *tb;
1025 int ret;
1027 if (cpu_single_env)
1028 env = cpu_single_env; /* XXX: find a correct solution for multithread */
1029 #if defined(DEBUG_SIGNAL)
1030 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
1031 pc, address, is_write, *(unsigned long *)old_set);
1032 #endif
1033 /* XXX: locking issue */
1034 if (is_write && page_unprotect(h2g(address), pc, puc)) {
1035 return 1;
1038 /* see if it is an MMU fault */
1039 ret = cpu_sh4_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
1040 if (ret < 0)
1041 return 0; /* not an MMU fault */
1042 if (ret == 0)
1043 return 1; /* the MMU fault was handled without causing real CPU fault */
1045 /* now we have a real cpu fault */
1046 tb = tb_find_pc(pc);
1047 if (tb) {
1048 /* the PC is inside the translated code. It means that we have
1049 a virtual CPU fault */
1050 cpu_restore_state(tb, env, pc, puc);
1052 #if 0
1053 printf("PF exception: NIP=0x%08x error=0x%x %p\n",
1054 env->nip, env->error_code, tb);
1055 #endif
1056 /* we restore the process signal mask as the sigreturn should
1057 do it (XXX: use sigsetjmp) */
1058 sigprocmask(SIG_SETMASK, old_set, NULL);
1059 cpu_loop_exit();
1060 /* never comes here */
1061 return 1;
1064 #elif defined (TARGET_ALPHA)
1065 static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
1066 int is_write, sigset_t *old_set,
1067 void *puc)
1069 TranslationBlock *tb;
1070 int ret;
1072 if (cpu_single_env)
1073 env = cpu_single_env; /* XXX: find a correct solution for multithread */
1074 #if defined(DEBUG_SIGNAL)
1075 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
1076 pc, address, is_write, *(unsigned long *)old_set);
1077 #endif
1078 /* XXX: locking issue */
1079 if (is_write && page_unprotect(h2g(address), pc, puc)) {
1080 return 1;
1083 /* see if it is an MMU fault */
1084 ret = cpu_alpha_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
1085 if (ret < 0)
1086 return 0; /* not an MMU fault */
1087 if (ret == 0)
1088 return 1; /* the MMU fault was handled without causing real CPU fault */
1090 /* now we have a real cpu fault */
1091 tb = tb_find_pc(pc);
1092 if (tb) {
1093 /* the PC is inside the translated code. It means that we have
1094 a virtual CPU fault */
1095 cpu_restore_state(tb, env, pc, puc);
1097 #if 0
1098 printf("PF exception: NIP=0x%08x error=0x%x %p\n",
1099 env->nip, env->error_code, tb);
1100 #endif
1101 /* we restore the process signal mask as the sigreturn should
1102 do it (XXX: use sigsetjmp) */
1103 sigprocmask(SIG_SETMASK, old_set, NULL);
1104 cpu_loop_exit();
1105 /* never comes here */
1106 return 1;
1108 #elif defined (TARGET_CRIS)
1109 static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
1110 int is_write, sigset_t *old_set,
1111 void *puc)
1113 TranslationBlock *tb;
1114 int ret;
1116 if (cpu_single_env)
1117 env = cpu_single_env; /* XXX: find a correct solution for multithread */
1118 #if defined(DEBUG_SIGNAL)
1119 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
1120 pc, address, is_write, *(unsigned long *)old_set);
1121 #endif
1122 /* XXX: locking issue */
1123 if (is_write && page_unprotect(h2g(address), pc, puc)) {
1124 return 1;
1127 /* see if it is an MMU fault */
1128 ret = cpu_cris_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
1129 if (ret < 0)
1130 return 0; /* not an MMU fault */
1131 if (ret == 0)
1132 return 1; /* the MMU fault was handled without causing real CPU fault */
1134 /* now we have a real cpu fault */
1135 tb = tb_find_pc(pc);
1136 if (tb) {
1137 /* the PC is inside the translated code. It means that we have
1138 a virtual CPU fault */
1139 cpu_restore_state(tb, env, pc, puc);
1141 /* we restore the process signal mask as the sigreturn should
1142 do it (XXX: use sigsetjmp) */
1143 sigprocmask(SIG_SETMASK, old_set, NULL);
1144 cpu_loop_exit();
1145 /* never comes here */
1146 return 1;
1149 #else
1150 #error unsupported target CPU
1151 #endif
1153 #if defined(__i386__)
1155 #if defined(__APPLE__)
1156 # include <sys/ucontext.h>
1158 # define EIP_sig(context) (*((unsigned long*)&(context)->uc_mcontext->ss.eip))
1159 # define TRAP_sig(context) ((context)->uc_mcontext->es.trapno)
1160 # define ERROR_sig(context) ((context)->uc_mcontext->es.err)
1161 #else
1162 # define EIP_sig(context) ((context)->uc_mcontext.gregs[REG_EIP])
1163 # define TRAP_sig(context) ((context)->uc_mcontext.gregs[REG_TRAPNO])
1164 # define ERROR_sig(context) ((context)->uc_mcontext.gregs[REG_ERR])
1165 #endif
1167 int cpu_signal_handler(int host_signum, void *pinfo,
1168 void *puc)
1170 siginfo_t *info = pinfo;
1171 struct ucontext *uc = puc;
1172 unsigned long pc;
1173 int trapno;
1175 #ifndef REG_EIP
1176 /* for glibc 2.1 */
1177 #define REG_EIP EIP
1178 #define REG_ERR ERR
1179 #define REG_TRAPNO TRAPNO
1180 #endif
1181 pc = EIP_sig(uc);
1182 trapno = TRAP_sig(uc);
1183 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1184 trapno == 0xe ?
1185 (ERROR_sig(uc) >> 1) & 1 : 0,
1186 &uc->uc_sigmask, puc);
1189 #elif defined(__x86_64__)
1191 #ifdef __NetBSD__
1192 #define REG_ERR _REG_ERR
1193 #define REG_TRAPNO _REG_TRAPNO
1195 #define QEMU_UC_MCONTEXT_GREGS(uc, reg) (uc)->uc_mcontext.__gregs[(reg)]
1196 #define QEMU_UC_MACHINE_PC(uc) _UC_MACHINE_PC(uc)
1197 #else
1198 #define QEMU_UC_MCONTEXT_GREGS(uc, reg) (uc)->uc_mcontext.gregs[(reg)]
1199 #define QEMU_UC_MACHINE_PC(uc) QEMU_UC_MCONTEXT_GREGS(uc, REG_RIP)
1200 #endif
1202 int cpu_signal_handler(int host_signum, void *pinfo,
1203 void *puc)
1205 siginfo_t *info = pinfo;
1206 unsigned long pc;
1207 #ifdef __NetBSD__
1208 ucontext_t *uc = puc;
1209 #else
1210 struct ucontext *uc = puc;
1211 #endif
1213 pc = QEMU_UC_MACHINE_PC(uc);
1214 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1215 QEMU_UC_MCONTEXT_GREGS(uc, REG_TRAPNO) == 0xe ?
1216 (QEMU_UC_MCONTEXT_GREGS(uc, REG_ERR) >> 1) & 1 : 0,
1217 &uc->uc_sigmask, puc);
1220 #elif defined(__powerpc__)
1222 /***********************************************************************
1223 * signal context platform-specific definitions
1224 * From Wine
1226 #ifdef linux
1227 /* All Registers access - only for local access */
1228 # define REG_sig(reg_name, context) ((context)->uc_mcontext.regs->reg_name)
1229 /* Gpr Registers access */
1230 # define GPR_sig(reg_num, context) REG_sig(gpr[reg_num], context)
1231 # define IAR_sig(context) REG_sig(nip, context) /* Program counter */
1232 # define MSR_sig(context) REG_sig(msr, context) /* Machine State Register (Supervisor) */
1233 # define CTR_sig(context) REG_sig(ctr, context) /* Count register */
1234 # define XER_sig(context) REG_sig(xer, context) /* User's integer exception register */
1235 # define LR_sig(context) REG_sig(link, context) /* Link register */
1236 # define CR_sig(context) REG_sig(ccr, context) /* Condition register */
1237 /* Float Registers access */
1238 # define FLOAT_sig(reg_num, context) (((double*)((char*)((context)->uc_mcontext.regs+48*4)))[reg_num])
1239 # define FPSCR_sig(context) (*(int*)((char*)((context)->uc_mcontext.regs+(48+32*2)*4)))
1240 /* Exception Registers access */
1241 # define DAR_sig(context) REG_sig(dar, context)
1242 # define DSISR_sig(context) REG_sig(dsisr, context)
1243 # define TRAP_sig(context) REG_sig(trap, context)
1244 #endif /* linux */
1246 #ifdef __APPLE__
1247 # include <sys/ucontext.h>
1248 typedef struct ucontext SIGCONTEXT;
1249 /* All Registers access - only for local access */
1250 # define REG_sig(reg_name, context) ((context)->uc_mcontext->ss.reg_name)
1251 # define FLOATREG_sig(reg_name, context) ((context)->uc_mcontext->fs.reg_name)
1252 # define EXCEPREG_sig(reg_name, context) ((context)->uc_mcontext->es.reg_name)
1253 # define VECREG_sig(reg_name, context) ((context)->uc_mcontext->vs.reg_name)
1254 /* Gpr Registers access */
1255 # define GPR_sig(reg_num, context) REG_sig(r##reg_num, context)
1256 # define IAR_sig(context) REG_sig(srr0, context) /* Program counter */
1257 # define MSR_sig(context) REG_sig(srr1, context) /* Machine State Register (Supervisor) */
1258 # define CTR_sig(context) REG_sig(ctr, context)
1259 # define XER_sig(context) REG_sig(xer, context) /* Link register */
1260 # define LR_sig(context) REG_sig(lr, context) /* User's integer exception register */
1261 # define CR_sig(context) REG_sig(cr, context) /* Condition register */
1262 /* Float Registers access */
1263 # define FLOAT_sig(reg_num, context) FLOATREG_sig(fpregs[reg_num], context)
1264 # define FPSCR_sig(context) ((double)FLOATREG_sig(fpscr, context))
1265 /* Exception Registers access */
1266 # define DAR_sig(context) EXCEPREG_sig(dar, context) /* Fault registers for coredump */
1267 # define DSISR_sig(context) EXCEPREG_sig(dsisr, context)
1268 # define TRAP_sig(context) EXCEPREG_sig(exception, context) /* number of powerpc exception taken */
1269 #endif /* __APPLE__ */
1271 int cpu_signal_handler(int host_signum, void *pinfo,
1272 void *puc)
1274 siginfo_t *info = pinfo;
1275 struct ucontext *uc = puc;
1276 unsigned long pc;
1277 int is_write;
1279 pc = IAR_sig(uc);
1280 is_write = 0;
1281 #if 0
1282 /* ppc 4xx case */
1283 if (DSISR_sig(uc) & 0x00800000)
1284 is_write = 1;
1285 #else
1286 if (TRAP_sig(uc) != 0x400 && (DSISR_sig(uc) & 0x02000000))
1287 is_write = 1;
1288 #endif
1289 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1290 is_write, &uc->uc_sigmask, puc);
1293 #elif defined(__alpha__)
1295 int cpu_signal_handler(int host_signum, void *pinfo,
1296 void *puc)
1298 siginfo_t *info = pinfo;
1299 struct ucontext *uc = puc;
1300 uint32_t *pc = uc->uc_mcontext.sc_pc;
1301 uint32_t insn = *pc;
1302 int is_write = 0;
1304 /* XXX: need kernel patch to get write flag faster */
1305 switch (insn >> 26) {
1306 case 0x0d: // stw
1307 case 0x0e: // stb
1308 case 0x0f: // stq_u
1309 case 0x24: // stf
1310 case 0x25: // stg
1311 case 0x26: // sts
1312 case 0x27: // stt
1313 case 0x2c: // stl
1314 case 0x2d: // stq
1315 case 0x2e: // stl_c
1316 case 0x2f: // stq_c
1317 is_write = 1;
1320 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1321 is_write, &uc->uc_sigmask, puc);
1323 #elif defined(__sparc__)
1325 int cpu_signal_handler(int host_signum, void *pinfo,
1326 void *puc)
1328 siginfo_t *info = pinfo;
1329 int is_write;
1330 uint32_t insn;
1331 #if !defined(__arch64__) || defined(HOST_SOLARIS)
1332 uint32_t *regs = (uint32_t *)(info + 1);
1333 void *sigmask = (regs + 20);
1334 /* XXX: is there a standard glibc define ? */
1335 unsigned long pc = regs[1];
1336 #else
1337 #ifdef __linux__
1338 struct sigcontext *sc = puc;
1339 unsigned long pc = sc->sigc_regs.tpc;
1340 void *sigmask = (void *)sc->sigc_mask;
1341 #elif defined(__OpenBSD__)
1342 struct sigcontext *uc = puc;
1343 unsigned long pc = uc->sc_pc;
1344 void *sigmask = (void *)(long)uc->sc_mask;
1345 #endif
1346 #endif
1348 /* XXX: need kernel patch to get write flag faster */
1349 is_write = 0;
1350 insn = *(uint32_t *)pc;
1351 if ((insn >> 30) == 3) {
1352 switch((insn >> 19) & 0x3f) {
1353 case 0x05: // stb
1354 case 0x06: // sth
1355 case 0x04: // st
1356 case 0x07: // std
1357 case 0x24: // stf
1358 case 0x27: // stdf
1359 case 0x25: // stfsr
1360 is_write = 1;
1361 break;
1364 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1365 is_write, sigmask, NULL);
1368 #elif defined(__arm__)
1370 int cpu_signal_handler(int host_signum, void *pinfo,
1371 void *puc)
1373 siginfo_t *info = pinfo;
1374 struct ucontext *uc = puc;
1375 unsigned long pc;
1376 int is_write;
1378 #if (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ <= 3))
1379 pc = uc->uc_mcontext.gregs[R15];
1380 #else
1381 pc = uc->uc_mcontext.arm_pc;
1382 #endif
1383 /* XXX: compute is_write */
1384 is_write = 0;
1385 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1386 is_write,
1387 &uc->uc_sigmask, puc);
1390 #elif defined(__mc68000)
1392 int cpu_signal_handler(int host_signum, void *pinfo,
1393 void *puc)
1395 siginfo_t *info = pinfo;
1396 struct ucontext *uc = puc;
1397 unsigned long pc;
1398 int is_write;
1400 pc = uc->uc_mcontext.gregs[16];
1401 /* XXX: compute is_write */
1402 is_write = 0;
1403 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1404 is_write,
1405 &uc->uc_sigmask, puc);
1408 #elif defined(__ia64)
1410 #ifndef __ISR_VALID
1411 /* This ought to be in <bits/siginfo.h>... */
1412 # define __ISR_VALID 1
1413 #endif
1415 int cpu_signal_handler(int host_signum, void *pinfo, void *puc)
1417 siginfo_t *info = pinfo;
1418 struct ucontext *uc = puc;
1419 unsigned long ip;
1420 int is_write = 0;
1422 ip = uc->uc_mcontext.sc_ip;
1423 switch (host_signum) {
1424 case SIGILL:
1425 case SIGFPE:
1426 case SIGSEGV:
1427 case SIGBUS:
1428 case SIGTRAP:
1429 if (info->si_code && (info->si_segvflags & __ISR_VALID))
1430 /* ISR.W (write-access) is bit 33: */
1431 is_write = (info->si_isr >> 33) & 1;
1432 break;
1434 default:
1435 break;
1437 return handle_cpu_signal(ip, (unsigned long)info->si_addr,
1438 is_write,
1439 &uc->uc_sigmask, puc);
1442 #elif defined(__s390__)
1444 int cpu_signal_handler(int host_signum, void *pinfo,
1445 void *puc)
1447 siginfo_t *info = pinfo;
1448 struct ucontext *uc = puc;
1449 unsigned long pc;
1450 int is_write;
1452 pc = uc->uc_mcontext.psw.addr;
1453 /* XXX: compute is_write */
1454 is_write = 0;
1455 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1456 is_write, &uc->uc_sigmask, puc);
1459 #elif defined(__mips__)
1461 int cpu_signal_handler(int host_signum, void *pinfo,
1462 void *puc)
1464 siginfo_t *info = pinfo;
1465 struct ucontext *uc = puc;
1466 greg_t pc = uc->uc_mcontext.pc;
1467 int is_write;
1469 /* XXX: compute is_write */
1470 is_write = 0;
1471 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1472 is_write, &uc->uc_sigmask, puc);
1475 #elif defined(__hppa__)
1477 int cpu_signal_handler(int host_signum, void *pinfo,
1478 void *puc)
1480 struct siginfo *info = pinfo;
1481 struct ucontext *uc = puc;
1482 unsigned long pc;
1483 int is_write;
1485 pc = uc->uc_mcontext.sc_iaoq[0];
1486 /* FIXME: compute is_write */
1487 is_write = 0;
1488 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1489 is_write,
1490 &uc->uc_sigmask, puc);
1493 #else
1495 #error host CPU specific signal handler needed
1497 #endif
1499 #endif /* !defined(CONFIG_SOFTMMU) */