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