Annotation of qemu/cpu-exec.c, revision 1.1.1.15
1.1 root 1: /*
2: * i386 emulator main execution loop
1.1.1.6 root 3: *
1.1 root 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
1.1.1.9 root 17: * License along with this library; if not, see <http://www.gnu.org/licenses/>.
1.1 root 18: */
19: #include "config.h"
1.1.1.14 root 20: #include "cpu.h"
1.1 root 21: #include "disas.h"
1.1.1.7 root 22: #include "tcg.h"
1.1.1.12 root 23: #include "qemu-barrier.h"
1.1 root 24:
1.1.1.7 root 25: int tb_invalidated_flag;
1.1.1.6 root 26:
1.1.1.10 root 27: //#define CONFIG_DEBUG_EXEC
1.1.1.6 root 28:
1.1.1.14 root 29: bool qemu_cpu_has_work(CPUState *env)
1.1.1.9 root 30: {
31: return cpu_has_work(env);
32: }
33:
1.1.1.14 root 34: void cpu_loop_exit(CPUState *env)
1.1 root 35: {
1.1.1.12 root 36: env->current_tb = NULL;
1.1 root 37: longjmp(env->jmp_env, 1);
38: }
1.1.1.6 root 39:
1.1 root 40: /* exit the current TB from a signal handler. The host registers are
41: restored in a state compatible with the CPU emulator
42: */
1.1.1.14 root 43: #if defined(CONFIG_SOFTMMU)
44: void cpu_resume_from_signal(CPUState *env, void *puc)
1.1 root 45: {
46: /* XXX: restore cpu registers saved in host registers */
47:
1.1.1.7 root 48: env->exception_index = -1;
1.1 root 49: longjmp(env->jmp_env, 1);
50: }
1.1.1.14 root 51: #endif
1.1 root 52:
1.1.1.7 root 53: /* Execute the code without caching the generated code. An interpreter
54: could be used if available. */
1.1.1.14 root 55: static void cpu_exec_nocache(CPUState *env, int max_cycles,
56: TranslationBlock *orig_tb)
1.1.1.7 root 57: {
58: unsigned long next_tb;
59: TranslationBlock *tb;
60:
61: /* Should never happen.
62: We only end up here when an existing TB is too long. */
63: if (max_cycles > CF_COUNT_MASK)
64: max_cycles = CF_COUNT_MASK;
65:
66: tb = tb_gen_code(env, orig_tb->pc, orig_tb->cs_base, orig_tb->flags,
67: max_cycles);
68: env->current_tb = tb;
69: /* execute the generated code */
1.1.1.14 root 70: next_tb = tcg_qemu_tb_exec(env, tb->tc_ptr);
1.1.1.12 root 71: env->current_tb = NULL;
1.1.1.7 root 72:
73: if ((next_tb & 3) == 2) {
74: /* Restore PC. This may happen if async event occurs before
75: the TB starts executing. */
76: cpu_pc_from_tb(env, tb);
77: }
78: tb_phys_invalidate(tb, -1);
79: tb_free(tb);
80: }
1.1.1.2 root 81:
1.1.1.14 root 82: static TranslationBlock *tb_find_slow(CPUState *env,
83: target_ulong pc,
1.1.1.2 root 84: target_ulong cs_base,
1.1.1.6 root 85: uint64_t flags)
1.1.1.2 root 86: {
87: TranslationBlock *tb, **ptb1;
88: unsigned int h;
1.1.1.15! root 89: tb_page_addr_t phys_pc, phys_page1;
1.1.1.12 root 90: target_ulong virt_page2;
1.1.1.2 root 91:
92: tb_invalidated_flag = 0;
1.1.1.6 root 93:
1.1.1.2 root 94: /* find translated block using physical mappings */
1.1.1.12 root 95: phys_pc = get_page_addr_code(env, pc);
1.1.1.2 root 96: phys_page1 = phys_pc & TARGET_PAGE_MASK;
97: h = tb_phys_hash_func(phys_pc);
98: ptb1 = &tb_phys_hash[h];
99: for(;;) {
100: tb = *ptb1;
101: if (!tb)
102: goto not_found;
1.1.1.6 root 103: if (tb->pc == pc &&
1.1.1.2 root 104: tb->page_addr[0] == phys_page1 &&
1.1.1.6 root 105: tb->cs_base == cs_base &&
1.1.1.2 root 106: tb->flags == flags) {
107: /* check next page if needed */
108: if (tb->page_addr[1] != -1) {
1.1.1.15! root 109: tb_page_addr_t phys_page2;
! 110:
1.1.1.6 root 111: virt_page2 = (pc & TARGET_PAGE_MASK) +
1.1.1.2 root 112: TARGET_PAGE_SIZE;
1.1.1.12 root 113: phys_page2 = get_page_addr_code(env, virt_page2);
1.1.1.2 root 114: if (tb->page_addr[1] == phys_page2)
115: goto found;
116: } else {
117: goto found;
118: }
119: }
120: ptb1 = &tb->phys_hash_next;
121: }
122: not_found:
1.1.1.7 root 123: /* if no translated code available, then translate it now */
124: tb = tb_gen_code(env, pc, cs_base, flags, 0);
1.1.1.6 root 125:
1.1.1.2 root 126: found:
1.1.1.13 root 127: /* Move the last found TB to the head of the list */
128: if (likely(*ptb1)) {
129: *ptb1 = tb->phys_hash_next;
130: tb->phys_hash_next = tb_phys_hash[h];
131: tb_phys_hash[h] = tb;
132: }
1.1.1.2 root 133: /* we add the TB in the virtual pc hash table */
134: env->tb_jmp_cache[tb_jmp_cache_hash_func(pc)] = tb;
135: return tb;
136: }
137:
1.1.1.14 root 138: static inline TranslationBlock *tb_find_fast(CPUState *env)
1.1.1.2 root 139: {
140: TranslationBlock *tb;
141: target_ulong cs_base, pc;
1.1.1.7 root 142: int flags;
1.1.1.2 root 143:
144: /* we record a subset of the CPU state. It will
145: always be the same before a given translated block
146: is executed. */
1.1.1.7 root 147: cpu_get_tb_cpu_state(env, &pc, &cs_base, &flags);
1.1.1.2 root 148: tb = env->tb_jmp_cache[tb_jmp_cache_hash_func(pc)];
1.1.1.7 root 149: if (unlikely(!tb || tb->pc != pc || tb->cs_base != cs_base ||
150: tb->flags != flags)) {
1.1.1.14 root 151: tb = tb_find_slow(env, pc, cs_base, flags);
1.1.1.2 root 152: }
153: return tb;
154: }
155:
1.1.1.7 root 156: static CPUDebugExcpHandler *debug_excp_handler;
157:
158: CPUDebugExcpHandler *cpu_set_debug_excp_handler(CPUDebugExcpHandler *handler)
159: {
160: CPUDebugExcpHandler *old_handler = debug_excp_handler;
161:
162: debug_excp_handler = handler;
163: return old_handler;
164: }
165:
166: static void cpu_handle_debug_exception(CPUState *env)
167: {
168: CPUWatchpoint *wp;
169:
1.1.1.14 root 170: if (!env->watchpoint_hit) {
171: QTAILQ_FOREACH(wp, &env->watchpoints, entry) {
1.1.1.7 root 172: wp->flags &= ~BP_WATCHPOINT_HIT;
1.1.1.14 root 173: }
174: }
175: if (debug_excp_handler) {
1.1.1.7 root 176: debug_excp_handler(env);
1.1.1.14 root 177: }
1.1.1.7 root 178: }
1.1.1.2 root 179:
1.1 root 180: /* main execution loop */
181:
1.1.1.12 root 182: volatile sig_atomic_t exit_request;
183:
1.1.1.14 root 184: int cpu_exec(CPUState *env)
1.1 root 185: {
1.1.1.2 root 186: int ret, interrupt_request;
187: TranslationBlock *tb;
1.1 root 188: uint8_t *tc_ptr;
1.1.1.7 root 189: unsigned long next_tb;
1.1.1.2 root 190:
1.1.1.14 root 191: if (env->halted) {
192: if (!cpu_has_work(env)) {
193: return EXCP_HALTED;
194: }
1.1.1.2 root 195:
1.1.1.14 root 196: env->halted = 0;
197: }
1.1 root 198:
1.1.1.14 root 199: cpu_single_env = env;
1.1 root 200:
1.1.1.12 root 201: if (unlikely(exit_request)) {
202: env->exit_request = 1;
203: }
204:
1.1.1.6 root 205: #if defined(TARGET_I386)
1.1.1.14 root 206: /* put eflags in CPU temporary format */
207: CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
208: DF = 1 - (2 * ((env->eflags >> 10) & 1));
209: CC_OP = CC_OP_EFLAGS;
210: env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
1.1 root 211: #elif defined(TARGET_SPARC)
1.1.1.5 root 212: #elif defined(TARGET_M68K)
213: env->cc_op = CC_OP_FLAGS;
214: env->cc_dest = env->sr & 0xf;
215: env->cc_x = (env->sr >> 4) & 1;
1.1.1.6 root 216: #elif defined(TARGET_ALPHA)
217: #elif defined(TARGET_ARM)
1.1.1.14 root 218: #elif defined(TARGET_UNICORE32)
1.1.1.6 root 219: #elif defined(TARGET_PPC)
1.1.1.15! root 220: env->reserve_addr = -1;
1.1.1.14 root 221: #elif defined(TARGET_LM32)
1.1.1.9 root 222: #elif defined(TARGET_MICROBLAZE)
1.1 root 223: #elif defined(TARGET_MIPS)
1.1.1.3 root 224: #elif defined(TARGET_SH4)
1.1.1.6 root 225: #elif defined(TARGET_CRIS)
1.1.1.10 root 226: #elif defined(TARGET_S390X)
1.1.1.15! root 227: #elif defined(TARGET_XTENSA)
1.1.1.3 root 228: /* XXXXX */
1.1 root 229: #else
230: #error unsupported target CPU
231: #endif
232: env->exception_index = -1;
233:
234: /* prepare setjmp context for exception handling */
235: for(;;) {
236: if (setjmp(env->jmp_env) == 0) {
237: /* if an exception is pending, we execute it here */
238: if (env->exception_index >= 0) {
239: if (env->exception_index >= EXCP_INTERRUPT) {
240: /* exit request from the cpu execution loop */
241: ret = env->exception_index;
1.1.1.14 root 242: if (ret == EXCP_DEBUG) {
1.1.1.7 root 243: cpu_handle_debug_exception(env);
1.1.1.14 root 244: }
1.1 root 245: break;
1.1.1.7 root 246: } else {
247: #if defined(CONFIG_USER_ONLY)
1.1 root 248: /* if user mode only, we simulate a fake exception
1.1.1.5 root 249: which will be handled outside the cpu execution
1.1 root 250: loop */
251: #if defined(TARGET_I386)
1.1.1.14 root 252: do_interrupt(env);
1.1 root 253: #endif
254: ret = env->exception_index;
255: break;
1.1.1.7 root 256: #else
257: do_interrupt(env);
1.1.1.12 root 258: env->exception_index = -1;
1.1.1.7 root 259: #endif
1.1 root 260: }
1.1.1.6 root 261: }
1.1 root 262:
1.1.1.7 root 263: next_tb = 0; /* force lookup of first TB */
1.1 root 264: for(;;) {
265: interrupt_request = env->interrupt_request;
1.1.1.7 root 266: if (unlikely(interrupt_request)) {
267: if (unlikely(env->singlestep_enabled & SSTEP_NOIRQ)) {
268: /* Mask out external interrupts for this step. */
1.1.1.14 root 269: interrupt_request &= ~CPU_INTERRUPT_SSTEP_MASK;
1.1.1.7 root 270: }
1.1.1.6 root 271: if (interrupt_request & CPU_INTERRUPT_DEBUG) {
272: env->interrupt_request &= ~CPU_INTERRUPT_DEBUG;
273: env->exception_index = EXCP_DEBUG;
1.1.1.14 root 274: cpu_loop_exit(env);
1.1.1.6 root 275: }
276: #if defined(TARGET_ARM) || defined(TARGET_SPARC) || defined(TARGET_MIPS) || \
1.1.1.9 root 277: defined(TARGET_PPC) || defined(TARGET_ALPHA) || defined(TARGET_CRIS) || \
1.1.1.14 root 278: defined(TARGET_MICROBLAZE) || defined(TARGET_LM32) || defined(TARGET_UNICORE32)
1.1.1.6 root 279: if (interrupt_request & CPU_INTERRUPT_HALT) {
280: env->interrupt_request &= ~CPU_INTERRUPT_HALT;
281: env->halted = 1;
282: env->exception_index = EXCP_HLT;
1.1.1.14 root 283: cpu_loop_exit(env);
1.1.1.6 root 284: }
285: #endif
1.1 root 286: #if defined(TARGET_I386)
1.1.1.9 root 287: if (interrupt_request & CPU_INTERRUPT_INIT) {
1.1.1.14 root 288: svm_check_intercept(env, SVM_EXIT_INIT);
1.1.1.9 root 289: do_cpu_init(env);
290: env->exception_index = EXCP_HALTED;
1.1.1.14 root 291: cpu_loop_exit(env);
1.1.1.9 root 292: } else if (interrupt_request & CPU_INTERRUPT_SIPI) {
293: do_cpu_sipi(env);
294: } else if (env->hflags2 & HF2_GIF_MASK) {
1.1.1.7 root 295: if ((interrupt_request & CPU_INTERRUPT_SMI) &&
296: !(env->hflags & HF_SMM_MASK)) {
1.1.1.14 root 297: svm_check_intercept(env, SVM_EXIT_SMI);
1.1.1.7 root 298: env->interrupt_request &= ~CPU_INTERRUPT_SMI;
1.1.1.14 root 299: do_smm_enter(env);
1.1.1.7 root 300: next_tb = 0;
301: } else if ((interrupt_request & CPU_INTERRUPT_NMI) &&
302: !(env->hflags2 & HF2_NMI_MASK)) {
303: env->interrupt_request &= ~CPU_INTERRUPT_NMI;
304: env->hflags2 |= HF2_NMI_MASK;
1.1.1.14 root 305: do_interrupt_x86_hardirq(env, EXCP02_NMI, 1);
1.1.1.7 root 306: next_tb = 0;
1.1.1.9 root 307: } else if (interrupt_request & CPU_INTERRUPT_MCE) {
308: env->interrupt_request &= ~CPU_INTERRUPT_MCE;
1.1.1.14 root 309: do_interrupt_x86_hardirq(env, EXCP12_MCHK, 0);
1.1.1.9 root 310: next_tb = 0;
1.1.1.7 root 311: } else if ((interrupt_request & CPU_INTERRUPT_HARD) &&
312: (((env->hflags2 & HF2_VINTR_MASK) &&
313: (env->hflags2 & HF2_HIF_MASK)) ||
314: (!(env->hflags2 & HF2_VINTR_MASK) &&
315: (env->eflags & IF_MASK &&
316: !(env->hflags & HF_INHIBIT_IRQ_MASK))))) {
317: int intno;
1.1.1.14 root 318: svm_check_intercept(env, SVM_EXIT_INTR);
1.1.1.7 root 319: env->interrupt_request &= ~(CPU_INTERRUPT_HARD | CPU_INTERRUPT_VIRQ);
320: intno = cpu_get_pic_interrupt(env);
321: qemu_log_mask(CPU_LOG_TB_IN_ASM, "Servicing hardware INT=0x%02x\n", intno);
1.1.1.14 root 322: do_interrupt_x86_hardirq(env, intno, 1);
1.1.1.7 root 323: /* ensure that no TB jump will be modified as
324: the program flow was changed */
325: next_tb = 0;
1.1.1.6 root 326: #if !defined(CONFIG_USER_ONLY)
1.1.1.7 root 327: } else if ((interrupt_request & CPU_INTERRUPT_VIRQ) &&
328: (env->eflags & IF_MASK) &&
329: !(env->hflags & HF_INHIBIT_IRQ_MASK)) {
330: int intno;
331: /* FIXME: this should respect TPR */
1.1.1.14 root 332: svm_check_intercept(env, SVM_EXIT_VINTR);
1.1.1.7 root 333: intno = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_vector));
334: qemu_log_mask(CPU_LOG_TB_IN_ASM, "Servicing virtual hardware INT=0x%02x\n", intno);
1.1.1.14 root 335: do_interrupt_x86_hardirq(env, intno, 1);
1.1.1.7 root 336: env->interrupt_request &= ~CPU_INTERRUPT_VIRQ;
337: next_tb = 0;
1.1 root 338: #endif
1.1.1.7 root 339: }
1.1 root 340: }
341: #elif defined(TARGET_PPC)
342: #if 0
343: if ((interrupt_request & CPU_INTERRUPT_RESET)) {
1.1.1.10 root 344: cpu_reset(env);
1.1 root 345: }
346: #endif
1.1.1.6 root 347: if (interrupt_request & CPU_INTERRUPT_HARD) {
348: ppc_hw_interrupt(env);
349: if (env->pending_interrupts == 0)
1.1.1.2 root 350: env->interrupt_request &= ~CPU_INTERRUPT_HARD;
1.1.1.7 root 351: next_tb = 0;
1.1 root 352: }
1.1.1.14 root 353: #elif defined(TARGET_LM32)
354: if ((interrupt_request & CPU_INTERRUPT_HARD)
355: && (env->ie & IE_IE)) {
356: env->exception_index = EXCP_IRQ;
357: do_interrupt(env);
358: next_tb = 0;
359: }
1.1.1.9 root 360: #elif defined(TARGET_MICROBLAZE)
361: if ((interrupt_request & CPU_INTERRUPT_HARD)
362: && (env->sregs[SR_MSR] & MSR_IE)
363: && !(env->sregs[SR_MSR] & (MSR_EIP | MSR_BIP))
364: && !(env->iflags & (D_FLAG | IMM_FLAG))) {
365: env->exception_index = EXCP_IRQ;
366: do_interrupt(env);
367: next_tb = 0;
368: }
1.1 root 369: #elif defined(TARGET_MIPS)
370: if ((interrupt_request & CPU_INTERRUPT_HARD) &&
1.1.1.13 root 371: cpu_mips_hw_interrupts_pending(env)) {
1.1 root 372: /* Raise it */
373: env->exception_index = EXCP_EXT_INTERRUPT;
374: env->error_code = 0;
375: do_interrupt(env);
1.1.1.7 root 376: next_tb = 0;
1.1 root 377: }
378: #elif defined(TARGET_SPARC)
1.1.1.12 root 379: if (interrupt_request & CPU_INTERRUPT_HARD) {
380: if (cpu_interrupts_enabled(env) &&
381: env->interrupt_index > 0) {
382: int pil = env->interrupt_index & 0xf;
383: int type = env->interrupt_index & 0xf0;
384:
385: if (((type == TT_EXTINT) &&
386: cpu_pil_allowed(env, pil)) ||
387: type != TT_EXTINT) {
388: env->exception_index = env->interrupt_index;
389: do_interrupt(env);
390: next_tb = 0;
391: }
392: }
1.1.1.6 root 393: }
1.1.1.2 root 394: #elif defined(TARGET_ARM)
395: if (interrupt_request & CPU_INTERRUPT_FIQ
396: && !(env->uncached_cpsr & CPSR_F)) {
397: env->exception_index = EXCP_FIQ;
398: do_interrupt(env);
1.1.1.7 root 399: next_tb = 0;
1.1.1.2 root 400: }
1.1.1.6 root 401: /* ARMv7-M interrupt return works by loading a magic value
402: into the PC. On real hardware the load causes the
403: return to occur. The qemu implementation performs the
404: jump normally, then does the exception return when the
405: CPU tries to execute code at the magic address.
406: This will cause the magic PC value to be pushed to
1.1.1.14 root 407: the stack if an interrupt occurred at the wrong time.
1.1.1.6 root 408: We avoid this by disabling interrupts when
409: pc contains a magic address. */
1.1.1.2 root 410: if (interrupt_request & CPU_INTERRUPT_HARD
1.1.1.6 root 411: && ((IS_M(env) && env->regs[15] < 0xfffffff0)
412: || !(env->uncached_cpsr & CPSR_I))) {
1.1.1.2 root 413: env->exception_index = EXCP_IRQ;
414: do_interrupt(env);
1.1.1.7 root 415: next_tb = 0;
1.1.1.2 root 416: }
1.1.1.14 root 417: #elif defined(TARGET_UNICORE32)
418: if (interrupt_request & CPU_INTERRUPT_HARD
419: && !(env->uncached_asr & ASR_I)) {
1.1.1.6 root 420: do_interrupt(env);
1.1.1.7 root 421: next_tb = 0;
1.1.1.6 root 422: }
1.1.1.14 root 423: #elif defined(TARGET_SH4)
1.1.1.6 root 424: if (interrupt_request & CPU_INTERRUPT_HARD) {
425: do_interrupt(env);
1.1.1.7 root 426: next_tb = 0;
1.1.1.6 root 427: }
1.1.1.14 root 428: #elif defined(TARGET_ALPHA)
429: {
430: int idx = -1;
431: /* ??? This hard-codes the OSF/1 interrupt levels. */
432: switch (env->pal_mode ? 7 : env->ps & PS_INT_MASK) {
433: case 0 ... 3:
434: if (interrupt_request & CPU_INTERRUPT_HARD) {
435: idx = EXCP_DEV_INTERRUPT;
436: }
437: /* FALLTHRU */
438: case 4:
439: if (interrupt_request & CPU_INTERRUPT_TIMER) {
440: idx = EXCP_CLK_INTERRUPT;
441: }
442: /* FALLTHRU */
443: case 5:
444: if (interrupt_request & CPU_INTERRUPT_SMP) {
445: idx = EXCP_SMP_INTERRUPT;
446: }
447: /* FALLTHRU */
448: case 6:
449: if (interrupt_request & CPU_INTERRUPT_MCHK) {
450: idx = EXCP_MCHK;
451: }
452: }
453: if (idx >= 0) {
454: env->exception_index = idx;
455: env->error_code = 0;
456: do_interrupt(env);
457: next_tb = 0;
458: }
459: }
1.1.1.6 root 460: #elif defined(TARGET_CRIS)
1.1.1.7 root 461: if (interrupt_request & CPU_INTERRUPT_HARD
1.1.1.12 root 462: && (env->pregs[PR_CCS] & I_FLAG)
463: && !env->locked_irq) {
1.1.1.7 root 464: env->exception_index = EXCP_IRQ;
1.1.1.6 root 465: do_interrupt(env);
1.1.1.7 root 466: next_tb = 0;
467: }
468: if (interrupt_request & CPU_INTERRUPT_NMI
469: && (env->pregs[PR_CCS] & M_FLAG)) {
470: env->exception_index = EXCP_NMI;
471: do_interrupt(env);
472: next_tb = 0;
1.1.1.6 root 473: }
474: #elif defined(TARGET_M68K)
475: if (interrupt_request & CPU_INTERRUPT_HARD
476: && ((env->sr & SR_I) >> SR_I_SHIFT)
477: < env->pending_level) {
478: /* Real hardware gets the interrupt vector via an
479: IACK cycle at this point. Current emulated
480: hardware doesn't rely on this, so we
481: provide/save the vector when the interrupt is
482: first signalled. */
483: env->exception_index = env->pending_vector;
1.1.1.14 root 484: do_interrupt_m68k_hardirq(env);
485: next_tb = 0;
486: }
487: #elif defined(TARGET_S390X) && !defined(CONFIG_USER_ONLY)
488: if ((interrupt_request & CPU_INTERRUPT_HARD) &&
489: (env->psw.mask & PSW_MASK_EXT)) {
490: do_interrupt(env);
1.1.1.7 root 491: next_tb = 0;
1.1.1.6 root 492: }
1.1.1.15! root 493: #elif defined(TARGET_XTENSA)
! 494: if (interrupt_request & CPU_INTERRUPT_HARD) {
! 495: env->exception_index = EXC_IRQ;
! 496: do_interrupt(env);
! 497: next_tb = 0;
! 498: }
1.1 root 499: #endif
1.1.1.14 root 500: /* Don't use the cached interrupt_request value,
1.1.1.4 root 501: do_interrupt may have updated the EXITTB flag. */
1.1.1.2 root 502: if (env->interrupt_request & CPU_INTERRUPT_EXITTB) {
1.1 root 503: env->interrupt_request &= ~CPU_INTERRUPT_EXITTB;
504: /* ensure that no TB jump will be modified as
505: the program flow was changed */
1.1.1.7 root 506: next_tb = 0;
1.1 root 507: }
1.1.1.8 root 508: }
509: if (unlikely(env->exit_request)) {
510: env->exit_request = 0;
511: env->exception_index = EXCP_INTERRUPT;
1.1.1.14 root 512: cpu_loop_exit(env);
1.1 root 513: }
1.1.1.12 root 514: #if defined(DEBUG_DISAS) || defined(CONFIG_DEBUG_EXEC)
1.1.1.7 root 515: if (qemu_loglevel_mask(CPU_LOG_TB_CPU)) {
1.1 root 516: /* restore flags in standard format */
1.1.1.6 root 517: #if defined(TARGET_I386)
1.1.1.14 root 518: env->eflags = env->eflags | cpu_cc_compute_all(env, CC_OP)
519: | (DF & DF_MASK);
1.1.1.7 root 520: log_cpu_state(env, X86_DUMP_CCOP);
1.1 root 521: env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
1.1.1.5 root 522: #elif defined(TARGET_M68K)
523: cpu_m68k_flush_flags(env, env->cc_op);
524: env->cc_op = CC_OP_FLAGS;
525: env->sr = (env->sr & 0xffe0)
526: | env->cc_dest | (env->cc_x << 4);
1.1.1.7 root 527: log_cpu_state(env, 0);
1.1 root 528: #else
1.1.1.12 root 529: log_cpu_state(env, 0);
1.1 root 530: #endif
531: }
1.1.1.12 root 532: #endif /* DEBUG_DISAS || CONFIG_DEBUG_EXEC */
1.1.1.7 root 533: spin_lock(&tb_lock);
1.1.1.14 root 534: tb = tb_find_fast(env);
1.1.1.7 root 535: /* Note: we do it here to avoid a gcc bug on Mac OS X when
536: doing it in tb_find_slow */
537: if (tb_invalidated_flag) {
538: /* as some TB could have been invalidated because
539: of memory exceptions while generating the code, we
540: must recompute the hash index here */
541: next_tb = 0;
542: tb_invalidated_flag = 0;
1.1 root 543: }
1.1.1.10 root 544: #ifdef CONFIG_DEBUG_EXEC
1.1.1.7 root 545: qemu_log_mask(CPU_LOG_EXEC, "Trace 0x%08lx [" TARGET_FMT_lx "] %s\n",
546: (long)tb->tc_ptr, tb->pc,
547: lookup_symbol(tb->pc));
1.1 root 548: #endif
1.1.1.2 root 549: /* see if we can patch the calling TB. When the TB
550: spans two pages, we cannot safely do a direct
551: jump. */
1.1.1.12 root 552: if (next_tb != 0 && tb->page_addr[1] == -1) {
1.1.1.7 root 553: tb_add_jump((TranslationBlock *)(next_tb & ~3), next_tb & 3, tb);
1.1 root 554: }
1.1.1.7 root 555: spin_unlock(&tb_lock);
556:
557: /* cpu_interrupt might be called while translating the
558: TB, but before it is linked into a potentially
559: infinite loop and becomes env->current_tb. Avoid
560: starting execution if there is a pending interrupt. */
1.1.1.12 root 561: env->current_tb = tb;
562: barrier();
563: if (likely(!env->exit_request)) {
1.1.1.7 root 564: tc_ptr = tb->tc_ptr;
1.1 root 565: /* execute the generated code */
1.1.1.14 root 566: next_tb = tcg_qemu_tb_exec(env, tc_ptr);
1.1.1.7 root 567: if ((next_tb & 3) == 2) {
568: /* Instruction counter expired. */
569: int insns_left;
570: tb = (TranslationBlock *)(long)(next_tb & ~3);
571: /* Restore PC. */
572: cpu_pc_from_tb(env, tb);
573: insns_left = env->icount_decr.u32;
574: if (env->icount_extra && insns_left >= 0) {
575: /* Refill decrementer and continue execution. */
576: env->icount_extra += insns_left;
577: if (env->icount_extra > 0xffff) {
578: insns_left = 0xffff;
579: } else {
580: insns_left = env->icount_extra;
581: }
582: env->icount_extra -= insns_left;
583: env->icount_decr.u16.low = insns_left;
584: } else {
585: if (insns_left > 0) {
586: /* Execute remaining instructions. */
1.1.1.14 root 587: cpu_exec_nocache(env, insns_left, tb);
1.1.1.7 root 588: }
589: env->exception_index = EXCP_INTERRUPT;
590: next_tb = 0;
1.1.1.14 root 591: cpu_loop_exit(env);
1.1.1.7 root 592: }
593: }
594: }
1.1.1.12 root 595: env->current_tb = NULL;
1.1 root 596: /* reset soft MMU for next block (it can currently
597: only be set by a memory fault) */
1.1.1.6 root 598: } /* for(;;) */
1.1.1.14 root 599: } else {
600: /* Reload env after longjmp - the compiler may have smashed all
601: * local variables as longjmp is marked 'noreturn'. */
602: env = cpu_single_env;
1.1 root 603: }
604: } /* for(;;) */
605:
606:
607: #if defined(TARGET_I386)
608: /* restore flags in standard format */
1.1.1.14 root 609: env->eflags = env->eflags | cpu_cc_compute_all(env, CC_OP)
610: | (DF & DF_MASK);
1.1 root 611: #elif defined(TARGET_ARM)
612: /* XXX: Save/restore host fpu exception state?. */
1.1.1.14 root 613: #elif defined(TARGET_UNICORE32)
1.1 root 614: #elif defined(TARGET_SPARC)
615: #elif defined(TARGET_PPC)
1.1.1.14 root 616: #elif defined(TARGET_LM32)
1.1.1.5 root 617: #elif defined(TARGET_M68K)
618: cpu_m68k_flush_flags(env, env->cc_op);
619: env->cc_op = CC_OP_FLAGS;
620: env->sr = (env->sr & 0xffe0)
621: | env->cc_dest | (env->cc_x << 4);
1.1.1.9 root 622: #elif defined(TARGET_MICROBLAZE)
1.1 root 623: #elif defined(TARGET_MIPS)
1.1.1.3 root 624: #elif defined(TARGET_SH4)
1.1.1.6 root 625: #elif defined(TARGET_ALPHA)
626: #elif defined(TARGET_CRIS)
1.1.1.10 root 627: #elif defined(TARGET_S390X)
1.1.1.15! root 628: #elif defined(TARGET_XTENSA)
1.1.1.3 root 629: /* XXXXX */
1.1 root 630: #else
631: #error unsupported target CPU
632: #endif
1.1.1.5 root 633:
1.1.1.2 root 634: /* fail safe : never use cpu_single_env outside cpu_exec() */
1.1.1.6 root 635: cpu_single_env = NULL;
1.1 root 636: return ret;
637: }
unix.superglobalmegacorp.com