blob: 7bc432d1a6e6b3766ae43277dc86b0816b4ca2ad [file] [log] [blame]
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001/*
2 * i386 emulator main execution loop
3 *
4 * Copyright (c) 2003-2005 Fabrice Bellard
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -070018 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080019 */
20#include "config.h"
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080021#include "exec.h"
22#include "disas.h"
23#include "tcg.h"
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -070024#include "kvm.h"
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080025
26#if !defined(CONFIG_SOFTMMU)
27#undef EAX
28#undef ECX
29#undef EDX
30#undef EBX
31#undef ESP
32#undef EBP
33#undef ESI
34#undef EDI
35#undef EIP
36#include <signal.h>
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -070037#ifdef __linux__
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080038#include <sys/ucontext.h>
39#endif
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -070040#endif
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080041
David 'Digit' Turner2c538c82010-05-10 16:48:20 -070042#if defined(__sparc__) && !defined(CONFIG_SOLARIS)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080043// Work around ugly bugs in glibc that mangle global register contents
44#undef env
45#define env cpu_single_env
46#endif
47
48int tb_invalidated_flag;
49
50//#define DEBUG_EXEC
51//#define DEBUG_SIGNAL
52
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -070053int qemu_cpu_has_work(CPUState *env)
54{
55 return cpu_has_work(env);
56}
57
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080058void cpu_loop_exit(void)
59{
60 /* NOTE: the register at this point must be saved by hand because
61 longjmp restore them */
62 regs_to_env();
63 longjmp(env->jmp_env, 1);
64}
65
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080066/* exit the current TB from a signal handler. The host registers are
67 restored in a state compatible with the CPU emulator
68 */
69void cpu_resume_from_signal(CPUState *env1, void *puc)
70{
71#if !defined(CONFIG_SOFTMMU)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -070072#ifdef __linux__
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080073 struct ucontext *uc = puc;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -070074#elif defined(__OpenBSD__)
75 struct sigcontext *uc = puc;
76#endif
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080077#endif
78
79 env = env1;
80
81 /* XXX: restore cpu registers saved in host registers */
82
83#if !defined(CONFIG_SOFTMMU)
84 if (puc) {
85 /* XXX: use siglongjmp ? */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -070086#ifdef __linux__
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080087 sigprocmask(SIG_SETMASK, &uc->uc_sigmask, NULL);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -070088#elif defined(__OpenBSD__)
89 sigprocmask(SIG_SETMASK, &uc->sc_mask, NULL);
90#endif
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080091 }
92#endif
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -070093 env->exception_index = -1;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080094 longjmp(env->jmp_env, 1);
95}
96
97/* Execute the code without caching the generated code. An interpreter
98 could be used if available. */
99static void cpu_exec_nocache(int max_cycles, TranslationBlock *orig_tb)
100{
101 unsigned long next_tb;
102 TranslationBlock *tb;
103
104 /* Should never happen.
105 We only end up here when an existing TB is too long. */
106 if (max_cycles > CF_COUNT_MASK)
107 max_cycles = CF_COUNT_MASK;
108
109 tb = tb_gen_code(env, orig_tb->pc, orig_tb->cs_base, orig_tb->flags,
110 max_cycles);
111 env->current_tb = tb;
112 /* execute the generated code */
113 next_tb = tcg_qemu_tb_exec(tb->tc_ptr);
114
115 if ((next_tb & 3) == 2) {
116 /* Restore PC. This may happen if async event occurs before
117 the TB starts executing. */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700118 cpu_pc_from_tb(env, tb);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800119 }
120 tb_phys_invalidate(tb, -1);
121 tb_free(tb);
122}
123
124static TranslationBlock *tb_find_slow(target_ulong pc,
125 target_ulong cs_base,
126 uint64_t flags)
127{
128 TranslationBlock *tb, **ptb1;
129 unsigned int h;
130 target_ulong phys_pc, phys_page1, phys_page2, virt_page2;
131
132 tb_invalidated_flag = 0;
133
134 regs_to_env(); /* XXX: do it just before cpu_gen_code() */
135
136 /* find translated block using physical mappings */
137 phys_pc = get_phys_addr_code(env, pc);
138 phys_page1 = phys_pc & TARGET_PAGE_MASK;
139 phys_page2 = -1;
140 h = tb_phys_hash_func(phys_pc);
141 ptb1 = &tb_phys_hash[h];
142 for(;;) {
143 tb = *ptb1;
144 if (!tb)
145 goto not_found;
146 if (tb->pc == pc &&
147 tb->page_addr[0] == phys_page1 &&
148 tb->cs_base == cs_base &&
149 tb->flags == flags) {
150 /* check next page if needed */
151 if (tb->page_addr[1] != -1) {
152 virt_page2 = (pc & TARGET_PAGE_MASK) +
153 TARGET_PAGE_SIZE;
154 phys_page2 = get_phys_addr_code(env, virt_page2);
155 if (tb->page_addr[1] == phys_page2)
156 goto found;
157 } else {
158 goto found;
159 }
160 }
161 ptb1 = &tb->phys_hash_next;
162 }
163 not_found:
164 /* if no translated code available, then translate it now */
165 tb = tb_gen_code(env, pc, cs_base, flags, 0);
166
167 found:
168 /* we add the TB in the virtual pc hash table */
169 env->tb_jmp_cache[tb_jmp_cache_hash_func(pc)] = tb;
170 return tb;
171}
172
173static inline TranslationBlock *tb_find_fast(void)
174{
175 TranslationBlock *tb;
176 target_ulong cs_base, pc;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700177 int flags;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800178
179 /* we record a subset of the CPU state. It will
180 always be the same before a given translated block
181 is executed. */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700182 cpu_get_tb_cpu_state(env, &pc, &cs_base, &flags);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800183 tb = env->tb_jmp_cache[tb_jmp_cache_hash_func(pc)];
184 if (unlikely(!tb || tb->pc != pc || tb->cs_base != cs_base ||
185 tb->flags != flags)) {
186 tb = tb_find_slow(pc, cs_base, flags);
187 }
188 return tb;
189}
190
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700191static CPUDebugExcpHandler *debug_excp_handler;
192
193CPUDebugExcpHandler *cpu_set_debug_excp_handler(CPUDebugExcpHandler *handler)
194{
195 CPUDebugExcpHandler *old_handler = debug_excp_handler;
196
197 debug_excp_handler = handler;
198 return old_handler;
199}
200
201static void cpu_handle_debug_exception(CPUState *env)
202{
203 CPUWatchpoint *wp;
204
205 if (!env->watchpoint_hit)
206 TAILQ_FOREACH(wp, &env->watchpoints, entry)
207 wp->flags &= ~BP_WATCHPOINT_HIT;
208
209 if (debug_excp_handler)
210 debug_excp_handler(env);
211}
212
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800213/* main execution loop */
214
215int cpu_exec(CPUState *env1)
216{
217#define DECLARE_HOST_REGS 1
218#include "hostregs_helper.h"
219 int ret, interrupt_request;
220 TranslationBlock *tb;
221 uint8_t *tc_ptr;
222 unsigned long next_tb;
223
224 if (cpu_halted(env1) == EXCP_HALTED)
225 return EXCP_HALTED;
226
227 cpu_single_env = env1;
228
229 /* first we save global registers */
230#define SAVE_HOST_REGS 1
231#include "hostregs_helper.h"
232 env = env1;
233
234 env_to_regs();
235#if defined(TARGET_I386)
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#elif defined(TARGET_SPARC)
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;
246#elif defined(TARGET_ALPHA)
247#elif defined(TARGET_ARM)
248#elif defined(TARGET_PPC)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700249#elif defined(TARGET_MICROBLAZE)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800250#elif defined(TARGET_MIPS)
251#elif defined(TARGET_SH4)
252#elif defined(TARGET_CRIS)
253 /* XXXXX */
254#else
255#error unsupported target CPU
256#endif
257 env->exception_index = -1;
258
259 /* prepare setjmp context for exception handling */
260 for(;;) {
261 if (setjmp(env->jmp_env) == 0) {
David 'Digit' Turner2c538c82010-05-10 16:48:20 -0700262#if defined(__sparc__) && !defined(CONFIG_SOLARIS)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700263#undef env
264 env = cpu_single_env;
265#define env cpu_single_env
266#endif
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800267 env->current_tb = NULL;
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;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700273 if (ret == EXCP_DEBUG)
274 cpu_handle_debug_exception(env);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800275 break;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700276 } else {
277#if defined(CONFIG_USER_ONLY)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800278 /* if user mode only, we simulate a fake exception
279 which will be handled outside the cpu execution
280 loop */
281#if defined(TARGET_I386)
282 do_interrupt_user(env->exception_index,
283 env->exception_is_int,
284 env->error_code,
285 env->exception_next_eip);
286 /* successfully delivered */
287 env->old_exception = -1;
288#endif
289 ret = env->exception_index;
290 break;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700291#else
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800292#if defined(TARGET_I386)
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. */
296 do_interrupt(env->exception_index,
297 env->exception_is_int,
298 env->error_code,
299 env->exception_next_eip, 0);
300 /* successfully delivered */
301 env->old_exception = -1;
302#elif defined(TARGET_PPC)
303 do_interrupt(env);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700304#elif defined(TARGET_MICROBLAZE)
305 do_interrupt(env);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800306#elif defined(TARGET_MIPS)
307 do_interrupt(env);
308#elif defined(TARGET_SPARC)
309 do_interrupt(env);
310#elif defined(TARGET_ARM)
311 do_interrupt(env);
312#elif defined(TARGET_SH4)
313 do_interrupt(env);
314#elif defined(TARGET_ALPHA)
315 do_interrupt(env);
316#elif defined(TARGET_CRIS)
317 do_interrupt(env);
318#elif defined(TARGET_M68K)
319 do_interrupt(0);
320#endif
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700321#endif
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800322 }
323 env->exception_index = -1;
324 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700325#ifdef CONFIG_KQEMU
326 if (kqemu_is_ok(env) && env->interrupt_request == 0 && env->exit_request == 0) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800327 int ret;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700328 env->eflags = env->eflags | helper_cc_compute_all(CC_OP) | (DF & DF_MASK);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800329 ret = kqemu_cpu_exec(env);
330 /* put eflags in CPU temporary format */
331 CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
332 DF = 1 - (2 * ((env->eflags >> 10) & 1));
333 CC_OP = CC_OP_EFLAGS;
334 env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
335 if (ret == 1) {
336 /* exception */
337 longjmp(env->jmp_env, 1);
338 } else if (ret == 2) {
339 /* softmmu execution needed */
340 } else {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700341 if (env->interrupt_request != 0 || env->exit_request != 0) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800342 /* hardware interrupt will be executed just after */
343 } else {
344 /* otherwise, we restart */
345 longjmp(env->jmp_env, 1);
346 }
347 }
348 }
349#endif
350
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700351 if (kvm_enabled()) {
352 kvm_cpu_exec(env);
353 longjmp(env->jmp_env, 1);
354 }
355
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800356 next_tb = 0; /* force lookup of first TB */
357 for(;;) {
358 interrupt_request = env->interrupt_request;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700359 if (unlikely(interrupt_request)) {
360 if (unlikely(env->singlestep_enabled & SSTEP_NOIRQ)) {
361 /* Mask out external interrupts for this step. */
362 interrupt_request &= ~(CPU_INTERRUPT_HARD |
363 CPU_INTERRUPT_FIQ |
364 CPU_INTERRUPT_SMI |
365 CPU_INTERRUPT_NMI);
366 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800367 if (interrupt_request & CPU_INTERRUPT_DEBUG) {
368 env->interrupt_request &= ~CPU_INTERRUPT_DEBUG;
369 env->exception_index = EXCP_DEBUG;
370 cpu_loop_exit();
371 }
372#if defined(TARGET_ARM) || defined(TARGET_SPARC) || defined(TARGET_MIPS) || \
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700373 defined(TARGET_PPC) || defined(TARGET_ALPHA) || defined(TARGET_CRIS) || \
374 defined(TARGET_MICROBLAZE)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800375 if (interrupt_request & CPU_INTERRUPT_HALT) {
376 env->interrupt_request &= ~CPU_INTERRUPT_HALT;
377 env->halted = 1;
378 env->exception_index = EXCP_HLT;
379 cpu_loop_exit();
380 }
381#endif
382#if defined(TARGET_I386)
383 if (env->hflags2 & HF2_GIF_MASK) {
384 if ((interrupt_request & CPU_INTERRUPT_SMI) &&
385 !(env->hflags & HF_SMM_MASK)) {
386 svm_check_intercept(SVM_EXIT_SMI);
387 env->interrupt_request &= ~CPU_INTERRUPT_SMI;
388 do_smm_enter();
389 next_tb = 0;
390 } else if ((interrupt_request & CPU_INTERRUPT_NMI) &&
391 !(env->hflags2 & HF2_NMI_MASK)) {
392 env->interrupt_request &= ~CPU_INTERRUPT_NMI;
393 env->hflags2 |= HF2_NMI_MASK;
394 do_interrupt(EXCP02_NMI, 0, 0, 0, 1);
395 next_tb = 0;
396 } else if ((interrupt_request & CPU_INTERRUPT_HARD) &&
397 (((env->hflags2 & HF2_VINTR_MASK) &&
398 (env->hflags2 & HF2_HIF_MASK)) ||
399 (!(env->hflags2 & HF2_VINTR_MASK) &&
400 (env->eflags & IF_MASK &&
401 !(env->hflags & HF_INHIBIT_IRQ_MASK))))) {
402 int intno;
403 svm_check_intercept(SVM_EXIT_INTR);
404 env->interrupt_request &= ~(CPU_INTERRUPT_HARD | CPU_INTERRUPT_VIRQ);
405 intno = cpu_get_pic_interrupt(env);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700406 qemu_log_mask(CPU_LOG_TB_IN_ASM, "Servicing hardware INT=0x%02x\n", intno);
David 'Digit' Turner2c538c82010-05-10 16:48:20 -0700407#if defined(__sparc__) && !defined(CONFIG_SOLARIS)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700408#undef env
409 env = cpu_single_env;
410#define env cpu_single_env
411#endif
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800412 do_interrupt(intno, 0, 0, 0, 1);
413 /* ensure that no TB jump will be modified as
414 the program flow was changed */
415 next_tb = 0;
416#if !defined(CONFIG_USER_ONLY)
417 } else if ((interrupt_request & CPU_INTERRUPT_VIRQ) &&
418 (env->eflags & IF_MASK) &&
419 !(env->hflags & HF_INHIBIT_IRQ_MASK)) {
420 int intno;
421 /* FIXME: this should respect TPR */
422 svm_check_intercept(SVM_EXIT_VINTR);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800423 intno = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_vector));
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700424 qemu_log_mask(CPU_LOG_TB_IN_ASM, "Servicing virtual hardware INT=0x%02x\n", intno);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800425 do_interrupt(intno, 0, 0, 0, 1);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700426 env->interrupt_request &= ~CPU_INTERRUPT_VIRQ;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800427 next_tb = 0;
428#endif
429 }
430 }
431#elif defined(TARGET_PPC)
432#if 0
433 if ((interrupt_request & CPU_INTERRUPT_RESET)) {
434 cpu_ppc_reset(env);
435 }
436#endif
437 if (interrupt_request & CPU_INTERRUPT_HARD) {
438 ppc_hw_interrupt(env);
439 if (env->pending_interrupts == 0)
440 env->interrupt_request &= ~CPU_INTERRUPT_HARD;
441 next_tb = 0;
442 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700443#elif defined(TARGET_MICROBLAZE)
444 if ((interrupt_request & CPU_INTERRUPT_HARD)
445 && (env->sregs[SR_MSR] & MSR_IE)
446 && !(env->sregs[SR_MSR] & (MSR_EIP | MSR_BIP))
447 && !(env->iflags & (D_FLAG | IMM_FLAG))) {
448 env->exception_index = EXCP_IRQ;
449 do_interrupt(env);
450 next_tb = 0;
451 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800452#elif defined(TARGET_MIPS)
453 if ((interrupt_request & CPU_INTERRUPT_HARD) &&
454 (env->CP0_Status & env->CP0_Cause & CP0Ca_IP_mask) &&
455 (env->CP0_Status & (1 << CP0St_IE)) &&
456 !(env->CP0_Status & (1 << CP0St_EXL)) &&
457 !(env->CP0_Status & (1 << CP0St_ERL)) &&
458 !(env->hflags & MIPS_HFLAG_DM)) {
459 /* Raise it */
460 env->exception_index = EXCP_EXT_INTERRUPT;
461 env->error_code = 0;
462 do_interrupt(env);
463 next_tb = 0;
464 }
465#elif defined(TARGET_SPARC)
466 if ((interrupt_request & CPU_INTERRUPT_HARD) &&
467 (env->psret != 0)) {
468 int pil = env->interrupt_index & 15;
469 int type = env->interrupt_index & 0xf0;
470
471 if (((type == TT_EXTINT) &&
472 (pil == 15 || pil > env->psrpil)) ||
473 type != TT_EXTINT) {
474 env->interrupt_request &= ~CPU_INTERRUPT_HARD;
475 env->exception_index = env->interrupt_index;
476 do_interrupt(env);
477 env->interrupt_index = 0;
478#if !defined(TARGET_SPARC64) && !defined(CONFIG_USER_ONLY)
479 cpu_check_irqs(env);
480#endif
481 next_tb = 0;
482 }
483 } else if (interrupt_request & CPU_INTERRUPT_TIMER) {
484 //do_interrupt(0, 0, 0, 0, 0);
485 env->interrupt_request &= ~CPU_INTERRUPT_TIMER;
486 }
487#elif defined(TARGET_ARM)
488 if (interrupt_request & CPU_INTERRUPT_FIQ
489 && !(env->uncached_cpsr & CPSR_F)) {
490 env->exception_index = EXCP_FIQ;
491 do_interrupt(env);
492 next_tb = 0;
493 }
494 /* ARMv7-M interrupt return works by loading a magic value
495 into the PC. On real hardware the load causes the
496 return to occur. The qemu implementation performs the
497 jump normally, then does the exception return when the
498 CPU tries to execute code at the magic address.
499 This will cause the magic PC value to be pushed to
500 the stack if an interrupt occured at the wrong time.
501 We avoid this by disabling interrupts when
502 pc contains a magic address. */
503 if (interrupt_request & CPU_INTERRUPT_HARD
504 && ((IS_M(env) && env->regs[15] < 0xfffffff0)
505 || !(env->uncached_cpsr & CPSR_I))) {
506 env->exception_index = EXCP_IRQ;
507 do_interrupt(env);
508 next_tb = 0;
509 }
510#elif defined(TARGET_SH4)
511 if (interrupt_request & CPU_INTERRUPT_HARD) {
512 do_interrupt(env);
513 next_tb = 0;
514 }
515#elif defined(TARGET_ALPHA)
516 if (interrupt_request & CPU_INTERRUPT_HARD) {
517 do_interrupt(env);
518 next_tb = 0;
519 }
520#elif defined(TARGET_CRIS)
521 if (interrupt_request & CPU_INTERRUPT_HARD
522 && (env->pregs[PR_CCS] & I_FLAG)) {
523 env->exception_index = EXCP_IRQ;
524 do_interrupt(env);
525 next_tb = 0;
526 }
527 if (interrupt_request & CPU_INTERRUPT_NMI
528 && (env->pregs[PR_CCS] & M_FLAG)) {
529 env->exception_index = EXCP_NMI;
530 do_interrupt(env);
531 next_tb = 0;
532 }
533#elif defined(TARGET_M68K)
534 if (interrupt_request & CPU_INTERRUPT_HARD
535 && ((env->sr & SR_I) >> SR_I_SHIFT)
536 < env->pending_level) {
537 /* Real hardware gets the interrupt vector via an
538 IACK cycle at this point. Current emulated
539 hardware doesn't rely on this, so we
540 provide/save the vector when the interrupt is
541 first signalled. */
542 env->exception_index = env->pending_vector;
543 do_interrupt(1);
544 next_tb = 0;
545 }
546#endif
547 /* Don't use the cached interupt_request value,
548 do_interrupt may have updated the EXITTB flag. */
549 if (env->interrupt_request & CPU_INTERRUPT_EXITTB) {
550 env->interrupt_request &= ~CPU_INTERRUPT_EXITTB;
551 /* ensure that no TB jump will be modified as
552 the program flow was changed */
553 next_tb = 0;
554 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700555 }
556 if (unlikely(env->exit_request)) {
557 env->exit_request = 0;
558 env->exception_index = EXCP_INTERRUPT;
559 cpu_loop_exit();
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800560 }
561#ifdef DEBUG_EXEC
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700562 if (qemu_loglevel_mask(CPU_LOG_TB_CPU)) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800563 /* restore flags in standard format */
564 regs_to_env();
565#if defined(TARGET_I386)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700566 env->eflags = env->eflags | helper_cc_compute_all(CC_OP) | (DF & DF_MASK);
567 log_cpu_state(env, X86_DUMP_CCOP);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800568 env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
569#elif defined(TARGET_ARM)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700570 log_cpu_state(env, 0);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800571#elif defined(TARGET_SPARC)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700572 log_cpu_state(env, 0);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800573#elif defined(TARGET_PPC)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700574 log_cpu_state(env, 0);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800575#elif defined(TARGET_M68K)
576 cpu_m68k_flush_flags(env, env->cc_op);
577 env->cc_op = CC_OP_FLAGS;
578 env->sr = (env->sr & 0xffe0)
579 | env->cc_dest | (env->cc_x << 4);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700580 log_cpu_state(env, 0);
581#elif defined(TARGET_MICROBLAZE)
582 log_cpu_state(env, 0);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800583#elif defined(TARGET_MIPS)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700584 log_cpu_state(env, 0);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800585#elif defined(TARGET_SH4)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700586 log_cpu_state(env, 0);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800587#elif defined(TARGET_ALPHA)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700588 log_cpu_state(env, 0);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800589#elif defined(TARGET_CRIS)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700590 log_cpu_state(env, 0);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800591#else
592#error unsupported target CPU
593#endif
594 }
595#endif
596 spin_lock(&tb_lock);
597 tb = tb_find_fast();
598 /* Note: we do it here to avoid a gcc bug on Mac OS X when
599 doing it in tb_find_slow */
600 if (tb_invalidated_flag) {
601 /* as some TB could have been invalidated because
602 of memory exceptions while generating the code, we
603 must recompute the hash index here */
604 next_tb = 0;
605 tb_invalidated_flag = 0;
606 }
607#ifdef DEBUG_EXEC
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700608 qemu_log_mask(CPU_LOG_EXEC, "Trace 0x%08lx [" TARGET_FMT_lx "] %s\n",
609 (long)tb->tc_ptr, tb->pc,
610 lookup_symbol(tb->pc));
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800611#endif
612 /* see if we can patch the calling TB. When the TB
613 spans two pages, we cannot safely do a direct
614 jump. */
615 {
616 if (next_tb != 0 &&
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700617#ifdef CONFIG_KQEMU
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800618 (env->kqemu_enabled != 2) &&
619#endif
620 tb->page_addr[1] == -1) {
621 tb_add_jump((TranslationBlock *)(next_tb & ~3), next_tb & 3, tb);
622 }
623 }
624 spin_unlock(&tb_lock);
625 env->current_tb = tb;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700626
627 /* cpu_interrupt might be called while translating the
628 TB, but before it is linked into a potentially
629 infinite loop and becomes env->current_tb. Avoid
630 starting execution if there is a pending interrupt. */
631 if (unlikely (env->exit_request))
632 env->current_tb = NULL;
633
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800634 while (env->current_tb) {
635 tc_ptr = tb->tc_ptr;
636 /* execute the generated code */
David 'Digit' Turner2c538c82010-05-10 16:48:20 -0700637#if defined(__sparc__) && !defined(CONFIG_SOLARIS)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800638#undef env
639 env = cpu_single_env;
640#define env cpu_single_env
641#endif
642 next_tb = tcg_qemu_tb_exec(tc_ptr);
643 env->current_tb = NULL;
644 if ((next_tb & 3) == 2) {
645 /* Instruction counter expired. */
646 int insns_left;
647 tb = (TranslationBlock *)(long)(next_tb & ~3);
648 /* Restore PC. */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700649 cpu_pc_from_tb(env, tb);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800650 insns_left = env->icount_decr.u32;
651 if (env->icount_extra && insns_left >= 0) {
652 /* Refill decrementer and continue execution. */
653 env->icount_extra += insns_left;
654 if (env->icount_extra > 0xffff) {
655 insns_left = 0xffff;
656 } else {
657 insns_left = env->icount_extra;
658 }
659 env->icount_extra -= insns_left;
660 env->icount_decr.u16.low = insns_left;
661 } else {
662 if (insns_left > 0) {
663 /* Execute remaining instructions. */
664 cpu_exec_nocache(insns_left, tb);
665 }
666 env->exception_index = EXCP_INTERRUPT;
667 next_tb = 0;
668 cpu_loop_exit();
669 }
670 }
671 }
672 /* reset soft MMU for next block (it can currently
673 only be set by a memory fault) */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700674#if defined(CONFIG_KQEMU)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800675#define MIN_CYCLE_BEFORE_SWITCH (100 * 1000)
676 if (kqemu_is_ok(env) &&
677 (cpu_get_time_fast() - env->last_io_time) >= MIN_CYCLE_BEFORE_SWITCH) {
678 cpu_loop_exit();
679 }
680#endif
681 } /* for(;;) */
682 } else {
683 env_to_regs();
684 }
685 } /* for(;;) */
686
687
688#if defined(TARGET_I386)
689 /* restore flags in standard format */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700690 env->eflags = env->eflags | helper_cc_compute_all(CC_OP) | (DF & DF_MASK);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800691#elif defined(TARGET_ARM)
692 /* XXX: Save/restore host fpu exception state?. */
693#elif defined(TARGET_SPARC)
694#elif defined(TARGET_PPC)
695#elif defined(TARGET_M68K)
696 cpu_m68k_flush_flags(env, env->cc_op);
697 env->cc_op = CC_OP_FLAGS;
698 env->sr = (env->sr & 0xffe0)
699 | env->cc_dest | (env->cc_x << 4);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700700#elif defined(TARGET_MICROBLAZE)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800701#elif defined(TARGET_MIPS)
702#elif defined(TARGET_SH4)
703#elif defined(TARGET_ALPHA)
704#elif defined(TARGET_CRIS)
705 /* XXXXX */
706#else
707#error unsupported target CPU
708#endif
709
710 /* restore global registers */
711#include "hostregs_helper.h"
712
713 /* fail safe : never use cpu_single_env outside cpu_exec() */
714 cpu_single_env = NULL;
715 return ret;
716}
717
718/* must only be called from the generated code as an exception can be
719 generated */
720void tb_invalidate_page_range(target_ulong start, target_ulong end)
721{
722 /* XXX: cannot enable it yet because it yields to MMU exception
723 where NIP != read address on PowerPC */
724#if 0
725 target_ulong phys_addr;
726 phys_addr = get_phys_addr_code(env, start);
727 tb_invalidate_phys_page_range(phys_addr, phys_addr + end - start, 0);
728#endif
729}
730
731#if defined(TARGET_I386) && defined(CONFIG_USER_ONLY)
732
733void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector)
734{
735 CPUX86State *saved_env;
736
737 saved_env = env;
738 env = s;
739 if (!(env->cr[0] & CR0_PE_MASK) || (env->eflags & VM_MASK)) {
740 selector &= 0xffff;
741 cpu_x86_load_seg_cache(env, seg_reg, selector,
742 (selector << 4), 0xffff, 0);
743 } else {
744 helper_load_seg(seg_reg, selector);
745 }
746 env = saved_env;
747}
748
749void cpu_x86_fsave(CPUX86State *s, target_ulong ptr, int data32)
750{
751 CPUX86State *saved_env;
752
753 saved_env = env;
754 env = s;
755
756 helper_fsave(ptr, data32);
757
758 env = saved_env;
759}
760
761void cpu_x86_frstor(CPUX86State *s, target_ulong ptr, int data32)
762{
763 CPUX86State *saved_env;
764
765 saved_env = env;
766 env = s;
767
768 helper_frstor(ptr, data32);
769
770 env = saved_env;
771}
772
773#endif /* TARGET_I386 */
774
775#if !defined(CONFIG_SOFTMMU)
776
777#if defined(TARGET_I386)
778
779/* 'pc' is the host PC at which the exception was raised. 'address' is
780 the effective address of the memory exception. 'is_write' is 1 if a
781 write caused the exception and otherwise 0'. 'old_set' is the
782 signal set which should be restored */
783static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
784 int is_write, sigset_t *old_set,
785 void *puc)
786{
787 TranslationBlock *tb;
788 int ret;
789
790 if (cpu_single_env)
791 env = cpu_single_env; /* XXX: find a correct solution for multithread */
792#if defined(DEBUG_SIGNAL)
793 qemu_printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
794 pc, address, is_write, *(unsigned long *)old_set);
795#endif
796 /* XXX: locking issue */
797 if (is_write && page_unprotect(h2g(address), pc, puc)) {
798 return 1;
799 }
800
801 /* see if it is an MMU fault */
802 ret = cpu_x86_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
803 if (ret < 0)
804 return 0; /* not an MMU fault */
805 if (ret == 0)
806 return 1; /* the MMU fault was handled without causing real CPU fault */
807 /* now we have a real cpu fault */
808 tb = tb_find_pc(pc);
809 if (tb) {
810 /* the PC is inside the translated code. It means that we have
811 a virtual CPU fault */
812 cpu_restore_state(tb, env, pc, puc);
813 }
814 if (ret == 1) {
815#if 0
816 printf("PF exception: EIP=0x%08x CR2=0x%08x error=0x%x\n",
817 env->eip, env->cr[2], env->error_code);
818#endif
819 /* we restore the process signal mask as the sigreturn should
820 do it (XXX: use sigsetjmp) */
821 sigprocmask(SIG_SETMASK, old_set, NULL);
822 raise_exception_err(env->exception_index, env->error_code);
823 } else {
824 /* activate soft MMU for this block */
825 env->hflags |= HF_SOFTMMU_MASK;
826 cpu_resume_from_signal(env, puc);
827 }
828 /* never comes here */
829 return 1;
830}
831
832#elif defined(TARGET_ARM)
833static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
834 int is_write, sigset_t *old_set,
835 void *puc)
836{
837 TranslationBlock *tb;
838 int ret;
839
840 if (cpu_single_env)
841 env = cpu_single_env; /* XXX: find a correct solution for multithread */
842#if defined(DEBUG_SIGNAL)
843 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
844 pc, address, is_write, *(unsigned long *)old_set);
845#endif
846 /* XXX: locking issue */
847 if (is_write && page_unprotect(h2g(address), pc, puc)) {
848 return 1;
849 }
850 /* see if it is an MMU fault */
851 ret = cpu_arm_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
852 if (ret < 0)
853 return 0; /* not an MMU fault */
854 if (ret == 0)
855 return 1; /* the MMU fault was handled without causing real CPU fault */
856 /* now we have a real cpu fault */
857 tb = tb_find_pc(pc);
858 if (tb) {
859 /* the PC is inside the translated code. It means that we have
860 a virtual CPU fault */
861 cpu_restore_state(tb, env, pc, puc);
862 }
863 /* we restore the process signal mask as the sigreturn should
864 do it (XXX: use sigsetjmp) */
865 sigprocmask(SIG_SETMASK, old_set, NULL);
866 cpu_loop_exit();
867 /* never comes here */
868 return 1;
869}
870#elif defined(TARGET_SPARC)
871static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
872 int is_write, sigset_t *old_set,
873 void *puc)
874{
875 TranslationBlock *tb;
876 int ret;
877
878 if (cpu_single_env)
879 env = cpu_single_env; /* XXX: find a correct solution for multithread */
880#if defined(DEBUG_SIGNAL)
881 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
882 pc, address, is_write, *(unsigned long *)old_set);
883#endif
884 /* XXX: locking issue */
885 if (is_write && page_unprotect(h2g(address), pc, puc)) {
886 return 1;
887 }
888 /* see if it is an MMU fault */
889 ret = cpu_sparc_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
890 if (ret < 0)
891 return 0; /* not an MMU fault */
892 if (ret == 0)
893 return 1; /* the MMU fault was handled without causing real CPU fault */
894 /* now we have a real cpu fault */
895 tb = tb_find_pc(pc);
896 if (tb) {
897 /* the PC is inside the translated code. It means that we have
898 a virtual CPU fault */
899 cpu_restore_state(tb, env, pc, puc);
900 }
901 /* we restore the process signal mask as the sigreturn should
902 do it (XXX: use sigsetjmp) */
903 sigprocmask(SIG_SETMASK, old_set, NULL);
904 cpu_loop_exit();
905 /* never comes here */
906 return 1;
907}
908#elif defined (TARGET_PPC)
909static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
910 int is_write, sigset_t *old_set,
911 void *puc)
912{
913 TranslationBlock *tb;
914 int ret;
915
916 if (cpu_single_env)
917 env = cpu_single_env; /* XXX: find a correct solution for multithread */
918#if defined(DEBUG_SIGNAL)
919 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
920 pc, address, is_write, *(unsigned long *)old_set);
921#endif
922 /* XXX: locking issue */
923 if (is_write && page_unprotect(h2g(address), pc, puc)) {
924 return 1;
925 }
926
927 /* see if it is an MMU fault */
928 ret = cpu_ppc_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
929 if (ret < 0)
930 return 0; /* not an MMU fault */
931 if (ret == 0)
932 return 1; /* the MMU fault was handled without causing real CPU fault */
933
934 /* now we have a real cpu fault */
935 tb = tb_find_pc(pc);
936 if (tb) {
937 /* the PC is inside the translated code. It means that we have
938 a virtual CPU fault */
939 cpu_restore_state(tb, env, pc, puc);
940 }
941 if (ret == 1) {
942#if 0
943 printf("PF exception: NIP=0x%08x error=0x%x %p\n",
944 env->nip, env->error_code, tb);
945#endif
946 /* we restore the process signal mask as the sigreturn should
947 do it (XXX: use sigsetjmp) */
948 sigprocmask(SIG_SETMASK, old_set, NULL);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700949 cpu_loop_exit();
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800950 } else {
951 /* activate soft MMU for this block */
952 cpu_resume_from_signal(env, puc);
953 }
954 /* never comes here */
955 return 1;
956}
957
958#elif defined(TARGET_M68K)
959static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
960 int is_write, sigset_t *old_set,
961 void *puc)
962{
963 TranslationBlock *tb;
964 int ret;
965
966 if (cpu_single_env)
967 env = cpu_single_env; /* XXX: find a correct solution for multithread */
968#if defined(DEBUG_SIGNAL)
969 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
970 pc, address, is_write, *(unsigned long *)old_set);
971#endif
972 /* XXX: locking issue */
973 if (is_write && page_unprotect(address, pc, puc)) {
974 return 1;
975 }
976 /* see if it is an MMU fault */
977 ret = cpu_m68k_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
978 if (ret < 0)
979 return 0; /* not an MMU fault */
980 if (ret == 0)
981 return 1; /* the MMU fault was handled without causing real CPU fault */
982 /* now we have a real cpu fault */
983 tb = tb_find_pc(pc);
984 if (tb) {
985 /* the PC is inside the translated code. It means that we have
986 a virtual CPU fault */
987 cpu_restore_state(tb, env, pc, puc);
988 }
989 /* we restore the process signal mask as the sigreturn should
990 do it (XXX: use sigsetjmp) */
991 sigprocmask(SIG_SETMASK, old_set, NULL);
992 cpu_loop_exit();
993 /* never comes here */
994 return 1;
995}
996
997#elif defined (TARGET_MIPS)
998static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
999 int is_write, sigset_t *old_set,
1000 void *puc)
1001{
1002 TranslationBlock *tb;
1003 int ret;
1004
1005 if (cpu_single_env)
1006 env = cpu_single_env; /* XXX: find a correct solution for multithread */
1007#if defined(DEBUG_SIGNAL)
1008 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
1009 pc, address, is_write, *(unsigned long *)old_set);
1010#endif
1011 /* XXX: locking issue */
1012 if (is_write && page_unprotect(h2g(address), pc, puc)) {
1013 return 1;
1014 }
1015
1016 /* see if it is an MMU fault */
1017 ret = cpu_mips_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
1018 if (ret < 0)
1019 return 0; /* not an MMU fault */
1020 if (ret == 0)
1021 return 1; /* the MMU fault was handled without causing real CPU fault */
1022
1023 /* now we have a real cpu fault */
1024 tb = tb_find_pc(pc);
1025 if (tb) {
1026 /* the PC is inside the translated code. It means that we have
1027 a virtual CPU fault */
1028 cpu_restore_state(tb, env, pc, puc);
1029 }
1030 if (ret == 1) {
1031#if 0
1032 printf("PF exception: PC=0x" TARGET_FMT_lx " error=0x%x %p\n",
1033 env->PC, env->error_code, tb);
1034#endif
1035 /* we restore the process signal mask as the sigreturn should
1036 do it (XXX: use sigsetjmp) */
1037 sigprocmask(SIG_SETMASK, old_set, NULL);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001038 cpu_loop_exit();
1039 } else {
1040 /* activate soft MMU for this block */
1041 cpu_resume_from_signal(env, puc);
1042 }
1043 /* never comes here */
1044 return 1;
1045}
1046
1047#elif defined (TARGET_MICROBLAZE)
1048static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
1049 int is_write, sigset_t *old_set,
1050 void *puc)
1051{
1052 TranslationBlock *tb;
1053 int ret;
1054
1055 if (cpu_single_env)
1056 env = cpu_single_env; /* XXX: find a correct solution for multithread */
1057#if defined(DEBUG_SIGNAL)
1058 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
1059 pc, address, is_write, *(unsigned long *)old_set);
1060#endif
1061 /* XXX: locking issue */
1062 if (is_write && page_unprotect(h2g(address), pc, puc)) {
1063 return 1;
1064 }
1065
1066 /* see if it is an MMU fault */
1067 ret = cpu_mb_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
1068 if (ret < 0)
1069 return 0; /* not an MMU fault */
1070 if (ret == 0)
1071 return 1; /* the MMU fault was handled without causing real CPU fault */
1072
1073 /* now we have a real cpu fault */
1074 tb = tb_find_pc(pc);
1075 if (tb) {
1076 /* the PC is inside the translated code. It means that we have
1077 a virtual CPU fault */
1078 cpu_restore_state(tb, env, pc, puc);
1079 }
1080 if (ret == 1) {
1081#if 0
1082 printf("PF exception: PC=0x" TARGET_FMT_lx " error=0x%x %p\n",
1083 env->PC, env->error_code, tb);
1084#endif
1085 /* we restore the process signal mask as the sigreturn should
1086 do it (XXX: use sigsetjmp) */
1087 sigprocmask(SIG_SETMASK, old_set, NULL);
1088 cpu_loop_exit();
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001089 } else {
1090 /* activate soft MMU for this block */
1091 cpu_resume_from_signal(env, puc);
1092 }
1093 /* never comes here */
1094 return 1;
1095}
1096
1097#elif defined (TARGET_SH4)
1098static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
1099 int is_write, sigset_t *old_set,
1100 void *puc)
1101{
1102 TranslationBlock *tb;
1103 int ret;
1104
1105 if (cpu_single_env)
1106 env = cpu_single_env; /* XXX: find a correct solution for multithread */
1107#if defined(DEBUG_SIGNAL)
1108 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
1109 pc, address, is_write, *(unsigned long *)old_set);
1110#endif
1111 /* XXX: locking issue */
1112 if (is_write && page_unprotect(h2g(address), pc, puc)) {
1113 return 1;
1114 }
1115
1116 /* see if it is an MMU fault */
1117 ret = cpu_sh4_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
1118 if (ret < 0)
1119 return 0; /* not an MMU fault */
1120 if (ret == 0)
1121 return 1; /* the MMU fault was handled without causing real CPU fault */
1122
1123 /* now we have a real cpu fault */
1124 tb = tb_find_pc(pc);
1125 if (tb) {
1126 /* the PC is inside the translated code. It means that we have
1127 a virtual CPU fault */
1128 cpu_restore_state(tb, env, pc, puc);
1129 }
1130#if 0
1131 printf("PF exception: NIP=0x%08x error=0x%x %p\n",
1132 env->nip, env->error_code, tb);
1133#endif
1134 /* we restore the process signal mask as the sigreturn should
1135 do it (XXX: use sigsetjmp) */
1136 sigprocmask(SIG_SETMASK, old_set, NULL);
1137 cpu_loop_exit();
1138 /* never comes here */
1139 return 1;
1140}
1141
1142#elif defined (TARGET_ALPHA)
1143static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
1144 int is_write, sigset_t *old_set,
1145 void *puc)
1146{
1147 TranslationBlock *tb;
1148 int ret;
1149
1150 if (cpu_single_env)
1151 env = cpu_single_env; /* XXX: find a correct solution for multithread */
1152#if defined(DEBUG_SIGNAL)
1153 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
1154 pc, address, is_write, *(unsigned long *)old_set);
1155#endif
1156 /* XXX: locking issue */
1157 if (is_write && page_unprotect(h2g(address), pc, puc)) {
1158 return 1;
1159 }
1160
1161 /* see if it is an MMU fault */
1162 ret = cpu_alpha_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
1163 if (ret < 0)
1164 return 0; /* not an MMU fault */
1165 if (ret == 0)
1166 return 1; /* the MMU fault was handled without causing real CPU fault */
1167
1168 /* now we have a real cpu fault */
1169 tb = tb_find_pc(pc);
1170 if (tb) {
1171 /* the PC is inside the translated code. It means that we have
1172 a virtual CPU fault */
1173 cpu_restore_state(tb, env, pc, puc);
1174 }
1175#if 0
1176 printf("PF exception: NIP=0x%08x error=0x%x %p\n",
1177 env->nip, env->error_code, tb);
1178#endif
1179 /* we restore the process signal mask as the sigreturn should
1180 do it (XXX: use sigsetjmp) */
1181 sigprocmask(SIG_SETMASK, old_set, NULL);
1182 cpu_loop_exit();
1183 /* never comes here */
1184 return 1;
1185}
1186#elif defined (TARGET_CRIS)
1187static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
1188 int is_write, sigset_t *old_set,
1189 void *puc)
1190{
1191 TranslationBlock *tb;
1192 int ret;
1193
1194 if (cpu_single_env)
1195 env = cpu_single_env; /* XXX: find a correct solution for multithread */
1196#if defined(DEBUG_SIGNAL)
1197 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
1198 pc, address, is_write, *(unsigned long *)old_set);
1199#endif
1200 /* XXX: locking issue */
1201 if (is_write && page_unprotect(h2g(address), pc, puc)) {
1202 return 1;
1203 }
1204
1205 /* see if it is an MMU fault */
1206 ret = cpu_cris_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
1207 if (ret < 0)
1208 return 0; /* not an MMU fault */
1209 if (ret == 0)
1210 return 1; /* the MMU fault was handled without causing real CPU fault */
1211
1212 /* now we have a real cpu fault */
1213 tb = tb_find_pc(pc);
1214 if (tb) {
1215 /* the PC is inside the translated code. It means that we have
1216 a virtual CPU fault */
1217 cpu_restore_state(tb, env, pc, puc);
1218 }
1219 /* we restore the process signal mask as the sigreturn should
1220 do it (XXX: use sigsetjmp) */
1221 sigprocmask(SIG_SETMASK, old_set, NULL);
1222 cpu_loop_exit();
1223 /* never comes here */
1224 return 1;
1225}
1226
1227#else
1228#error unsupported target CPU
1229#endif
1230
1231#if defined(__i386__)
1232
1233#if defined(__APPLE__)
1234# include <sys/ucontext.h>
1235
1236# define EIP_sig(context) (*((unsigned long*)&(context)->uc_mcontext->ss.eip))
1237# define TRAP_sig(context) ((context)->uc_mcontext->es.trapno)
1238# define ERROR_sig(context) ((context)->uc_mcontext->es.err)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001239# define MASK_sig(context) ((context)->uc_sigmask)
1240#elif defined(__OpenBSD__)
1241# define EIP_sig(context) ((context)->sc_eip)
1242# define TRAP_sig(context) ((context)->sc_trapno)
1243# define ERROR_sig(context) ((context)->sc_err)
1244# define MASK_sig(context) ((context)->sc_mask)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001245#else
1246# define EIP_sig(context) ((context)->uc_mcontext.gregs[REG_EIP])
1247# define TRAP_sig(context) ((context)->uc_mcontext.gregs[REG_TRAPNO])
1248# define ERROR_sig(context) ((context)->uc_mcontext.gregs[REG_ERR])
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001249# define MASK_sig(context) ((context)->uc_sigmask)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001250#endif
1251
1252int cpu_signal_handler(int host_signum, void *pinfo,
1253 void *puc)
1254{
1255 siginfo_t *info = pinfo;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001256#if defined(__OpenBSD__)
1257 struct sigcontext *uc = puc;
1258#else
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001259 struct ucontext *uc = puc;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001260#endif
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001261 unsigned long pc;
1262 int trapno;
1263
1264#ifndef REG_EIP
1265/* for glibc 2.1 */
1266#define REG_EIP EIP
1267#define REG_ERR ERR
1268#define REG_TRAPNO TRAPNO
1269#endif
1270 pc = EIP_sig(uc);
1271 trapno = TRAP_sig(uc);
1272 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1273 trapno == 0xe ?
1274 (ERROR_sig(uc) >> 1) & 1 : 0,
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001275 &MASK_sig(uc), puc);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001276}
1277
1278#elif defined(__x86_64__)
1279
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001280#ifdef __NetBSD__
1281#define PC_sig(context) _UC_MACHINE_PC(context)
1282#define TRAP_sig(context) ((context)->uc_mcontext.__gregs[_REG_TRAPNO])
1283#define ERROR_sig(context) ((context)->uc_mcontext.__gregs[_REG_ERR])
1284#define MASK_sig(context) ((context)->uc_sigmask)
1285#elif defined(__OpenBSD__)
1286#define PC_sig(context) ((context)->sc_rip)
1287#define TRAP_sig(context) ((context)->sc_trapno)
1288#define ERROR_sig(context) ((context)->sc_err)
1289#define MASK_sig(context) ((context)->sc_mask)
1290#else
1291#define PC_sig(context) ((context)->uc_mcontext.gregs[REG_RIP])
1292#define TRAP_sig(context) ((context)->uc_mcontext.gregs[REG_TRAPNO])
1293#define ERROR_sig(context) ((context)->uc_mcontext.gregs[REG_ERR])
1294#define MASK_sig(context) ((context)->uc_sigmask)
1295#endif
1296
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001297int cpu_signal_handler(int host_signum, void *pinfo,
1298 void *puc)
1299{
1300 siginfo_t *info = pinfo;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001301 unsigned long pc;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001302#ifdef __NetBSD__
1303 ucontext_t *uc = puc;
1304#elif defined(__OpenBSD__)
1305 struct sigcontext *uc = puc;
1306#else
1307 struct ucontext *uc = puc;
1308#endif
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001309
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001310 pc = PC_sig(uc);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001311 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001312 TRAP_sig(uc) == 0xe ?
1313 (ERROR_sig(uc) >> 1) & 1 : 0,
1314 &MASK_sig(uc), puc);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001315}
1316
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001317#elif defined(_ARCH_PPC)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001318
1319/***********************************************************************
1320 * signal context platform-specific definitions
1321 * From Wine
1322 */
1323#ifdef linux
1324/* All Registers access - only for local access */
1325# define REG_sig(reg_name, context) ((context)->uc_mcontext.regs->reg_name)
1326/* Gpr Registers access */
1327# define GPR_sig(reg_num, context) REG_sig(gpr[reg_num], context)
1328# define IAR_sig(context) REG_sig(nip, context) /* Program counter */
1329# define MSR_sig(context) REG_sig(msr, context) /* Machine State Register (Supervisor) */
1330# define CTR_sig(context) REG_sig(ctr, context) /* Count register */
1331# define XER_sig(context) REG_sig(xer, context) /* User's integer exception register */
1332# define LR_sig(context) REG_sig(link, context) /* Link register */
1333# define CR_sig(context) REG_sig(ccr, context) /* Condition register */
1334/* Float Registers access */
1335# define FLOAT_sig(reg_num, context) (((double*)((char*)((context)->uc_mcontext.regs+48*4)))[reg_num])
1336# define FPSCR_sig(context) (*(int*)((char*)((context)->uc_mcontext.regs+(48+32*2)*4)))
1337/* Exception Registers access */
1338# define DAR_sig(context) REG_sig(dar, context)
1339# define DSISR_sig(context) REG_sig(dsisr, context)
1340# define TRAP_sig(context) REG_sig(trap, context)
1341#endif /* linux */
1342
1343#ifdef __APPLE__
1344# include <sys/ucontext.h>
1345typedef struct ucontext SIGCONTEXT;
1346/* All Registers access - only for local access */
1347# define REG_sig(reg_name, context) ((context)->uc_mcontext->ss.reg_name)
1348# define FLOATREG_sig(reg_name, context) ((context)->uc_mcontext->fs.reg_name)
1349# define EXCEPREG_sig(reg_name, context) ((context)->uc_mcontext->es.reg_name)
1350# define VECREG_sig(reg_name, context) ((context)->uc_mcontext->vs.reg_name)
1351/* Gpr Registers access */
1352# define GPR_sig(reg_num, context) REG_sig(r##reg_num, context)
1353# define IAR_sig(context) REG_sig(srr0, context) /* Program counter */
1354# define MSR_sig(context) REG_sig(srr1, context) /* Machine State Register (Supervisor) */
1355# define CTR_sig(context) REG_sig(ctr, context)
1356# define XER_sig(context) REG_sig(xer, context) /* Link register */
1357# define LR_sig(context) REG_sig(lr, context) /* User's integer exception register */
1358# define CR_sig(context) REG_sig(cr, context) /* Condition register */
1359/* Float Registers access */
1360# define FLOAT_sig(reg_num, context) FLOATREG_sig(fpregs[reg_num], context)
1361# define FPSCR_sig(context) ((double)FLOATREG_sig(fpscr, context))
1362/* Exception Registers access */
1363# define DAR_sig(context) EXCEPREG_sig(dar, context) /* Fault registers for coredump */
1364# define DSISR_sig(context) EXCEPREG_sig(dsisr, context)
1365# define TRAP_sig(context) EXCEPREG_sig(exception, context) /* number of powerpc exception taken */
1366#endif /* __APPLE__ */
1367
1368int cpu_signal_handler(int host_signum, void *pinfo,
1369 void *puc)
1370{
1371 siginfo_t *info = pinfo;
1372 struct ucontext *uc = puc;
1373 unsigned long pc;
1374 int is_write;
1375
1376 pc = IAR_sig(uc);
1377 is_write = 0;
1378#if 0
1379 /* ppc 4xx case */
1380 if (DSISR_sig(uc) & 0x00800000)
1381 is_write = 1;
1382#else
1383 if (TRAP_sig(uc) != 0x400 && (DSISR_sig(uc) & 0x02000000))
1384 is_write = 1;
1385#endif
1386 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1387 is_write, &uc->uc_sigmask, puc);
1388}
1389
1390#elif defined(__alpha__)
1391
1392int cpu_signal_handler(int host_signum, void *pinfo,
1393 void *puc)
1394{
1395 siginfo_t *info = pinfo;
1396 struct ucontext *uc = puc;
1397 uint32_t *pc = uc->uc_mcontext.sc_pc;
1398 uint32_t insn = *pc;
1399 int is_write = 0;
1400
1401 /* XXX: need kernel patch to get write flag faster */
1402 switch (insn >> 26) {
1403 case 0x0d: // stw
1404 case 0x0e: // stb
1405 case 0x0f: // stq_u
1406 case 0x24: // stf
1407 case 0x25: // stg
1408 case 0x26: // sts
1409 case 0x27: // stt
1410 case 0x2c: // stl
1411 case 0x2d: // stq
1412 case 0x2e: // stl_c
1413 case 0x2f: // stq_c
1414 is_write = 1;
1415 }
1416
1417 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1418 is_write, &uc->uc_sigmask, puc);
1419}
1420#elif defined(__sparc__)
1421
1422int cpu_signal_handler(int host_signum, void *pinfo,
1423 void *puc)
1424{
1425 siginfo_t *info = pinfo;
1426 int is_write;
1427 uint32_t insn;
David 'Digit' Turner2c538c82010-05-10 16:48:20 -07001428#if !defined(__arch64__) || defined(CONFIG_SOLARIS)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001429 uint32_t *regs = (uint32_t *)(info + 1);
1430 void *sigmask = (regs + 20);
1431 /* XXX: is there a standard glibc define ? */
1432 unsigned long pc = regs[1];
1433#else
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001434#ifdef __linux__
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001435 struct sigcontext *sc = puc;
1436 unsigned long pc = sc->sigc_regs.tpc;
1437 void *sigmask = (void *)sc->sigc_mask;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001438#elif defined(__OpenBSD__)
1439 struct sigcontext *uc = puc;
1440 unsigned long pc = uc->sc_pc;
1441 void *sigmask = (void *)(long)uc->sc_mask;
1442#endif
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001443#endif
1444
1445 /* XXX: need kernel patch to get write flag faster */
1446 is_write = 0;
1447 insn = *(uint32_t *)pc;
1448 if ((insn >> 30) == 3) {
1449 switch((insn >> 19) & 0x3f) {
1450 case 0x05: // stb
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001451 case 0x15: // stba
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001452 case 0x06: // sth
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001453 case 0x16: // stha
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001454 case 0x04: // st
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001455 case 0x14: // sta
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001456 case 0x07: // std
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001457 case 0x17: // stda
1458 case 0x0e: // stx
1459 case 0x1e: // stxa
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001460 case 0x24: // stf
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001461 case 0x34: // stfa
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001462 case 0x27: // stdf
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001463 case 0x37: // stdfa
1464 case 0x26: // stqf
1465 case 0x36: // stqfa
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001466 case 0x25: // stfsr
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001467 case 0x3c: // casa
1468 case 0x3e: // casxa
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001469 is_write = 1;
1470 break;
1471 }
1472 }
1473 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1474 is_write, sigmask, NULL);
1475}
1476
1477#elif defined(__arm__)
1478
1479int cpu_signal_handler(int host_signum, void *pinfo,
1480 void *puc)
1481{
1482 siginfo_t *info = pinfo;
1483 struct ucontext *uc = puc;
1484 unsigned long pc;
1485 int is_write;
1486
1487#if (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ <= 3))
1488 pc = uc->uc_mcontext.gregs[R15];
1489#else
1490 pc = uc->uc_mcontext.arm_pc;
1491#endif
1492 /* XXX: compute is_write */
1493 is_write = 0;
1494 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1495 is_write,
1496 &uc->uc_sigmask, puc);
1497}
1498
1499#elif defined(__mc68000)
1500
1501int cpu_signal_handler(int host_signum, void *pinfo,
1502 void *puc)
1503{
1504 siginfo_t *info = pinfo;
1505 struct ucontext *uc = puc;
1506 unsigned long pc;
1507 int is_write;
1508
1509 pc = uc->uc_mcontext.gregs[16];
1510 /* XXX: compute is_write */
1511 is_write = 0;
1512 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1513 is_write,
1514 &uc->uc_sigmask, puc);
1515}
1516
1517#elif defined(__ia64)
1518
1519#ifndef __ISR_VALID
1520 /* This ought to be in <bits/siginfo.h>... */
1521# define __ISR_VALID 1
1522#endif
1523
1524int cpu_signal_handler(int host_signum, void *pinfo, void *puc)
1525{
1526 siginfo_t *info = pinfo;
1527 struct ucontext *uc = puc;
1528 unsigned long ip;
1529 int is_write = 0;
1530
1531 ip = uc->uc_mcontext.sc_ip;
1532 switch (host_signum) {
1533 case SIGILL:
1534 case SIGFPE:
1535 case SIGSEGV:
1536 case SIGBUS:
1537 case SIGTRAP:
1538 if (info->si_code && (info->si_segvflags & __ISR_VALID))
1539 /* ISR.W (write-access) is bit 33: */
1540 is_write = (info->si_isr >> 33) & 1;
1541 break;
1542
1543 default:
1544 break;
1545 }
1546 return handle_cpu_signal(ip, (unsigned long)info->si_addr,
1547 is_write,
1548 &uc->uc_sigmask, puc);
1549}
1550
1551#elif defined(__s390__)
1552
1553int cpu_signal_handler(int host_signum, void *pinfo,
1554 void *puc)
1555{
1556 siginfo_t *info = pinfo;
1557 struct ucontext *uc = puc;
1558 unsigned long pc;
1559 int is_write;
1560
1561 pc = uc->uc_mcontext.psw.addr;
1562 /* XXX: compute is_write */
1563 is_write = 0;
1564 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1565 is_write, &uc->uc_sigmask, puc);
1566}
1567
1568#elif defined(__mips__)
1569
1570int cpu_signal_handler(int host_signum, void *pinfo,
1571 void *puc)
1572{
1573 siginfo_t *info = pinfo;
1574 struct ucontext *uc = puc;
1575 greg_t pc = uc->uc_mcontext.pc;
1576 int is_write;
1577
1578 /* XXX: compute is_write */
1579 is_write = 0;
1580 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1581 is_write, &uc->uc_sigmask, puc);
1582}
1583
1584#elif defined(__hppa__)
1585
1586int cpu_signal_handler(int host_signum, void *pinfo,
1587 void *puc)
1588{
1589 struct siginfo *info = pinfo;
1590 struct ucontext *uc = puc;
1591 unsigned long pc;
1592 int is_write;
1593
1594 pc = uc->uc_mcontext.sc_iaoq[0];
1595 /* FIXME: compute is_write */
1596 is_write = 0;
1597 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1598 is_write,
1599 &uc->uc_sigmask, puc);
1600}
1601
1602#else
1603
1604#error host CPU specific signal handler needed
1605
1606#endif
1607
1608#endif /* !defined(CONFIG_SOFTMMU) */