blob: 49de9e0ad96bb0edfc3b6d9ced58357458bb3638 [file] [log] [blame]
bellard7d132992003-03-06 23:23:54 +00001/*
2 * i386 emulator main execution loop
ths5fafdf22007-09-16 21:08:06 +00003 *
bellard66321a12005-04-06 20:47:48 +00004 * Copyright (c) 2003-2005 Fabrice Bellard
bellard7d132992003-03-06 23:23:54 +00005 *
bellard3ef693a2003-03-23 20:17:16 +00006 * 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.
bellard7d132992003-03-06 23:23:54 +000010 *
bellard3ef693a2003-03-23 20:17:16 +000011 * 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.
bellard7d132992003-03-06 23:23:54 +000015 *
bellard3ef693a2003-03-23 20:17:16 +000016 * You should have received a copy of the GNU Lesser General Public
Blue Swirl8167ee82009-07-16 20:47:01 +000017 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
bellard7d132992003-03-06 23:23:54 +000018 */
bellarde4533c72003-06-15 19:51:39 +000019#include "config.h"
bellard93ac68b2003-09-30 20:57:29 +000020#include "exec.h"
bellard956034d2003-04-29 20:40:53 +000021#include "disas.h"
bellard7cb69ca2008-05-10 10:55:51 +000022#include "tcg.h"
Jan Kiszka1d93f0f2010-06-25 16:56:49 +020023#include "qemu-barrier.h"
bellard7d132992003-03-06 23:23:54 +000024
Juan Quinteladfe5fff2009-07-27 16:12:40 +020025#if defined(__sparc__) && !defined(CONFIG_SOLARIS)
blueswir1572a9d42008-05-17 07:38:10 +000026// Work around ugly bugs in glibc that mangle global register contents
27#undef env
28#define env cpu_single_env
29#endif
30
bellard36bdbe52003-11-19 22:12:02 +000031int tb_invalidated_flag;
32
Juan Quintelaf0667e62009-07-27 16:13:05 +020033//#define CONFIG_DEBUG_EXEC
bellard7d132992003-03-06 23:23:54 +000034
Blue Swirlf3e27032011-05-21 12:16:05 +000035bool qemu_cpu_has_work(CPUState *env)
aliguori6a4955a2009-04-24 18:03:20 +000036{
37 return cpu_has_work(env);
38}
39
Blue Swirl1162c042011-05-14 12:52:35 +000040void cpu_loop_exit(CPUState *env1)
bellarde4533c72003-06-15 19:51:39 +000041{
Blue Swirl1162c042011-05-14 12:52:35 +000042 env1->current_tb = NULL;
43 longjmp(env1->jmp_env, 1);
bellarde4533c72003-06-15 19:51:39 +000044}
thsbfed01f2007-06-03 17:44:37 +000045
bellardfbf9eeb2004-04-25 21:21:33 +000046/* exit the current TB from a signal handler. The host registers are
47 restored in a state compatible with the CPU emulator
48 */
Blue Swirl9eff14f2011-05-21 08:42:35 +000049#if defined(CONFIG_SOFTMMU)
ths5fafdf22007-09-16 21:08:06 +000050void cpu_resume_from_signal(CPUState *env1, void *puc)
bellardfbf9eeb2004-04-25 21:21:33 +000051{
Blue Swirl9eff14f2011-05-21 08:42:35 +000052 env = env1;
53
54 /* XXX: restore cpu registers saved in host registers */
55
56 env->exception_index = -1;
57 longjmp(env->jmp_env, 1);
58}
Blue Swirl9eff14f2011-05-21 08:42:35 +000059#endif
bellardfbf9eeb2004-04-25 21:21:33 +000060
pbrook2e70f6e2008-06-29 01:03:05 +000061/* Execute the code without caching the generated code. An interpreter
62 could be used if available. */
63static void cpu_exec_nocache(int max_cycles, TranslationBlock *orig_tb)
64{
65 unsigned long next_tb;
66 TranslationBlock *tb;
67
68 /* Should never happen.
69 We only end up here when an existing TB is too long. */
70 if (max_cycles > CF_COUNT_MASK)
71 max_cycles = CF_COUNT_MASK;
72
73 tb = tb_gen_code(env, orig_tb->pc, orig_tb->cs_base, orig_tb->flags,
74 max_cycles);
75 env->current_tb = tb;
76 /* execute the generated code */
77 next_tb = tcg_qemu_tb_exec(tb->tc_ptr);
Paolo Bonzini1c3569f2010-01-15 09:42:07 +010078 env->current_tb = NULL;
pbrook2e70f6e2008-06-29 01:03:05 +000079
80 if ((next_tb & 3) == 2) {
81 /* Restore PC. This may happen if async event occurs before
82 the TB starts executing. */
aliguori622ed362008-11-18 19:36:03 +000083 cpu_pc_from_tb(env, tb);
pbrook2e70f6e2008-06-29 01:03:05 +000084 }
85 tb_phys_invalidate(tb, -1);
86 tb_free(tb);
87}
88
bellard8a40a182005-11-20 10:35:40 +000089static TranslationBlock *tb_find_slow(target_ulong pc,
90 target_ulong cs_base,
j_mayerc0686882007-09-20 22:47:42 +000091 uint64_t flags)
bellard8a40a182005-11-20 10:35:40 +000092{
93 TranslationBlock *tb, **ptb1;
bellard8a40a182005-11-20 10:35:40 +000094 unsigned int h;
Paul Brook41c1b1c2010-03-12 16:54:58 +000095 tb_page_addr_t phys_pc, phys_page1, phys_page2;
96 target_ulong virt_page2;
ths3b46e622007-09-17 08:09:54 +000097
bellard8a40a182005-11-20 10:35:40 +000098 tb_invalidated_flag = 0;
ths3b46e622007-09-17 08:09:54 +000099
bellard8a40a182005-11-20 10:35:40 +0000100 /* find translated block using physical mappings */
Paul Brook41c1b1c2010-03-12 16:54:58 +0000101 phys_pc = get_page_addr_code(env, pc);
bellard8a40a182005-11-20 10:35:40 +0000102 phys_page1 = phys_pc & TARGET_PAGE_MASK;
103 phys_page2 = -1;
104 h = tb_phys_hash_func(phys_pc);
105 ptb1 = &tb_phys_hash[h];
106 for(;;) {
107 tb = *ptb1;
108 if (!tb)
109 goto not_found;
ths5fafdf22007-09-16 21:08:06 +0000110 if (tb->pc == pc &&
bellard8a40a182005-11-20 10:35:40 +0000111 tb->page_addr[0] == phys_page1 &&
ths5fafdf22007-09-16 21:08:06 +0000112 tb->cs_base == cs_base &&
bellard8a40a182005-11-20 10:35:40 +0000113 tb->flags == flags) {
114 /* check next page if needed */
115 if (tb->page_addr[1] != -1) {
ths5fafdf22007-09-16 21:08:06 +0000116 virt_page2 = (pc & TARGET_PAGE_MASK) +
bellard8a40a182005-11-20 10:35:40 +0000117 TARGET_PAGE_SIZE;
Paul Brook41c1b1c2010-03-12 16:54:58 +0000118 phys_page2 = get_page_addr_code(env, virt_page2);
bellard8a40a182005-11-20 10:35:40 +0000119 if (tb->page_addr[1] == phys_page2)
120 goto found;
121 } else {
122 goto found;
123 }
124 }
125 ptb1 = &tb->phys_hash_next;
126 }
127 not_found:
pbrook2e70f6e2008-06-29 01:03:05 +0000128 /* if no translated code available, then translate it now */
129 tb = tb_gen_code(env, pc, cs_base, flags, 0);
ths3b46e622007-09-17 08:09:54 +0000130
bellard8a40a182005-11-20 10:35:40 +0000131 found:
Kirill Batuzov2c90fe22010-12-02 16:12:46 +0300132 /* Move the last found TB to the head of the list */
133 if (likely(*ptb1)) {
134 *ptb1 = tb->phys_hash_next;
135 tb->phys_hash_next = tb_phys_hash[h];
136 tb_phys_hash[h] = tb;
137 }
bellard8a40a182005-11-20 10:35:40 +0000138 /* we add the TB in the virtual pc hash table */
139 env->tb_jmp_cache[tb_jmp_cache_hash_func(pc)] = tb;
bellard8a40a182005-11-20 10:35:40 +0000140 return tb;
141}
142
143static inline TranslationBlock *tb_find_fast(void)
144{
145 TranslationBlock *tb;
146 target_ulong cs_base, pc;
aliguori6b917542008-11-18 19:46:41 +0000147 int flags;
bellard8a40a182005-11-20 10:35:40 +0000148
149 /* we record a subset of the CPU state. It will
150 always be the same before a given translated block
151 is executed. */
aliguori6b917542008-11-18 19:46:41 +0000152 cpu_get_tb_cpu_state(env, &pc, &cs_base, &flags);
bellardbce61842008-02-01 22:18:51 +0000153 tb = env->tb_jmp_cache[tb_jmp_cache_hash_func(pc)];
ths551bd272008-07-03 17:57:36 +0000154 if (unlikely(!tb || tb->pc != pc || tb->cs_base != cs_base ||
155 tb->flags != flags)) {
bellard8a40a182005-11-20 10:35:40 +0000156 tb = tb_find_slow(pc, cs_base, flags);
157 }
158 return tb;
159}
160
Jan Kiszka1009d2e2011-03-15 12:26:13 +0100161static CPUDebugExcpHandler *debug_excp_handler;
162
163CPUDebugExcpHandler *cpu_set_debug_excp_handler(CPUDebugExcpHandler *handler)
164{
165 CPUDebugExcpHandler *old_handler = debug_excp_handler;
166
167 debug_excp_handler = handler;
168 return old_handler;
169}
170
171static void cpu_handle_debug_exception(CPUState *env)
172{
173 CPUWatchpoint *wp;
174
175 if (!env->watchpoint_hit) {
176 QTAILQ_FOREACH(wp, &env->watchpoints, entry) {
177 wp->flags &= ~BP_WATCHPOINT_HIT;
178 }
179 }
180 if (debug_excp_handler) {
181 debug_excp_handler(env);
182 }
183}
184
bellard7d132992003-03-06 23:23:54 +0000185/* main execution loop */
186
Marcelo Tosatti1a28cac2010-05-04 09:45:20 -0300187volatile sig_atomic_t exit_request;
188
bellarde4533c72003-06-15 19:51:39 +0000189int cpu_exec(CPUState *env1)
bellard7d132992003-03-06 23:23:54 +0000190{
Paolo Bonzini1d9000e2010-02-23 19:21:00 +0100191 volatile host_reg_t saved_env_reg;
bellard8a40a182005-11-20 10:35:40 +0000192 int ret, interrupt_request;
bellard8a40a182005-11-20 10:35:40 +0000193 TranslationBlock *tb;
bellardc27004e2005-01-03 23:35:10 +0000194 uint8_t *tc_ptr;
pbrookd5975362008-06-07 20:50:51 +0000195 unsigned long next_tb;
bellard8c6939c2003-06-09 15:28:00 +0000196
Paolo Bonzinieda48c32011-03-12 17:43:56 +0100197 if (env1->halted) {
198 if (!cpu_has_work(env1)) {
199 return EXCP_HALTED;
200 }
201
202 env1->halted = 0;
203 }
bellard5a1e3cf2005-11-23 21:02:53 +0000204
ths5fafdf22007-09-16 21:08:06 +0000205 cpu_single_env = env1;
bellard6a00d602005-11-21 23:25:50 +0000206
Paolo Bonzini24ebf5f2010-02-18 21:25:23 +0100207 /* the access to env below is actually saving the global register's
208 value, so that files not including target-xyz/exec.h are free to
209 use it. */
210 QEMU_BUILD_BUG_ON (sizeof (saved_env_reg) != sizeof (env));
211 saved_env_reg = (host_reg_t) env;
Jan Kiszka1d93f0f2010-06-25 16:56:49 +0200212 barrier();
bellardc27004e2005-01-03 23:35:10 +0000213 env = env1;
bellarde4533c72003-06-15 19:51:39 +0000214
Jan Kiszkac629a4b2010-06-25 16:56:52 +0200215 if (unlikely(exit_request)) {
Marcelo Tosatti1a28cac2010-05-04 09:45:20 -0300216 env->exit_request = 1;
Marcelo Tosatti1a28cac2010-05-04 09:45:20 -0300217 }
218
thsecb644f2007-06-03 18:45:53 +0000219#if defined(TARGET_I386)
Jan Kiszka6792a572011-02-07 12:19:18 +0100220 /* put eflags in CPU temporary format */
221 CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
222 DF = 1 - (2 * ((env->eflags >> 10) & 1));
223 CC_OP = CC_OP_EFLAGS;
224 env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
bellard93ac68b2003-09-30 20:57:29 +0000225#elif defined(TARGET_SPARC)
pbrooke6e59062006-10-22 00:18:54 +0000226#elif defined(TARGET_M68K)
227 env->cc_op = CC_OP_FLAGS;
228 env->cc_dest = env->sr & 0xf;
229 env->cc_x = (env->sr >> 4) & 1;
thsecb644f2007-06-03 18:45:53 +0000230#elif defined(TARGET_ALPHA)
231#elif defined(TARGET_ARM)
Guan Xuetaod2fbca92011-04-12 16:27:03 +0800232#elif defined(TARGET_UNICORE32)
thsecb644f2007-06-03 18:45:53 +0000233#elif defined(TARGET_PPC)
Michael Walle81ea0e12011-02-17 23:45:02 +0100234#elif defined(TARGET_LM32)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +0200235#elif defined(TARGET_MICROBLAZE)
bellard6af0bf92005-07-02 14:58:51 +0000236#elif defined(TARGET_MIPS)
bellardfdf9b3e2006-04-27 21:07:38 +0000237#elif defined(TARGET_SH4)
thsf1ccf902007-10-08 13:16:14 +0000238#elif defined(TARGET_CRIS)
Alexander Graf10ec5112009-12-05 12:44:21 +0100239#elif defined(TARGET_S390X)
bellardfdf9b3e2006-04-27 21:07:38 +0000240 /* XXXXX */
bellarde4533c72003-06-15 19:51:39 +0000241#else
242#error unsupported target CPU
243#endif
bellard3fb2ded2003-06-24 13:22:59 +0000244 env->exception_index = -1;
bellard9d27abd2003-05-10 13:13:54 +0000245
bellard7d132992003-03-06 23:23:54 +0000246 /* prepare setjmp context for exception handling */
bellard3fb2ded2003-06-24 13:22:59 +0000247 for(;;) {
248 if (setjmp(env->jmp_env) == 0) {
Juan Quinteladfe5fff2009-07-27 16:12:40 +0200249#if defined(__sparc__) && !defined(CONFIG_SOLARIS)
blueswir19ddff3d2009-04-04 07:41:20 +0000250#undef env
Jan Kiszka6792a572011-02-07 12:19:18 +0100251 env = cpu_single_env;
blueswir19ddff3d2009-04-04 07:41:20 +0000252#define env cpu_single_env
253#endif
bellard3fb2ded2003-06-24 13:22:59 +0000254 /* if an exception is pending, we execute it here */
255 if (env->exception_index >= 0) {
256 if (env->exception_index >= EXCP_INTERRUPT) {
257 /* exit request from the cpu execution loop */
258 ret = env->exception_index;
Jan Kiszka1009d2e2011-03-15 12:26:13 +0100259 if (ret == EXCP_DEBUG) {
260 cpu_handle_debug_exception(env);
261 }
bellard3fb2ded2003-06-24 13:22:59 +0000262 break;
aurel3272d239e2009-01-14 19:40:27 +0000263 } else {
264#if defined(CONFIG_USER_ONLY)
bellard3fb2ded2003-06-24 13:22:59 +0000265 /* if user mode only, we simulate a fake exception
ths9f083492006-12-07 18:28:42 +0000266 which will be handled outside the cpu execution
bellard3fb2ded2003-06-24 13:22:59 +0000267 loop */
bellard83479e72003-06-25 16:12:37 +0000268#if defined(TARGET_I386)
Blue Swirle694d4e2011-05-16 19:38:48 +0000269 do_interrupt(env);
bellard83479e72003-06-25 16:12:37 +0000270#endif
bellard3fb2ded2003-06-24 13:22:59 +0000271 ret = env->exception_index;
272 break;
aurel3272d239e2009-01-14 19:40:27 +0000273#else
Blue Swirle694d4e2011-05-16 19:38:48 +0000274 do_interrupt(env);
Paolo Bonzini301d2902010-01-15 09:41:01 +0100275 env->exception_index = -1;
aurel3272d239e2009-01-14 19:40:27 +0000276#endif
bellard3fb2ded2003-06-24 13:22:59 +0000277 }
ths5fafdf22007-09-16 21:08:06 +0000278 }
bellard9df217a2005-02-10 22:05:51 +0000279
blueswir1b5fc09a2008-05-04 06:38:18 +0000280 next_tb = 0; /* force lookup of first TB */
bellard3fb2ded2003-06-24 13:22:59 +0000281 for(;;) {
bellard68a79312003-06-30 13:12:32 +0000282 interrupt_request = env->interrupt_request;
malce1638bd2008-11-06 18:54:46 +0000283 if (unlikely(interrupt_request)) {
284 if (unlikely(env->singlestep_enabled & SSTEP_NOIRQ)) {
285 /* Mask out external interrupts for this step. */
Richard Henderson3125f762011-05-04 13:34:25 -0700286 interrupt_request &= ~CPU_INTERRUPT_SSTEP_MASK;
malce1638bd2008-11-06 18:54:46 +0000287 }
pbrook6658ffb2007-03-16 23:58:11 +0000288 if (interrupt_request & CPU_INTERRUPT_DEBUG) {
289 env->interrupt_request &= ~CPU_INTERRUPT_DEBUG;
290 env->exception_index = EXCP_DEBUG;
Blue Swirl1162c042011-05-14 12:52:35 +0000291 cpu_loop_exit(env);
pbrook6658ffb2007-03-16 23:58:11 +0000292 }
balroga90b7312007-05-01 01:28:01 +0000293#if defined(TARGET_ARM) || defined(TARGET_SPARC) || defined(TARGET_MIPS) || \
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +0200294 defined(TARGET_PPC) || defined(TARGET_ALPHA) || defined(TARGET_CRIS) || \
Guan Xuetaod2fbca92011-04-12 16:27:03 +0800295 defined(TARGET_MICROBLAZE) || defined(TARGET_LM32) || defined(TARGET_UNICORE32)
balroga90b7312007-05-01 01:28:01 +0000296 if (interrupt_request & CPU_INTERRUPT_HALT) {
297 env->interrupt_request &= ~CPU_INTERRUPT_HALT;
298 env->halted = 1;
299 env->exception_index = EXCP_HLT;
Blue Swirl1162c042011-05-14 12:52:35 +0000300 cpu_loop_exit(env);
balroga90b7312007-05-01 01:28:01 +0000301 }
302#endif
bellard68a79312003-06-30 13:12:32 +0000303#if defined(TARGET_I386)
Gleb Natapovb09ea7d2009-06-17 23:26:59 +0300304 if (interrupt_request & CPU_INTERRUPT_INIT) {
Blue Swirle694d4e2011-05-16 19:38:48 +0000305 svm_check_intercept(env, SVM_EXIT_INIT);
Gleb Natapovb09ea7d2009-06-17 23:26:59 +0300306 do_cpu_init(env);
307 env->exception_index = EXCP_HALTED;
Blue Swirl1162c042011-05-14 12:52:35 +0000308 cpu_loop_exit(env);
Gleb Natapovb09ea7d2009-06-17 23:26:59 +0300309 } else if (interrupt_request & CPU_INTERRUPT_SIPI) {
310 do_cpu_sipi(env);
311 } else if (env->hflags2 & HF2_GIF_MASK) {
bellarddb620f42008-06-04 17:02:19 +0000312 if ((interrupt_request & CPU_INTERRUPT_SMI) &&
313 !(env->hflags & HF_SMM_MASK)) {
Blue Swirle694d4e2011-05-16 19:38:48 +0000314 svm_check_intercept(env, SVM_EXIT_SMI);
bellarddb620f42008-06-04 17:02:19 +0000315 env->interrupt_request &= ~CPU_INTERRUPT_SMI;
Blue Swirle694d4e2011-05-16 19:38:48 +0000316 do_smm_enter(env);
bellarddb620f42008-06-04 17:02:19 +0000317 next_tb = 0;
318 } else if ((interrupt_request & CPU_INTERRUPT_NMI) &&
319 !(env->hflags2 & HF2_NMI_MASK)) {
320 env->interrupt_request &= ~CPU_INTERRUPT_NMI;
321 env->hflags2 |= HF2_NMI_MASK;
Blue Swirle694d4e2011-05-16 19:38:48 +0000322 do_interrupt_x86_hardirq(env, EXCP02_NMI, 1);
bellarddb620f42008-06-04 17:02:19 +0000323 next_tb = 0;
Huang Ying79c4f6b2009-06-23 10:05:14 +0800324 } else if (interrupt_request & CPU_INTERRUPT_MCE) {
325 env->interrupt_request &= ~CPU_INTERRUPT_MCE;
Blue Swirle694d4e2011-05-16 19:38:48 +0000326 do_interrupt_x86_hardirq(env, EXCP12_MCHK, 0);
Huang Ying79c4f6b2009-06-23 10:05:14 +0800327 next_tb = 0;
bellarddb620f42008-06-04 17:02:19 +0000328 } else if ((interrupt_request & CPU_INTERRUPT_HARD) &&
329 (((env->hflags2 & HF2_VINTR_MASK) &&
330 (env->hflags2 & HF2_HIF_MASK)) ||
331 (!(env->hflags2 & HF2_VINTR_MASK) &&
332 (env->eflags & IF_MASK &&
333 !(env->hflags & HF_INHIBIT_IRQ_MASK))))) {
334 int intno;
Blue Swirle694d4e2011-05-16 19:38:48 +0000335 svm_check_intercept(env, SVM_EXIT_INTR);
bellarddb620f42008-06-04 17:02:19 +0000336 env->interrupt_request &= ~(CPU_INTERRUPT_HARD | CPU_INTERRUPT_VIRQ);
337 intno = cpu_get_pic_interrupt(env);
aliguori93fcfe32009-01-15 22:34:14 +0000338 qemu_log_mask(CPU_LOG_TB_IN_ASM, "Servicing hardware INT=0x%02x\n", intno);
Juan Quinteladfe5fff2009-07-27 16:12:40 +0200339#if defined(__sparc__) && !defined(CONFIG_SOLARIS)
blueswir19ddff3d2009-04-04 07:41:20 +0000340#undef env
341 env = cpu_single_env;
342#define env cpu_single_env
343#endif
Blue Swirle694d4e2011-05-16 19:38:48 +0000344 do_interrupt_x86_hardirq(env, intno, 1);
bellarddb620f42008-06-04 17:02:19 +0000345 /* ensure that no TB jump will be modified as
346 the program flow was changed */
347 next_tb = 0;
ths0573fbf2007-09-23 15:28:04 +0000348#if !defined(CONFIG_USER_ONLY)
bellarddb620f42008-06-04 17:02:19 +0000349 } else if ((interrupt_request & CPU_INTERRUPT_VIRQ) &&
350 (env->eflags & IF_MASK) &&
351 !(env->hflags & HF_INHIBIT_IRQ_MASK)) {
352 int intno;
353 /* FIXME: this should respect TPR */
Blue Swirle694d4e2011-05-16 19:38:48 +0000354 svm_check_intercept(env, SVM_EXIT_VINTR);
bellarddb620f42008-06-04 17:02:19 +0000355 intno = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_vector));
aliguori93fcfe32009-01-15 22:34:14 +0000356 qemu_log_mask(CPU_LOG_TB_IN_ASM, "Servicing virtual hardware INT=0x%02x\n", intno);
Blue Swirle694d4e2011-05-16 19:38:48 +0000357 do_interrupt_x86_hardirq(env, intno, 1);
aurel32d40c54d2008-12-13 12:33:02 +0000358 env->interrupt_request &= ~CPU_INTERRUPT_VIRQ;
bellarddb620f42008-06-04 17:02:19 +0000359 next_tb = 0;
ths0573fbf2007-09-23 15:28:04 +0000360#endif
bellarddb620f42008-06-04 17:02:19 +0000361 }
bellard68a79312003-06-30 13:12:32 +0000362 }
bellardce097762004-01-04 23:53:18 +0000363#elif defined(TARGET_PPC)
bellard9fddaa02004-05-21 12:59:32 +0000364#if 0
365 if ((interrupt_request & CPU_INTERRUPT_RESET)) {
Blue Swirld84bda42009-11-07 10:36:04 +0000366 cpu_reset(env);
bellard9fddaa02004-05-21 12:59:32 +0000367 }
368#endif
j_mayer47103572007-03-30 09:38:04 +0000369 if (interrupt_request & CPU_INTERRUPT_HARD) {
j_mayere9df0142007-04-09 22:45:36 +0000370 ppc_hw_interrupt(env);
371 if (env->pending_interrupts == 0)
372 env->interrupt_request &= ~CPU_INTERRUPT_HARD;
blueswir1b5fc09a2008-05-04 06:38:18 +0000373 next_tb = 0;
bellardce097762004-01-04 23:53:18 +0000374 }
Michael Walle81ea0e12011-02-17 23:45:02 +0100375#elif defined(TARGET_LM32)
376 if ((interrupt_request & CPU_INTERRUPT_HARD)
377 && (env->ie & IE_IE)) {
378 env->exception_index = EXCP_IRQ;
379 do_interrupt(env);
380 next_tb = 0;
381 }
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +0200382#elif defined(TARGET_MICROBLAZE)
383 if ((interrupt_request & CPU_INTERRUPT_HARD)
384 && (env->sregs[SR_MSR] & MSR_IE)
385 && !(env->sregs[SR_MSR] & (MSR_EIP | MSR_BIP))
386 && !(env->iflags & (D_FLAG | IMM_FLAG))) {
387 env->exception_index = EXCP_IRQ;
388 do_interrupt(env);
389 next_tb = 0;
390 }
bellard6af0bf92005-07-02 14:58:51 +0000391#elif defined(TARGET_MIPS)
392 if ((interrupt_request & CPU_INTERRUPT_HARD) &&
Aurelien Jarno4cdc1cd2010-12-25 22:56:32 +0100393 cpu_mips_hw_interrupts_pending(env)) {
bellard6af0bf92005-07-02 14:58:51 +0000394 /* Raise it */
395 env->exception_index = EXCP_EXT_INTERRUPT;
396 env->error_code = 0;
397 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000398 next_tb = 0;
bellard6af0bf92005-07-02 14:58:51 +0000399 }
bellarde95c8d52004-09-30 22:22:08 +0000400#elif defined(TARGET_SPARC)
Igor V. Kovalenkod532b262010-01-07 23:28:31 +0300401 if (interrupt_request & CPU_INTERRUPT_HARD) {
402 if (cpu_interrupts_enabled(env) &&
403 env->interrupt_index > 0) {
404 int pil = env->interrupt_index & 0xf;
405 int type = env->interrupt_index & 0xf0;
bellard66321a12005-04-06 20:47:48 +0000406
Igor V. Kovalenkod532b262010-01-07 23:28:31 +0300407 if (((type == TT_EXTINT) &&
408 cpu_pil_allowed(env, pil)) ||
409 type != TT_EXTINT) {
410 env->exception_index = env->interrupt_index;
411 do_interrupt(env);
412 next_tb = 0;
413 }
414 }
balroga90b7312007-05-01 01:28:01 +0000415 }
bellardb5ff1b32005-11-26 10:38:39 +0000416#elif defined(TARGET_ARM)
417 if (interrupt_request & CPU_INTERRUPT_FIQ
418 && !(env->uncached_cpsr & CPSR_F)) {
419 env->exception_index = EXCP_FIQ;
420 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000421 next_tb = 0;
bellardb5ff1b32005-11-26 10:38:39 +0000422 }
pbrook9ee6e8b2007-11-11 00:04:49 +0000423 /* ARMv7-M interrupt return works by loading a magic value
424 into the PC. On real hardware the load causes the
425 return to occur. The qemu implementation performs the
426 jump normally, then does the exception return when the
427 CPU tries to execute code at the magic address.
428 This will cause the magic PC value to be pushed to
Stefan Weila1c72732011-04-28 17:20:38 +0200429 the stack if an interrupt occurred at the wrong time.
pbrook9ee6e8b2007-11-11 00:04:49 +0000430 We avoid this by disabling interrupts when
431 pc contains a magic address. */
bellardb5ff1b32005-11-26 10:38:39 +0000432 if (interrupt_request & CPU_INTERRUPT_HARD
pbrook9ee6e8b2007-11-11 00:04:49 +0000433 && ((IS_M(env) && env->regs[15] < 0xfffffff0)
434 || !(env->uncached_cpsr & CPSR_I))) {
bellardb5ff1b32005-11-26 10:38:39 +0000435 env->exception_index = EXCP_IRQ;
436 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000437 next_tb = 0;
bellardb5ff1b32005-11-26 10:38:39 +0000438 }
Guan Xuetaod2fbca92011-04-12 16:27:03 +0800439#elif defined(TARGET_UNICORE32)
440 if (interrupt_request & CPU_INTERRUPT_HARD
441 && !(env->uncached_asr & ASR_I)) {
442 do_interrupt(env);
443 next_tb = 0;
444 }
bellardfdf9b3e2006-04-27 21:07:38 +0000445#elif defined(TARGET_SH4)
thse96e2042007-12-02 06:18:24 +0000446 if (interrupt_request & CPU_INTERRUPT_HARD) {
447 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000448 next_tb = 0;
thse96e2042007-12-02 06:18:24 +0000449 }
j_mayereddf68a2007-04-05 07:22:49 +0000450#elif defined(TARGET_ALPHA)
Richard Henderson6a80e082011-04-18 15:09:09 -0700451 {
452 int idx = -1;
453 /* ??? This hard-codes the OSF/1 interrupt levels. */
454 switch (env->pal_mode ? 7 : env->ps & PS_INT_MASK) {
455 case 0 ... 3:
456 if (interrupt_request & CPU_INTERRUPT_HARD) {
457 idx = EXCP_DEV_INTERRUPT;
458 }
459 /* FALLTHRU */
460 case 4:
461 if (interrupt_request & CPU_INTERRUPT_TIMER) {
462 idx = EXCP_CLK_INTERRUPT;
463 }
464 /* FALLTHRU */
465 case 5:
466 if (interrupt_request & CPU_INTERRUPT_SMP) {
467 idx = EXCP_SMP_INTERRUPT;
468 }
469 /* FALLTHRU */
470 case 6:
471 if (interrupt_request & CPU_INTERRUPT_MCHK) {
472 idx = EXCP_MCHK;
473 }
474 }
475 if (idx >= 0) {
476 env->exception_index = idx;
477 env->error_code = 0;
478 do_interrupt(env);
479 next_tb = 0;
480 }
j_mayereddf68a2007-04-05 07:22:49 +0000481 }
thsf1ccf902007-10-08 13:16:14 +0000482#elif defined(TARGET_CRIS)
edgar_igl1b1a38b2008-06-09 23:18:06 +0000483 if (interrupt_request & CPU_INTERRUPT_HARD
Edgar E. Iglesiasfb9fb692010-02-15 11:17:33 +0100484 && (env->pregs[PR_CCS] & I_FLAG)
485 && !env->locked_irq) {
edgar_igl1b1a38b2008-06-09 23:18:06 +0000486 env->exception_index = EXCP_IRQ;
487 do_interrupt(env);
488 next_tb = 0;
489 }
490 if (interrupt_request & CPU_INTERRUPT_NMI
491 && (env->pregs[PR_CCS] & M_FLAG)) {
492 env->exception_index = EXCP_NMI;
thsf1ccf902007-10-08 13:16:14 +0000493 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000494 next_tb = 0;
thsf1ccf902007-10-08 13:16:14 +0000495 }
pbrook06338792007-05-23 19:58:11 +0000496#elif defined(TARGET_M68K)
497 if (interrupt_request & CPU_INTERRUPT_HARD
498 && ((env->sr & SR_I) >> SR_I_SHIFT)
499 < env->pending_level) {
500 /* Real hardware gets the interrupt vector via an
501 IACK cycle at this point. Current emulated
502 hardware doesn't rely on this, so we
503 provide/save the vector when the interrupt is
504 first signalled. */
505 env->exception_index = env->pending_vector;
Blue Swirl3c688822011-05-21 07:55:24 +0000506 do_interrupt_m68k_hardirq(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000507 next_tb = 0;
pbrook06338792007-05-23 19:58:11 +0000508 }
Alexander Graf3110e292011-04-15 17:32:48 +0200509#elif defined(TARGET_S390X) && !defined(CONFIG_USER_ONLY)
510 if ((interrupt_request & CPU_INTERRUPT_HARD) &&
511 (env->psw.mask & PSW_MASK_EXT)) {
512 do_interrupt(env);
513 next_tb = 0;
514 }
bellard68a79312003-06-30 13:12:32 +0000515#endif
Stefan Weilff2712b2011-04-28 17:20:35 +0200516 /* Don't use the cached interrupt_request value,
bellard9d050952006-05-22 22:03:52 +0000517 do_interrupt may have updated the EXITTB flag. */
bellardb5ff1b32005-11-26 10:38:39 +0000518 if (env->interrupt_request & CPU_INTERRUPT_EXITTB) {
bellardbf3e8bf2004-02-16 21:58:54 +0000519 env->interrupt_request &= ~CPU_INTERRUPT_EXITTB;
520 /* ensure that no TB jump will be modified as
521 the program flow was changed */
blueswir1b5fc09a2008-05-04 06:38:18 +0000522 next_tb = 0;
bellardbf3e8bf2004-02-16 21:58:54 +0000523 }
aurel32be214e62009-03-06 21:48:00 +0000524 }
525 if (unlikely(env->exit_request)) {
526 env->exit_request = 0;
527 env->exception_index = EXCP_INTERRUPT;
Blue Swirl1162c042011-05-14 12:52:35 +0000528 cpu_loop_exit(env);
bellard3fb2ded2003-06-24 13:22:59 +0000529 }
Richard Hendersona73b1fd2010-04-28 16:07:57 -0700530#if defined(DEBUG_DISAS) || defined(CONFIG_DEBUG_EXEC)
aliguori8fec2b82009-01-15 22:36:53 +0000531 if (qemu_loglevel_mask(CPU_LOG_TB_CPU)) {
bellard3fb2ded2003-06-24 13:22:59 +0000532 /* restore flags in standard format */
thsecb644f2007-06-03 18:45:53 +0000533#if defined(TARGET_I386)
Blue Swirle694d4e2011-05-16 19:38:48 +0000534 env->eflags = env->eflags | cpu_cc_compute_all(env, CC_OP)
535 | (DF & DF_MASK);
aliguori93fcfe32009-01-15 22:34:14 +0000536 log_cpu_state(env, X86_DUMP_CCOP);
bellard3fb2ded2003-06-24 13:22:59 +0000537 env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
pbrooke6e59062006-10-22 00:18:54 +0000538#elif defined(TARGET_M68K)
539 cpu_m68k_flush_flags(env, env->cc_op);
540 env->cc_op = CC_OP_FLAGS;
541 env->sr = (env->sr & 0xffe0)
542 | env->cc_dest | (env->cc_x << 4);
aliguori93fcfe32009-01-15 22:34:14 +0000543 log_cpu_state(env, 0);
bellarde4533c72003-06-15 19:51:39 +0000544#else
Richard Hendersona73b1fd2010-04-28 16:07:57 -0700545 log_cpu_state(env, 0);
bellarde4533c72003-06-15 19:51:39 +0000546#endif
bellard3fb2ded2003-06-24 13:22:59 +0000547 }
Richard Hendersona73b1fd2010-04-28 16:07:57 -0700548#endif /* DEBUG_DISAS || CONFIG_DEBUG_EXEC */
pbrookd5975362008-06-07 20:50:51 +0000549 spin_lock(&tb_lock);
bellard8a40a182005-11-20 10:35:40 +0000550 tb = tb_find_fast();
pbrookd5975362008-06-07 20:50:51 +0000551 /* Note: we do it here to avoid a gcc bug on Mac OS X when
552 doing it in tb_find_slow */
553 if (tb_invalidated_flag) {
554 /* as some TB could have been invalidated because
555 of memory exceptions while generating the code, we
556 must recompute the hash index here */
557 next_tb = 0;
pbrook2e70f6e2008-06-29 01:03:05 +0000558 tb_invalidated_flag = 0;
pbrookd5975362008-06-07 20:50:51 +0000559 }
Juan Quintelaf0667e62009-07-27 16:13:05 +0200560#ifdef CONFIG_DEBUG_EXEC
aliguori93fcfe32009-01-15 22:34:14 +0000561 qemu_log_mask(CPU_LOG_EXEC, "Trace 0x%08lx [" TARGET_FMT_lx "] %s\n",
562 (long)tb->tc_ptr, tb->pc,
563 lookup_symbol(tb->pc));
bellard9d27abd2003-05-10 13:13:54 +0000564#endif
bellard8a40a182005-11-20 10:35:40 +0000565 /* see if we can patch the calling TB. When the TB
566 spans two pages, we cannot safely do a direct
567 jump. */
Paolo Bonzini040f2fb2010-01-15 08:56:36 +0100568 if (next_tb != 0 && tb->page_addr[1] == -1) {
blueswir1b5fc09a2008-05-04 06:38:18 +0000569 tb_add_jump((TranslationBlock *)(next_tb & ~3), next_tb & 3, tb);
bellard3fb2ded2003-06-24 13:22:59 +0000570 }
pbrookd5975362008-06-07 20:50:51 +0000571 spin_unlock(&tb_lock);
malc55e8b852008-11-04 14:18:13 +0000572
573 /* cpu_interrupt might be called while translating the
574 TB, but before it is linked into a potentially
575 infinite loop and becomes env->current_tb. Avoid
576 starting execution if there is a pending interrupt. */
Jan Kiszkab0052d12010-06-25 16:56:50 +0200577 env->current_tb = tb;
578 barrier();
579 if (likely(!env->exit_request)) {
pbrook2e70f6e2008-06-29 01:03:05 +0000580 tc_ptr = tb->tc_ptr;
bellard3fb2ded2003-06-24 13:22:59 +0000581 /* execute the generated code */
Juan Quinteladfe5fff2009-07-27 16:12:40 +0200582#if defined(__sparc__) && !defined(CONFIG_SOLARIS)
blueswir1572a9d42008-05-17 07:38:10 +0000583#undef env
pbrook2e70f6e2008-06-29 01:03:05 +0000584 env = cpu_single_env;
blueswir1572a9d42008-05-17 07:38:10 +0000585#define env cpu_single_env
586#endif
pbrook2e70f6e2008-06-29 01:03:05 +0000587 next_tb = tcg_qemu_tb_exec(tc_ptr);
pbrook2e70f6e2008-06-29 01:03:05 +0000588 if ((next_tb & 3) == 2) {
thsbf20dc02008-06-30 17:22:19 +0000589 /* Instruction counter expired. */
pbrook2e70f6e2008-06-29 01:03:05 +0000590 int insns_left;
591 tb = (TranslationBlock *)(long)(next_tb & ~3);
592 /* Restore PC. */
aliguori622ed362008-11-18 19:36:03 +0000593 cpu_pc_from_tb(env, tb);
pbrook2e70f6e2008-06-29 01:03:05 +0000594 insns_left = env->icount_decr.u32;
595 if (env->icount_extra && insns_left >= 0) {
596 /* Refill decrementer and continue execution. */
597 env->icount_extra += insns_left;
598 if (env->icount_extra > 0xffff) {
599 insns_left = 0xffff;
600 } else {
601 insns_left = env->icount_extra;
602 }
603 env->icount_extra -= insns_left;
604 env->icount_decr.u16.low = insns_left;
605 } else {
606 if (insns_left > 0) {
607 /* Execute remaining instructions. */
608 cpu_exec_nocache(insns_left, tb);
609 }
610 env->exception_index = EXCP_INTERRUPT;
611 next_tb = 0;
Blue Swirl1162c042011-05-14 12:52:35 +0000612 cpu_loop_exit(env);
pbrook2e70f6e2008-06-29 01:03:05 +0000613 }
614 }
615 }
Jan Kiszkab0052d12010-06-25 16:56:50 +0200616 env->current_tb = NULL;
bellard4cbf74b2003-08-10 21:48:43 +0000617 /* reset soft MMU for next block (it can currently
618 only be set by a memory fault) */
ths50a518e2007-06-03 18:52:15 +0000619 } /* for(;;) */
bellard7d132992003-03-06 23:23:54 +0000620 }
bellard3fb2ded2003-06-24 13:22:59 +0000621 } /* for(;;) */
622
bellard7d132992003-03-06 23:23:54 +0000623
bellarde4533c72003-06-15 19:51:39 +0000624#if defined(TARGET_I386)
bellard9de5e442003-03-23 16:49:39 +0000625 /* restore flags in standard format */
Blue Swirle694d4e2011-05-16 19:38:48 +0000626 env->eflags = env->eflags | cpu_cc_compute_all(env, CC_OP)
627 | (DF & DF_MASK);
bellarde4533c72003-06-15 19:51:39 +0000628#elif defined(TARGET_ARM)
bellardb7bcbe92005-02-22 19:27:29 +0000629 /* XXX: Save/restore host fpu exception state?. */
Guan Xuetaod2fbca92011-04-12 16:27:03 +0800630#elif defined(TARGET_UNICORE32)
bellard93ac68b2003-09-30 20:57:29 +0000631#elif defined(TARGET_SPARC)
bellard67867302003-11-23 17:05:30 +0000632#elif defined(TARGET_PPC)
Michael Walle81ea0e12011-02-17 23:45:02 +0100633#elif defined(TARGET_LM32)
pbrooke6e59062006-10-22 00:18:54 +0000634#elif defined(TARGET_M68K)
635 cpu_m68k_flush_flags(env, env->cc_op);
636 env->cc_op = CC_OP_FLAGS;
637 env->sr = (env->sr & 0xffe0)
638 | env->cc_dest | (env->cc_x << 4);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +0200639#elif defined(TARGET_MICROBLAZE)
bellard6af0bf92005-07-02 14:58:51 +0000640#elif defined(TARGET_MIPS)
bellardfdf9b3e2006-04-27 21:07:38 +0000641#elif defined(TARGET_SH4)
j_mayereddf68a2007-04-05 07:22:49 +0000642#elif defined(TARGET_ALPHA)
thsf1ccf902007-10-08 13:16:14 +0000643#elif defined(TARGET_CRIS)
Alexander Graf10ec5112009-12-05 12:44:21 +0100644#elif defined(TARGET_S390X)
bellardfdf9b3e2006-04-27 21:07:38 +0000645 /* XXXXX */
bellarde4533c72003-06-15 19:51:39 +0000646#else
647#error unsupported target CPU
648#endif
pbrook1057eaa2007-02-04 13:37:44 +0000649
650 /* restore global registers */
Jan Kiszka1d93f0f2010-06-25 16:56:49 +0200651 barrier();
Paolo Bonzini24ebf5f2010-02-18 21:25:23 +0100652 env = (void *) saved_env_reg;
pbrook1057eaa2007-02-04 13:37:44 +0000653
bellard6a00d602005-11-21 23:25:50 +0000654 /* fail safe : never use cpu_single_env outside cpu_exec() */
ths5fafdf22007-09-16 21:08:06 +0000655 cpu_single_env = NULL;
bellard7d132992003-03-06 23:23:54 +0000656 return ret;
657}