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