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