blob: afb9ebc3b7d1fc144fb76693b2db71a35396ab86 [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
David 'Digit' Turnera5d41202010-05-10 18:37:10 -070017 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080018 */
19#include "config.h"
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080020#include "exec.h"
David 'Digit' Turnercc33b2d2013-12-15 00:09:42 +010021#include "disas/disas.h"
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080022#include "tcg.h"
David 'Digit' Turner34c48ff2013-12-15 00:25:03 +010023#include "sysemu/kvm.h"
David 'Digit' Turnere1e03df2013-12-15 00:42:21 +010024#include "exec/hax.h"
25#include "qemu/atomic.h"
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080026
27#if !defined(CONFIG_SOFTMMU)
28#undef EAX
29#undef ECX
30#undef EDX
31#undef EBX
32#undef ESP
33#undef EBP
34#undef ESI
35#undef EDI
36#undef EIP
37#include <signal.h>
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -070038#ifdef __linux__
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080039#include <sys/ucontext.h>
40#endif
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -070041#endif
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080042
David 'Digit' Turner2c538c82010-05-10 16:48:20 -070043#if defined(__sparc__) && !defined(CONFIG_SOLARIS)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080044// Work around ugly bugs in glibc that mangle global register contents
45#undef env
46#define env cpu_single_env
47#endif
48
49int tb_invalidated_flag;
50
David 'Digit' Turnera5d41202010-05-10 18:37:10 -070051//#define CONFIG_DEBUG_EXEC
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080052//#define DEBUG_SIGNAL
53
David 'Digit' Turnere2678e12014-01-16 15:56:43 +010054int qemu_cpu_has_work(CPUOldState *env)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -070055{
56 return cpu_has_work(env);
57}
58
David 'Digit' Turner85c62202014-02-16 20:53:40 +010059void cpu_loop_exit(CPUArchState* env1)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080060{
David 'Digit' Turner85c62202014-02-16 20:53:40 +010061 env1->current_tb = NULL;
62 longjmp(env1->jmp_env, 1);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080063}
64
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080065/* exit the current TB from a signal handler. The host registers are
66 restored in a state compatible with the CPU emulator
67 */
David 'Digit' Turner4d6613c2014-01-22 18:19:00 +010068void cpu_resume_from_signal(CPUArchState *env1, void *puc)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080069{
70#if !defined(CONFIG_SOFTMMU)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -070071#ifdef __linux__
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080072 struct ucontext *uc = puc;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -070073#elif defined(__OpenBSD__)
74 struct sigcontext *uc = puc;
75#endif
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080076#endif
77
78 env = env1;
79
80 /* XXX: restore cpu registers saved in host registers */
81
82#if !defined(CONFIG_SOFTMMU)
83 if (puc) {
84 /* XXX: use siglongjmp ? */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -070085#ifdef __linux__
David Turner24cd25a2010-09-10 14:22:27 +020086#ifdef __ia64
87 sigprocmask(SIG_SETMASK, (sigset_t *)&uc->uc_sigmask, NULL);
88#else
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080089 sigprocmask(SIG_SETMASK, &uc->uc_sigmask, NULL);
David Turner24cd25a2010-09-10 14:22:27 +020090#endif
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -070091#elif defined(__OpenBSD__)
92 sigprocmask(SIG_SETMASK, &uc->sc_mask, NULL);
93#endif
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080094 }
95#endif
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -070096 env->exception_index = -1;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080097 longjmp(env->jmp_env, 1);
98}
99
100/* Execute the code without caching the generated code. An interpreter
101 could be used if available. */
102static void cpu_exec_nocache(int max_cycles, TranslationBlock *orig_tb)
103{
104 unsigned long next_tb;
105 TranslationBlock *tb;
106
107 /* Should never happen.
108 We only end up here when an existing TB is too long. */
109 if (max_cycles > CF_COUNT_MASK)
110 max_cycles = CF_COUNT_MASK;
111
112 tb = tb_gen_code(env, orig_tb->pc, orig_tb->cs_base, orig_tb->flags,
113 max_cycles);
114 env->current_tb = tb;
115 /* execute the generated code */
116 next_tb = tcg_qemu_tb_exec(tb->tc_ptr);
David Turner24cd25a2010-09-10 14:22:27 +0200117 env->current_tb = NULL;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800118
119 if ((next_tb & 3) == 2) {
120 /* Restore PC. This may happen if async event occurs before
121 the TB starts executing. */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700122 cpu_pc_from_tb(env, tb);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800123 }
124 tb_phys_invalidate(tb, -1);
125 tb_free(tb);
126}
127
128static TranslationBlock *tb_find_slow(target_ulong pc,
129 target_ulong cs_base,
130 uint64_t flags)
131{
132 TranslationBlock *tb, **ptb1;
133 unsigned int h;
134 target_ulong phys_pc, phys_page1, phys_page2, virt_page2;
135
136 tb_invalidated_flag = 0;
137
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800138 /* find translated block using physical mappings */
David 'Digit' Turner13487772014-02-17 21:16:46 +0100139 phys_pc = get_page_addr_code(env, pc);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800140 phys_page1 = phys_pc & TARGET_PAGE_MASK;
141 phys_page2 = -1;
142 h = tb_phys_hash_func(phys_pc);
David 'Digit' Turner13487772014-02-17 21:16:46 +0100143 ptb1 = &tcg_ctx.tb_ctx.tb_phys_hash[h];
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800144 for(;;) {
145 tb = *ptb1;
146 if (!tb)
147 goto not_found;
148 if (tb->pc == pc &&
149 tb->page_addr[0] == phys_page1 &&
150 tb->cs_base == cs_base &&
151 tb->flags == flags) {
152 /* check next page if needed */
153 if (tb->page_addr[1] != -1) {
154 virt_page2 = (pc & TARGET_PAGE_MASK) +
155 TARGET_PAGE_SIZE;
David 'Digit' Turner13487772014-02-17 21:16:46 +0100156 phys_page2 = get_page_addr_code(env, virt_page2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800157 if (tb->page_addr[1] == phys_page2)
158 goto found;
159 } else {
160 goto found;
161 }
162 }
163 ptb1 = &tb->phys_hash_next;
164 }
165 not_found:
166 /* if no translated code available, then translate it now */
167 tb = tb_gen_code(env, pc, cs_base, flags, 0);
168
169 found:
David 'Digit' Turner52858642011-06-03 13:41:05 +0200170 /* Move the last found TB to the head of the list */
171 if (likely(*ptb1)) {
172 *ptb1 = tb->phys_hash_next;
David 'Digit' Turner13487772014-02-17 21:16:46 +0100173 tb->phys_hash_next = tcg_ctx.tb_ctx.tb_phys_hash[h];
174 tcg_ctx.tb_ctx.tb_phys_hash[h] = tb;
David 'Digit' Turner52858642011-06-03 13:41:05 +0200175 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800176 /* we add the TB in the virtual pc hash table */
177 env->tb_jmp_cache[tb_jmp_cache_hash_func(pc)] = tb;
178 return tb;
179}
180
181static inline TranslationBlock *tb_find_fast(void)
182{
183 TranslationBlock *tb;
184 target_ulong cs_base, pc;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700185 int flags;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800186
187 /* we record a subset of the CPU state. It will
188 always be the same before a given translated block
189 is executed. */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700190 cpu_get_tb_cpu_state(env, &pc, &cs_base, &flags);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800191 tb = env->tb_jmp_cache[tb_jmp_cache_hash_func(pc)];
192 if (unlikely(!tb || tb->pc != pc || tb->cs_base != cs_base ||
193 tb->flags != flags)) {
194 tb = tb_find_slow(pc, cs_base, flags);
195 }
196 return tb;
197}
198
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700199static CPUDebugExcpHandler *debug_excp_handler;
200
David 'Digit' Turner13487772014-02-17 21:16:46 +0100201void cpu_set_debug_excp_handler(CPUDebugExcpHandler *handler)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700202{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700203 debug_excp_handler = handler;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700204}
205
David 'Digit' Turnere2678e12014-01-16 15:56:43 +0100206static void cpu_handle_debug_exception(CPUOldState *env)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700207{
208 CPUWatchpoint *wp;
209
David 'Digit' Turner42760382011-05-11 01:48:19 +0200210 if (!env->watchpoint_hit) {
211 QTAILQ_FOREACH(wp, &env->watchpoints, entry) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700212 wp->flags &= ~BP_WATCHPOINT_HIT;
David 'Digit' Turner42760382011-05-11 01:48:19 +0200213 }
214 }
215 if (debug_excp_handler) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700216 debug_excp_handler(env);
David 'Digit' Turner42760382011-05-11 01:48:19 +0200217 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700218}
219
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800220/* main execution loop */
221
David Turner24cd25a2010-09-10 14:22:27 +0200222volatile sig_atomic_t exit_request;
223
Jun Nakajimaa381ef02011-12-17 19:13:25 -0800224/*
225 * Qemu emulation can happen because of MMIO or emulation mode,
226 * i.e. non-PG mode. For MMIO cases, the pending interrupt should not
227 * be emulated in qemu because MMIO is emulated for only one
228 * instruction now and then back to the HAX kernel module.
229 */
David 'Digit' Turnere2678e12014-01-16 15:56:43 +0100230int need_handle_intr_request(CPUOldState *env)
Jun Nakajimaa381ef02011-12-17 19:13:25 -0800231{
232#ifdef CONFIG_HAX
233 if (!hax_enabled() || hax_vcpu_emulation_mode(env))
234 return env->interrupt_request;
235 return 0;
236#else
237 return env->interrupt_request;
238#endif
239}
240
David 'Digit' Turnere2678e12014-01-16 15:56:43 +0100241int cpu_exec(CPUOldState *env1)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800242{
David Turner24cd25a2010-09-10 14:22:27 +0200243 volatile host_reg_t saved_env_reg;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800244 int ret, interrupt_request;
245 TranslationBlock *tb;
246 uint8_t *tc_ptr;
247 unsigned long next_tb;
248
David 'Digit' Turner52858642011-06-03 13:41:05 +0200249 if (env1->halted) {
250 if (!cpu_has_work(env1)) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800251 return EXCP_HALTED;
David 'Digit' Turner52858642011-06-03 13:41:05 +0200252 }
253
254 env1->halted = 0;
255 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800256
257 cpu_single_env = env1;
258
David Turner24cd25a2010-09-10 14:22:27 +0200259 /* the access to env below is actually saving the global register's
260 value, so that files not including target-xyz/exec.h are free to
261 use it. */
262 QEMU_BUILD_BUG_ON (sizeof (saved_env_reg) != sizeof (env));
263 saved_env_reg = (host_reg_t) env;
264 barrier();
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800265 env = env1;
266
David Turner24cd25a2010-09-10 14:22:27 +0200267 if (unlikely(exit_request)) {
268 env->exit_request = 1;
269 }
270
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800271#if defined(TARGET_I386)
David Turner24cd25a2010-09-10 14:22:27 +0200272 if (!kvm_enabled()) {
273 /* put eflags in CPU temporary format */
274 CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
275 DF = 1 - (2 * ((env->eflags >> 10) & 1));
276 CC_OP = CC_OP_EFLAGS;
277 env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
278 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800279#elif defined(TARGET_SPARC)
280#elif defined(TARGET_M68K)
281 env->cc_op = CC_OP_FLAGS;
282 env->cc_dest = env->sr & 0xf;
283 env->cc_x = (env->sr >> 4) & 1;
284#elif defined(TARGET_ALPHA)
285#elif defined(TARGET_ARM)
David 'Digit' Turner42760382011-05-11 01:48:19 +0200286#elif defined(TARGET_UNICORE32)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800287#elif defined(TARGET_PPC)
David 'Digit' Turner42760382011-05-11 01:48:19 +0200288#elif defined(TARGET_LM32)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700289#elif defined(TARGET_MICROBLAZE)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800290#elif defined(TARGET_MIPS)
291#elif defined(TARGET_SH4)
292#elif defined(TARGET_CRIS)
David 'Digit' Turnera5d41202010-05-10 18:37:10 -0700293#elif defined(TARGET_S390X)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800294 /* XXXXX */
295#else
296#error unsupported target CPU
297#endif
298 env->exception_index = -1;
299
300 /* prepare setjmp context for exception handling */
301 for(;;) {
302 if (setjmp(env->jmp_env) == 0) {
David 'Digit' Turner2c538c82010-05-10 16:48:20 -0700303#if defined(__sparc__) && !defined(CONFIG_SOLARIS)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700304#undef env
305 env = cpu_single_env;
306#define env cpu_single_env
307#endif
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800308 /* if an exception is pending, we execute it here */
309 if (env->exception_index >= 0) {
310 if (env->exception_index >= EXCP_INTERRUPT) {
311 /* exit request from the cpu execution loop */
312 ret = env->exception_index;
David 'Digit' Turner42760382011-05-11 01:48:19 +0200313 if (ret == EXCP_DEBUG) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700314 cpu_handle_debug_exception(env);
David 'Digit' Turner42760382011-05-11 01:48:19 +0200315 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800316 break;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700317 } else {
318#if defined(CONFIG_USER_ONLY)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800319 /* if user mode only, we simulate a fake exception
320 which will be handled outside the cpu execution
321 loop */
322#if defined(TARGET_I386)
323 do_interrupt_user(env->exception_index,
324 env->exception_is_int,
325 env->error_code,
326 env->exception_next_eip);
327 /* successfully delivered */
328 env->old_exception = -1;
329#endif
330 ret = env->exception_index;
331 break;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700332#else
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800333#if defined(TARGET_I386)
334 /* simulate a real cpu exception. On i386, it can
335 trigger new exceptions, but we do not handle
336 double or triple faults yet. */
337 do_interrupt(env->exception_index,
338 env->exception_is_int,
339 env->error_code,
340 env->exception_next_eip, 0);
341 /* successfully delivered */
342 env->old_exception = -1;
343#elif defined(TARGET_PPC)
344 do_interrupt(env);
David 'Digit' Turner42760382011-05-11 01:48:19 +0200345#elif defined(TARGET_LM32)
346 do_interrupt(env);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700347#elif defined(TARGET_MICROBLAZE)
348 do_interrupt(env);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800349#elif defined(TARGET_MIPS)
350 do_interrupt(env);
351#elif defined(TARGET_SPARC)
352 do_interrupt(env);
353#elif defined(TARGET_ARM)
354 do_interrupt(env);
David 'Digit' Turner42760382011-05-11 01:48:19 +0200355#elif defined(TARGET_UNICORE32)
356 do_interrupt(env);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800357#elif defined(TARGET_SH4)
358 do_interrupt(env);
359#elif defined(TARGET_ALPHA)
360 do_interrupt(env);
361#elif defined(TARGET_CRIS)
362 do_interrupt(env);
363#elif defined(TARGET_M68K)
364 do_interrupt(0);
David 'Digit' Turner42760382011-05-11 01:48:19 +0200365#elif defined(TARGET_S390X)
366 do_interrupt(env);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800367#endif
David 'Digit' Turnera5d41202010-05-10 18:37:10 -0700368 env->exception_index = -1;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700369#endif
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800370 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800371 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800372
Jun Nakajimaa381ef02011-12-17 19:13:25 -0800373#ifdef CONFIG_HAX
374 if (hax_enabled() && !hax_vcpu_exec(env))
375 longjmp(env->jmp_env, 1);
376#endif
377
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700378 if (kvm_enabled()) {
379 kvm_cpu_exec(env);
380 longjmp(env->jmp_env, 1);
381 }
382
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800383 next_tb = 0; /* force lookup of first TB */
384 for(;;) {
385 interrupt_request = env->interrupt_request;
Jun Nakajimaa381ef02011-12-17 19:13:25 -0800386 if (unlikely(need_handle_intr_request(env))) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700387 if (unlikely(env->singlestep_enabled & SSTEP_NOIRQ)) {
388 /* Mask out external interrupts for this step. */
David 'Digit' Turner52858642011-06-03 13:41:05 +0200389 interrupt_request &= ~CPU_INTERRUPT_SSTEP_MASK;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700390 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800391 if (interrupt_request & CPU_INTERRUPT_DEBUG) {
392 env->interrupt_request &= ~CPU_INTERRUPT_DEBUG;
393 env->exception_index = EXCP_DEBUG;
David 'Digit' Turner85c62202014-02-16 20:53:40 +0100394 cpu_loop_exit(env);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800395 }
396#if defined(TARGET_ARM) || defined(TARGET_SPARC) || defined(TARGET_MIPS) || \
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700397 defined(TARGET_PPC) || defined(TARGET_ALPHA) || defined(TARGET_CRIS) || \
David 'Digit' Turner42760382011-05-11 01:48:19 +0200398 defined(TARGET_MICROBLAZE) || defined(TARGET_LM32) || defined(TARGET_UNICORE32)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800399 if (interrupt_request & CPU_INTERRUPT_HALT) {
400 env->interrupt_request &= ~CPU_INTERRUPT_HALT;
401 env->halted = 1;
402 env->exception_index = EXCP_HLT;
David 'Digit' Turner85c62202014-02-16 20:53:40 +0100403 cpu_loop_exit(env);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800404 }
405#endif
406#if defined(TARGET_I386)
David 'Digit' Turnera5d41202010-05-10 18:37:10 -0700407 if (interrupt_request & CPU_INTERRUPT_INIT) {
408 svm_check_intercept(SVM_EXIT_INIT);
409 do_cpu_init(env);
410 env->exception_index = EXCP_HALTED;
David 'Digit' Turner85c62202014-02-16 20:53:40 +0100411 cpu_loop_exit(env);
David 'Digit' Turnera5d41202010-05-10 18:37:10 -0700412 } else if (interrupt_request & CPU_INTERRUPT_SIPI) {
413 do_cpu_sipi(env);
414 } else if (env->hflags2 & HF2_GIF_MASK) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800415 if ((interrupt_request & CPU_INTERRUPT_SMI) &&
416 !(env->hflags & HF_SMM_MASK)) {
417 svm_check_intercept(SVM_EXIT_SMI);
418 env->interrupt_request &= ~CPU_INTERRUPT_SMI;
419 do_smm_enter();
420 next_tb = 0;
421 } else if ((interrupt_request & CPU_INTERRUPT_NMI) &&
422 !(env->hflags2 & HF2_NMI_MASK)) {
423 env->interrupt_request &= ~CPU_INTERRUPT_NMI;
424 env->hflags2 |= HF2_NMI_MASK;
425 do_interrupt(EXCP02_NMI, 0, 0, 0, 1);
426 next_tb = 0;
David 'Digit' Turnera5d41202010-05-10 18:37:10 -0700427 } else if (interrupt_request & CPU_INTERRUPT_MCE) {
428 env->interrupt_request &= ~CPU_INTERRUPT_MCE;
429 do_interrupt(EXCP12_MCHK, 0, 0, 0, 0);
430 next_tb = 0;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800431 } else if ((interrupt_request & CPU_INTERRUPT_HARD) &&
David 'Digit' Turnerf645f7d2011-05-11 00:44:05 +0200432 (((env->hflags2 & HF2_VINTR_MASK) &&
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800433 (env->hflags2 & HF2_HIF_MASK)) ||
David 'Digit' Turnerf645f7d2011-05-11 00:44:05 +0200434 (!(env->hflags2 & HF2_VINTR_MASK) &&
435 (env->eflags & IF_MASK &&
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800436 !(env->hflags & HF_INHIBIT_IRQ_MASK))))) {
437 int intno;
438 svm_check_intercept(SVM_EXIT_INTR);
439 env->interrupt_request &= ~(CPU_INTERRUPT_HARD | CPU_INTERRUPT_VIRQ);
440 intno = cpu_get_pic_interrupt(env);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700441 qemu_log_mask(CPU_LOG_TB_IN_ASM, "Servicing hardware INT=0x%02x\n", intno);
David 'Digit' Turner2c538c82010-05-10 16:48:20 -0700442#if defined(__sparc__) && !defined(CONFIG_SOLARIS)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700443#undef env
444 env = cpu_single_env;
445#define env cpu_single_env
446#endif
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800447 do_interrupt(intno, 0, 0, 0, 1);
448 /* ensure that no TB jump will be modified as
449 the program flow was changed */
450 next_tb = 0;
451#if !defined(CONFIG_USER_ONLY)
452 } else if ((interrupt_request & CPU_INTERRUPT_VIRQ) &&
David 'Digit' Turnerf645f7d2011-05-11 00:44:05 +0200453 (env->eflags & IF_MASK) &&
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800454 !(env->hflags & HF_INHIBIT_IRQ_MASK)) {
455 int intno;
456 /* FIXME: this should respect TPR */
457 svm_check_intercept(SVM_EXIT_VINTR);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800458 intno = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_vector));
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700459 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 -0800460 do_interrupt(intno, 0, 0, 0, 1);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700461 env->interrupt_request &= ~CPU_INTERRUPT_VIRQ;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800462 next_tb = 0;
463#endif
464 }
465 }
466#elif defined(TARGET_PPC)
467#if 0
468 if ((interrupt_request & CPU_INTERRUPT_RESET)) {
David 'Digit' Turnera5d41202010-05-10 18:37:10 -0700469 cpu_reset(env);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800470 }
471#endif
472 if (interrupt_request & CPU_INTERRUPT_HARD) {
473 ppc_hw_interrupt(env);
474 if (env->pending_interrupts == 0)
475 env->interrupt_request &= ~CPU_INTERRUPT_HARD;
476 next_tb = 0;
477 }
David 'Digit' Turner42760382011-05-11 01:48:19 +0200478#elif defined(TARGET_LM32)
479 if ((interrupt_request & CPU_INTERRUPT_HARD)
480 && (env->ie & IE_IE)) {
481 env->exception_index = EXCP_IRQ;
482 do_interrupt(env);
483 next_tb = 0;
484 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700485#elif defined(TARGET_MICROBLAZE)
486 if ((interrupt_request & CPU_INTERRUPT_HARD)
487 && (env->sregs[SR_MSR] & MSR_IE)
488 && !(env->sregs[SR_MSR] & (MSR_EIP | MSR_BIP))
489 && !(env->iflags & (D_FLAG | IMM_FLAG))) {
490 env->exception_index = EXCP_IRQ;
491 do_interrupt(env);
492 next_tb = 0;
493 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800494#elif defined(TARGET_MIPS)
495 if ((interrupt_request & CPU_INTERRUPT_HARD) &&
David 'Digit' Turner42760382011-05-11 01:48:19 +0200496 cpu_mips_hw_interrupts_pending(env)) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800497 /* Raise it */
498 env->exception_index = EXCP_EXT_INTERRUPT;
499 env->error_code = 0;
500 do_interrupt(env);
501 next_tb = 0;
502 }
503#elif defined(TARGET_SPARC)
David Turner24cd25a2010-09-10 14:22:27 +0200504 if (interrupt_request & CPU_INTERRUPT_HARD) {
505 if (cpu_interrupts_enabled(env) &&
506 env->interrupt_index > 0) {
507 int pil = env->interrupt_index & 0xf;
508 int type = env->interrupt_index & 0xf0;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800509
David Turner24cd25a2010-09-10 14:22:27 +0200510 if (((type == TT_EXTINT) &&
511 cpu_pil_allowed(env, pil)) ||
512 type != TT_EXTINT) {
513 env->exception_index = env->interrupt_index;
514 do_interrupt(env);
515 next_tb = 0;
516 }
517 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800518 }
519#elif defined(TARGET_ARM)
520 if (interrupt_request & CPU_INTERRUPT_FIQ
521 && !(env->uncached_cpsr & CPSR_F)) {
522 env->exception_index = EXCP_FIQ;
523 do_interrupt(env);
524 next_tb = 0;
525 }
526 /* ARMv7-M interrupt return works by loading a magic value
527 into the PC. On real hardware the load causes the
528 return to occur. The qemu implementation performs the
529 jump normally, then does the exception return when the
530 CPU tries to execute code at the magic address.
531 This will cause the magic PC value to be pushed to
David 'Digit' Turner52858642011-06-03 13:41:05 +0200532 the stack if an interrupt occurred at the wrong time.
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800533 We avoid this by disabling interrupts when
534 pc contains a magic address. */
535 if (interrupt_request & CPU_INTERRUPT_HARD
536 && ((IS_M(env) && env->regs[15] < 0xfffffff0)
537 || !(env->uncached_cpsr & CPSR_I))) {
538 env->exception_index = EXCP_IRQ;
539 do_interrupt(env);
540 next_tb = 0;
541 }
David 'Digit' Turner42760382011-05-11 01:48:19 +0200542#elif defined(TARGET_UNICORE32)
543 if (interrupt_request & CPU_INTERRUPT_HARD
544 && !(env->uncached_asr & ASR_I)) {
545 do_interrupt(env);
546 next_tb = 0;
547 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800548#elif defined(TARGET_SH4)
549 if (interrupt_request & CPU_INTERRUPT_HARD) {
550 do_interrupt(env);
551 next_tb = 0;
552 }
553#elif defined(TARGET_ALPHA)
554 if (interrupt_request & CPU_INTERRUPT_HARD) {
555 do_interrupt(env);
556 next_tb = 0;
557 }
558#elif defined(TARGET_CRIS)
559 if (interrupt_request & CPU_INTERRUPT_HARD
David Turner24cd25a2010-09-10 14:22:27 +0200560 && (env->pregs[PR_CCS] & I_FLAG)
561 && !env->locked_irq) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800562 env->exception_index = EXCP_IRQ;
563 do_interrupt(env);
564 next_tb = 0;
565 }
566 if (interrupt_request & CPU_INTERRUPT_NMI
567 && (env->pregs[PR_CCS] & M_FLAG)) {
568 env->exception_index = EXCP_NMI;
569 do_interrupt(env);
570 next_tb = 0;
571 }
572#elif defined(TARGET_M68K)
573 if (interrupt_request & CPU_INTERRUPT_HARD
574 && ((env->sr & SR_I) >> SR_I_SHIFT)
575 < env->pending_level) {
576 /* Real hardware gets the interrupt vector via an
577 IACK cycle at this point. Current emulated
578 hardware doesn't rely on this, so we
579 provide/save the vector when the interrupt is
580 first signalled. */
581 env->exception_index = env->pending_vector;
582 do_interrupt(1);
583 next_tb = 0;
584 }
David 'Digit' Turner42760382011-05-11 01:48:19 +0200585#elif defined(TARGET_S390X) && !defined(CONFIG_USER_ONLY)
586 if ((interrupt_request & CPU_INTERRUPT_HARD) &&
587 (env->psw.mask & PSW_MASK_EXT)) {
588 do_interrupt(env);
589 next_tb = 0;
590 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800591#endif
David 'Digit' Turner52858642011-06-03 13:41:05 +0200592 /* Don't use the cached interrupt_request value,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800593 do_interrupt may have updated the EXITTB flag. */
594 if (env->interrupt_request & CPU_INTERRUPT_EXITTB) {
595 env->interrupt_request &= ~CPU_INTERRUPT_EXITTB;
596 /* ensure that no TB jump will be modified as
597 the program flow was changed */
598 next_tb = 0;
599 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700600 }
601 if (unlikely(env->exit_request)) {
602 env->exit_request = 0;
603 env->exception_index = EXCP_INTERRUPT;
David 'Digit' Turner85c62202014-02-16 20:53:40 +0100604 cpu_loop_exit(env);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800605 }
David Turner24cd25a2010-09-10 14:22:27 +0200606#if defined(DEBUG_DISAS) || defined(CONFIG_DEBUG_EXEC)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700607 if (qemu_loglevel_mask(CPU_LOG_TB_CPU)) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800608 /* restore flags in standard format */
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800609#if defined(TARGET_I386)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700610 env->eflags = env->eflags | helper_cc_compute_all(CC_OP) | (DF & DF_MASK);
611 log_cpu_state(env, X86_DUMP_CCOP);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800612 env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800613#elif defined(TARGET_M68K)
614 cpu_m68k_flush_flags(env, env->cc_op);
615 env->cc_op = CC_OP_FLAGS;
616 env->sr = (env->sr & 0xffe0)
617 | env->cc_dest | (env->cc_x << 4);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700618 log_cpu_state(env, 0);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800619#else
David Turner24cd25a2010-09-10 14:22:27 +0200620 log_cpu_state(env, 0);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800621#endif
622 }
David Turner24cd25a2010-09-10 14:22:27 +0200623#endif /* DEBUG_DISAS || CONFIG_DEBUG_EXEC */
David 'Digit' Turner13487772014-02-17 21:16:46 +0100624 spin_lock(&tcg_ctx.tb_ctx.tb_lock);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800625 tb = tb_find_fast();
626 /* Note: we do it here to avoid a gcc bug on Mac OS X when
627 doing it in tb_find_slow */
628 if (tb_invalidated_flag) {
629 /* as some TB could have been invalidated because
630 of memory exceptions while generating the code, we
631 must recompute the hash index here */
632 next_tb = 0;
633 tb_invalidated_flag = 0;
634 }
David Turner24cd25a2010-09-10 14:22:27 +0200635#ifdef CONFIG_DEBUG_EXEC
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700636 qemu_log_mask(CPU_LOG_EXEC, "Trace 0x%08lx [" TARGET_FMT_lx "] %s\n",
637 (long)tb->tc_ptr, tb->pc,
638 lookup_symbol(tb->pc));
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800639#endif
640 /* see if we can patch the calling TB. When the TB
641 spans two pages, we cannot safely do a direct
642 jump. */
David Turner24cd25a2010-09-10 14:22:27 +0200643 if (next_tb != 0 && tb->page_addr[1] == -1) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800644 tb_add_jump((TranslationBlock *)(next_tb & ~3), next_tb & 3, tb);
645 }
David 'Digit' Turner13487772014-02-17 21:16:46 +0100646 spin_unlock(&tcg_ctx.tb_ctx.tb_lock);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700647
648 /* cpu_interrupt might be called while translating the
649 TB, but before it is linked into a potentially
650 infinite loop and becomes env->current_tb. Avoid
651 starting execution if there is a pending interrupt. */
David Turner24cd25a2010-09-10 14:22:27 +0200652 env->current_tb = tb;
653 barrier();
654 if (likely(!env->exit_request)) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800655 tc_ptr = tb->tc_ptr;
656 /* execute the generated code */
David 'Digit' Turner2c538c82010-05-10 16:48:20 -0700657#if defined(__sparc__) && !defined(CONFIG_SOLARIS)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800658#undef env
659 env = cpu_single_env;
660#define env cpu_single_env
661#endif
662 next_tb = tcg_qemu_tb_exec(tc_ptr);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800663 if ((next_tb & 3) == 2) {
664 /* Instruction counter expired. */
665 int insns_left;
666 tb = (TranslationBlock *)(long)(next_tb & ~3);
667 /* Restore PC. */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700668 cpu_pc_from_tb(env, tb);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800669 insns_left = env->icount_decr.u32;
670 if (env->icount_extra && insns_left >= 0) {
671 /* Refill decrementer and continue execution. */
672 env->icount_extra += insns_left;
673 if (env->icount_extra > 0xffff) {
674 insns_left = 0xffff;
675 } else {
676 insns_left = env->icount_extra;
677 }
678 env->icount_extra -= insns_left;
679 env->icount_decr.u16.low = insns_left;
680 } else {
681 if (insns_left > 0) {
682 /* Execute remaining instructions. */
683 cpu_exec_nocache(insns_left, tb);
684 }
685 env->exception_index = EXCP_INTERRUPT;
686 next_tb = 0;
David 'Digit' Turner85c62202014-02-16 20:53:40 +0100687 cpu_loop_exit(env);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800688 }
689 }
690 }
David Turner24cd25a2010-09-10 14:22:27 +0200691 env->current_tb = NULL;
Jun Nakajimaa381ef02011-12-17 19:13:25 -0800692#ifdef CONFIG_HAX
693 if (hax_enabled() && hax_stop_emulation(env))
David 'Digit' Turner85c62202014-02-16 20:53:40 +0100694 cpu_loop_exit(env);
Jun Nakajimaa381ef02011-12-17 19:13:25 -0800695#endif
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800696 /* reset soft MMU for next block (it can currently
697 only be set by a memory fault) */
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800698 } /* for(;;) */
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800699 }
700 } /* for(;;) */
701
702
703#if defined(TARGET_I386)
704 /* restore flags in standard format */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700705 env->eflags = env->eflags | helper_cc_compute_all(CC_OP) | (DF & DF_MASK);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800706#elif defined(TARGET_ARM)
707 /* XXX: Save/restore host fpu exception state?. */
David 'Digit' Turner42760382011-05-11 01:48:19 +0200708#elif defined(TARGET_UNICORE32)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800709#elif defined(TARGET_SPARC)
710#elif defined(TARGET_PPC)
David 'Digit' Turner42760382011-05-11 01:48:19 +0200711#elif defined(TARGET_LM32)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800712#elif defined(TARGET_M68K)
713 cpu_m68k_flush_flags(env, env->cc_op);
714 env->cc_op = CC_OP_FLAGS;
715 env->sr = (env->sr & 0xffe0)
716 | env->cc_dest | (env->cc_x << 4);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700717#elif defined(TARGET_MICROBLAZE)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800718#elif defined(TARGET_MIPS)
719#elif defined(TARGET_SH4)
720#elif defined(TARGET_ALPHA)
721#elif defined(TARGET_CRIS)
David Turner24cd25a2010-09-10 14:22:27 +0200722#elif defined(TARGET_S390X)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800723 /* XXXXX */
724#else
725#error unsupported target CPU
726#endif
727
728 /* restore global registers */
David Turner24cd25a2010-09-10 14:22:27 +0200729 barrier();
730 env = (void *) saved_env_reg;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800731
732 /* fail safe : never use cpu_single_env outside cpu_exec() */
733 cpu_single_env = NULL;
734 return ret;
735}
736
737/* must only be called from the generated code as an exception can be
738 generated */
739void tb_invalidate_page_range(target_ulong start, target_ulong end)
740{
741 /* XXX: cannot enable it yet because it yields to MMU exception
742 where NIP != read address on PowerPC */
743#if 0
744 target_ulong phys_addr;
David 'Digit' Turner13487772014-02-17 21:16:46 +0100745 phys_addr = get_page_addr_code(env, start);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800746 tb_invalidate_phys_page_range(phys_addr, phys_addr + end - start, 0);
747#endif
748}
749
750#if defined(TARGET_I386) && defined(CONFIG_USER_ONLY)
751
752void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector)
753{
754 CPUX86State *saved_env;
755
756 saved_env = env;
757 env = s;
758 if (!(env->cr[0] & CR0_PE_MASK) || (env->eflags & VM_MASK)) {
759 selector &= 0xffff;
760 cpu_x86_load_seg_cache(env, seg_reg, selector,
761 (selector << 4), 0xffff, 0);
762 } else {
763 helper_load_seg(seg_reg, selector);
764 }
765 env = saved_env;
766}
767
768void cpu_x86_fsave(CPUX86State *s, target_ulong ptr, int data32)
769{
770 CPUX86State *saved_env;
771
772 saved_env = env;
773 env = s;
774
775 helper_fsave(ptr, data32);
776
777 env = saved_env;
778}
779
780void cpu_x86_frstor(CPUX86State *s, target_ulong ptr, int data32)
781{
782 CPUX86State *saved_env;
783
784 saved_env = env;
785 env = s;
786
787 helper_frstor(ptr, data32);
788
789 env = saved_env;
790}
791
792#endif /* TARGET_I386 */
793
794#if !defined(CONFIG_SOFTMMU)
795
796#if defined(TARGET_I386)
David Turner24cd25a2010-09-10 14:22:27 +0200797#define EXCEPTION_ACTION raise_exception_err(env->exception_index, env->error_code)
798#else
David 'Digit' Turner85c62202014-02-16 20:53:40 +0100799#define EXCEPTION_ACTION cpu_loop_exit(env)
David Turner24cd25a2010-09-10 14:22:27 +0200800#endif
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800801
802/* 'pc' is the host PC at which the exception was raised. 'address' is
803 the effective address of the memory exception. 'is_write' is 1 if a
804 write caused the exception and otherwise 0'. 'old_set' is the
805 signal set which should be restored */
806static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
807 int is_write, sigset_t *old_set,
808 void *puc)
809{
810 TranslationBlock *tb;
811 int ret;
812
813 if (cpu_single_env)
814 env = cpu_single_env; /* XXX: find a correct solution for multithread */
815#if defined(DEBUG_SIGNAL)
816 qemu_printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
817 pc, address, is_write, *(unsigned long *)old_set);
818#endif
819 /* XXX: locking issue */
820 if (is_write && page_unprotect(h2g(address), pc, puc)) {
821 return 1;
822 }
823
824 /* see if it is an MMU fault */
David Turner24cd25a2010-09-10 14:22:27 +0200825 ret = cpu_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800826 if (ret < 0)
827 return 0; /* not an MMU fault */
828 if (ret == 0)
829 return 1; /* the MMU fault was handled without causing real CPU fault */
830 /* now we have a real cpu fault */
831 tb = tb_find_pc(pc);
832 if (tb) {
833 /* the PC is inside the translated code. It means that we have
834 a virtual CPU fault */
David 'Digit' Turner3e0677d2014-03-07 15:01:06 +0100835 cpu_restore_state(env, pc);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800836 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800837
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800838 /* we restore the process signal mask as the sigreturn should
839 do it (XXX: use sigsetjmp) */
840 sigprocmask(SIG_SETMASK, old_set, NULL);
David Turner24cd25a2010-09-10 14:22:27 +0200841 EXCEPTION_ACTION;
842
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800843 /* never comes here */
844 return 1;
845}
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800846
847#if defined(__i386__)
848
849#if defined(__APPLE__)
850# include <sys/ucontext.h>
851
852# define EIP_sig(context) (*((unsigned long*)&(context)->uc_mcontext->ss.eip))
853# define TRAP_sig(context) ((context)->uc_mcontext->es.trapno)
854# define ERROR_sig(context) ((context)->uc_mcontext->es.err)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700855# define MASK_sig(context) ((context)->uc_sigmask)
David Turner24cd25a2010-09-10 14:22:27 +0200856#elif defined (__NetBSD__)
857# include <ucontext.h>
858
859# define EIP_sig(context) ((context)->uc_mcontext.__gregs[_REG_EIP])
860# define TRAP_sig(context) ((context)->uc_mcontext.__gregs[_REG_TRAPNO])
861# define ERROR_sig(context) ((context)->uc_mcontext.__gregs[_REG_ERR])
862# define MASK_sig(context) ((context)->uc_sigmask)
863#elif defined (__FreeBSD__) || defined(__DragonFly__)
864# include <ucontext.h>
865
866# define EIP_sig(context) (*((unsigned long*)&(context)->uc_mcontext.mc_eip))
867# define TRAP_sig(context) ((context)->uc_mcontext.mc_trapno)
868# define ERROR_sig(context) ((context)->uc_mcontext.mc_err)
869# define MASK_sig(context) ((context)->uc_sigmask)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700870#elif defined(__OpenBSD__)
871# define EIP_sig(context) ((context)->sc_eip)
872# define TRAP_sig(context) ((context)->sc_trapno)
873# define ERROR_sig(context) ((context)->sc_err)
874# define MASK_sig(context) ((context)->sc_mask)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800875#else
876# define EIP_sig(context) ((context)->uc_mcontext.gregs[REG_EIP])
877# define TRAP_sig(context) ((context)->uc_mcontext.gregs[REG_TRAPNO])
878# define ERROR_sig(context) ((context)->uc_mcontext.gregs[REG_ERR])
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700879# define MASK_sig(context) ((context)->uc_sigmask)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800880#endif
881
882int cpu_signal_handler(int host_signum, void *pinfo,
883 void *puc)
884{
885 siginfo_t *info = pinfo;
David Turner24cd25a2010-09-10 14:22:27 +0200886#if defined(__NetBSD__) || defined (__FreeBSD__) || defined(__DragonFly__)
887 ucontext_t *uc = puc;
888#elif defined(__OpenBSD__)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700889 struct sigcontext *uc = puc;
890#else
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800891 struct ucontext *uc = puc;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700892#endif
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800893 unsigned long pc;
894 int trapno;
895
896#ifndef REG_EIP
897/* for glibc 2.1 */
898#define REG_EIP EIP
899#define REG_ERR ERR
900#define REG_TRAPNO TRAPNO
901#endif
902 pc = EIP_sig(uc);
903 trapno = TRAP_sig(uc);
904 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
905 trapno == 0xe ?
906 (ERROR_sig(uc) >> 1) & 1 : 0,
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700907 &MASK_sig(uc), puc);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800908}
909
910#elif defined(__x86_64__)
911
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700912#ifdef __NetBSD__
913#define PC_sig(context) _UC_MACHINE_PC(context)
914#define TRAP_sig(context) ((context)->uc_mcontext.__gregs[_REG_TRAPNO])
915#define ERROR_sig(context) ((context)->uc_mcontext.__gregs[_REG_ERR])
916#define MASK_sig(context) ((context)->uc_sigmask)
917#elif defined(__OpenBSD__)
918#define PC_sig(context) ((context)->sc_rip)
919#define TRAP_sig(context) ((context)->sc_trapno)
920#define ERROR_sig(context) ((context)->sc_err)
921#define MASK_sig(context) ((context)->sc_mask)
David Turner24cd25a2010-09-10 14:22:27 +0200922#elif defined (__FreeBSD__) || defined(__DragonFly__)
923#include <ucontext.h>
924
925#define PC_sig(context) (*((unsigned long*)&(context)->uc_mcontext.mc_rip))
926#define TRAP_sig(context) ((context)->uc_mcontext.mc_trapno)
927#define ERROR_sig(context) ((context)->uc_mcontext.mc_err)
928#define MASK_sig(context) ((context)->uc_sigmask)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700929#else
930#define PC_sig(context) ((context)->uc_mcontext.gregs[REG_RIP])
931#define TRAP_sig(context) ((context)->uc_mcontext.gregs[REG_TRAPNO])
932#define ERROR_sig(context) ((context)->uc_mcontext.gregs[REG_ERR])
933#define MASK_sig(context) ((context)->uc_sigmask)
934#endif
935
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800936int cpu_signal_handler(int host_signum, void *pinfo,
937 void *puc)
938{
939 siginfo_t *info = pinfo;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800940 unsigned long pc;
David Turner24cd25a2010-09-10 14:22:27 +0200941#if defined(__NetBSD__) || defined (__FreeBSD__) || defined(__DragonFly__)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700942 ucontext_t *uc = puc;
943#elif defined(__OpenBSD__)
944 struct sigcontext *uc = puc;
945#else
946 struct ucontext *uc = puc;
947#endif
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800948
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700949 pc = PC_sig(uc);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800950 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700951 TRAP_sig(uc) == 0xe ?
952 (ERROR_sig(uc) >> 1) & 1 : 0,
953 &MASK_sig(uc), puc);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800954}
955
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700956#elif defined(_ARCH_PPC)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800957
958/***********************************************************************
959 * signal context platform-specific definitions
960 * From Wine
961 */
962#ifdef linux
963/* All Registers access - only for local access */
964# define REG_sig(reg_name, context) ((context)->uc_mcontext.regs->reg_name)
965/* Gpr Registers access */
966# define GPR_sig(reg_num, context) REG_sig(gpr[reg_num], context)
967# define IAR_sig(context) REG_sig(nip, context) /* Program counter */
968# define MSR_sig(context) REG_sig(msr, context) /* Machine State Register (Supervisor) */
969# define CTR_sig(context) REG_sig(ctr, context) /* Count register */
970# define XER_sig(context) REG_sig(xer, context) /* User's integer exception register */
971# define LR_sig(context) REG_sig(link, context) /* Link register */
972# define CR_sig(context) REG_sig(ccr, context) /* Condition register */
973/* Float Registers access */
974# define FLOAT_sig(reg_num, context) (((double*)((char*)((context)->uc_mcontext.regs+48*4)))[reg_num])
975# define FPSCR_sig(context) (*(int*)((char*)((context)->uc_mcontext.regs+(48+32*2)*4)))
976/* Exception Registers access */
977# define DAR_sig(context) REG_sig(dar, context)
978# define DSISR_sig(context) REG_sig(dsisr, context)
979# define TRAP_sig(context) REG_sig(trap, context)
980#endif /* linux */
981
David Turner24cd25a2010-09-10 14:22:27 +0200982#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
983#include <ucontext.h>
984# define IAR_sig(context) ((context)->uc_mcontext.mc_srr0)
985# define MSR_sig(context) ((context)->uc_mcontext.mc_srr1)
986# define CTR_sig(context) ((context)->uc_mcontext.mc_ctr)
987# define XER_sig(context) ((context)->uc_mcontext.mc_xer)
988# define LR_sig(context) ((context)->uc_mcontext.mc_lr)
989# define CR_sig(context) ((context)->uc_mcontext.mc_cr)
990/* Exception Registers access */
991# define DAR_sig(context) ((context)->uc_mcontext.mc_dar)
992# define DSISR_sig(context) ((context)->uc_mcontext.mc_dsisr)
993# define TRAP_sig(context) ((context)->uc_mcontext.mc_exc)
994#endif /* __FreeBSD__|| __FreeBSD_kernel__ */
995
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800996#ifdef __APPLE__
997# include <sys/ucontext.h>
998typedef struct ucontext SIGCONTEXT;
999/* All Registers access - only for local access */
1000# define REG_sig(reg_name, context) ((context)->uc_mcontext->ss.reg_name)
1001# define FLOATREG_sig(reg_name, context) ((context)->uc_mcontext->fs.reg_name)
1002# define EXCEPREG_sig(reg_name, context) ((context)->uc_mcontext->es.reg_name)
1003# define VECREG_sig(reg_name, context) ((context)->uc_mcontext->vs.reg_name)
1004/* Gpr Registers access */
1005# define GPR_sig(reg_num, context) REG_sig(r##reg_num, context)
1006# define IAR_sig(context) REG_sig(srr0, context) /* Program counter */
1007# define MSR_sig(context) REG_sig(srr1, context) /* Machine State Register (Supervisor) */
1008# define CTR_sig(context) REG_sig(ctr, context)
1009# define XER_sig(context) REG_sig(xer, context) /* Link register */
1010# define LR_sig(context) REG_sig(lr, context) /* User's integer exception register */
1011# define CR_sig(context) REG_sig(cr, context) /* Condition register */
1012/* Float Registers access */
1013# define FLOAT_sig(reg_num, context) FLOATREG_sig(fpregs[reg_num], context)
1014# define FPSCR_sig(context) ((double)FLOATREG_sig(fpscr, context))
1015/* Exception Registers access */
1016# define DAR_sig(context) EXCEPREG_sig(dar, context) /* Fault registers for coredump */
1017# define DSISR_sig(context) EXCEPREG_sig(dsisr, context)
1018# define TRAP_sig(context) EXCEPREG_sig(exception, context) /* number of powerpc exception taken */
1019#endif /* __APPLE__ */
1020
1021int cpu_signal_handler(int host_signum, void *pinfo,
1022 void *puc)
1023{
1024 siginfo_t *info = pinfo;
David Turner24cd25a2010-09-10 14:22:27 +02001025#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
1026 ucontext_t *uc = puc;
1027#else
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001028 struct ucontext *uc = puc;
David Turner24cd25a2010-09-10 14:22:27 +02001029#endif
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001030 unsigned long pc;
1031 int is_write;
1032
1033 pc = IAR_sig(uc);
1034 is_write = 0;
1035#if 0
1036 /* ppc 4xx case */
1037 if (DSISR_sig(uc) & 0x00800000)
1038 is_write = 1;
1039#else
1040 if (TRAP_sig(uc) != 0x400 && (DSISR_sig(uc) & 0x02000000))
1041 is_write = 1;
1042#endif
1043 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1044 is_write, &uc->uc_sigmask, puc);
1045}
1046
1047#elif defined(__alpha__)
1048
1049int cpu_signal_handler(int host_signum, void *pinfo,
1050 void *puc)
1051{
1052 siginfo_t *info = pinfo;
1053 struct ucontext *uc = puc;
1054 uint32_t *pc = uc->uc_mcontext.sc_pc;
1055 uint32_t insn = *pc;
1056 int is_write = 0;
1057
1058 /* XXX: need kernel patch to get write flag faster */
1059 switch (insn >> 26) {
1060 case 0x0d: // stw
1061 case 0x0e: // stb
1062 case 0x0f: // stq_u
1063 case 0x24: // stf
1064 case 0x25: // stg
1065 case 0x26: // sts
1066 case 0x27: // stt
1067 case 0x2c: // stl
1068 case 0x2d: // stq
1069 case 0x2e: // stl_c
1070 case 0x2f: // stq_c
1071 is_write = 1;
1072 }
1073
1074 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1075 is_write, &uc->uc_sigmask, puc);
1076}
1077#elif defined(__sparc__)
1078
1079int cpu_signal_handler(int host_signum, void *pinfo,
1080 void *puc)
1081{
1082 siginfo_t *info = pinfo;
1083 int is_write;
1084 uint32_t insn;
David 'Digit' Turner2c538c82010-05-10 16:48:20 -07001085#if !defined(__arch64__) || defined(CONFIG_SOLARIS)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001086 uint32_t *regs = (uint32_t *)(info + 1);
1087 void *sigmask = (regs + 20);
1088 /* XXX: is there a standard glibc define ? */
1089 unsigned long pc = regs[1];
1090#else
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001091#ifdef __linux__
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001092 struct sigcontext *sc = puc;
1093 unsigned long pc = sc->sigc_regs.tpc;
1094 void *sigmask = (void *)sc->sigc_mask;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001095#elif defined(__OpenBSD__)
1096 struct sigcontext *uc = puc;
1097 unsigned long pc = uc->sc_pc;
1098 void *sigmask = (void *)(long)uc->sc_mask;
1099#endif
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001100#endif
1101
1102 /* XXX: need kernel patch to get write flag faster */
1103 is_write = 0;
1104 insn = *(uint32_t *)pc;
1105 if ((insn >> 30) == 3) {
1106 switch((insn >> 19) & 0x3f) {
1107 case 0x05: // stb
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001108 case 0x15: // stba
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001109 case 0x06: // sth
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001110 case 0x16: // stha
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001111 case 0x04: // st
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001112 case 0x14: // sta
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001113 case 0x07: // std
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001114 case 0x17: // stda
1115 case 0x0e: // stx
1116 case 0x1e: // stxa
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001117 case 0x24: // stf
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001118 case 0x34: // stfa
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001119 case 0x27: // stdf
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001120 case 0x37: // stdfa
1121 case 0x26: // stqf
1122 case 0x36: // stqfa
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001123 case 0x25: // stfsr
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001124 case 0x3c: // casa
1125 case 0x3e: // casxa
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001126 is_write = 1;
1127 break;
1128 }
1129 }
1130 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1131 is_write, sigmask, NULL);
1132}
1133
1134#elif defined(__arm__)
1135
1136int cpu_signal_handler(int host_signum, void *pinfo,
1137 void *puc)
1138{
1139 siginfo_t *info = pinfo;
1140 struct ucontext *uc = puc;
1141 unsigned long pc;
1142 int is_write;
1143
1144#if (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ <= 3))
1145 pc = uc->uc_mcontext.gregs[R15];
1146#else
1147 pc = uc->uc_mcontext.arm_pc;
1148#endif
1149 /* XXX: compute is_write */
1150 is_write = 0;
1151 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1152 is_write,
1153 &uc->uc_sigmask, puc);
1154}
1155
1156#elif defined(__mc68000)
1157
1158int cpu_signal_handler(int host_signum, void *pinfo,
1159 void *puc)
1160{
1161 siginfo_t *info = pinfo;
1162 struct ucontext *uc = puc;
1163 unsigned long pc;
1164 int is_write;
1165
1166 pc = uc->uc_mcontext.gregs[16];
1167 /* XXX: compute is_write */
1168 is_write = 0;
1169 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1170 is_write,
1171 &uc->uc_sigmask, puc);
1172}
1173
1174#elif defined(__ia64)
1175
1176#ifndef __ISR_VALID
1177 /* This ought to be in <bits/siginfo.h>... */
1178# define __ISR_VALID 1
1179#endif
1180
1181int cpu_signal_handler(int host_signum, void *pinfo, void *puc)
1182{
1183 siginfo_t *info = pinfo;
1184 struct ucontext *uc = puc;
1185 unsigned long ip;
1186 int is_write = 0;
1187
1188 ip = uc->uc_mcontext.sc_ip;
1189 switch (host_signum) {
1190 case SIGILL:
1191 case SIGFPE:
1192 case SIGSEGV:
1193 case SIGBUS:
1194 case SIGTRAP:
1195 if (info->si_code && (info->si_segvflags & __ISR_VALID))
1196 /* ISR.W (write-access) is bit 33: */
1197 is_write = (info->si_isr >> 33) & 1;
1198 break;
1199
1200 default:
1201 break;
1202 }
1203 return handle_cpu_signal(ip, (unsigned long)info->si_addr,
1204 is_write,
David Turner24cd25a2010-09-10 14:22:27 +02001205 (sigset_t *)&uc->uc_sigmask, puc);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001206}
1207
1208#elif defined(__s390__)
1209
1210int cpu_signal_handler(int host_signum, void *pinfo,
1211 void *puc)
1212{
1213 siginfo_t *info = pinfo;
1214 struct ucontext *uc = puc;
1215 unsigned long pc;
David Turner24cd25a2010-09-10 14:22:27 +02001216 uint16_t *pinsn;
1217 int is_write = 0;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001218
1219 pc = uc->uc_mcontext.psw.addr;
David Turner24cd25a2010-09-10 14:22:27 +02001220
1221 /* ??? On linux, the non-rt signal handler has 4 (!) arguments instead
1222 of the normal 2 arguments. The 3rd argument contains the "int_code"
1223 from the hardware which does in fact contain the is_write value.
1224 The rt signal handler, as far as I can tell, does not give this value
1225 at all. Not that we could get to it from here even if it were. */
1226 /* ??? This is not even close to complete, since it ignores all
1227 of the read-modify-write instructions. */
1228 pinsn = (uint16_t *)pc;
1229 switch (pinsn[0] >> 8) {
1230 case 0x50: /* ST */
1231 case 0x42: /* STC */
1232 case 0x40: /* STH */
1233 is_write = 1;
1234 break;
1235 case 0xc4: /* RIL format insns */
1236 switch (pinsn[0] & 0xf) {
1237 case 0xf: /* STRL */
1238 case 0xb: /* STGRL */
1239 case 0x7: /* STHRL */
1240 is_write = 1;
1241 }
1242 break;
1243 case 0xe3: /* RXY format insns */
1244 switch (pinsn[2] & 0xff) {
1245 case 0x50: /* STY */
1246 case 0x24: /* STG */
1247 case 0x72: /* STCY */
1248 case 0x70: /* STHY */
1249 case 0x8e: /* STPQ */
1250 case 0x3f: /* STRVH */
1251 case 0x3e: /* STRV */
1252 case 0x2f: /* STRVG */
1253 is_write = 1;
1254 }
1255 break;
1256 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001257 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1258 is_write, &uc->uc_sigmask, puc);
1259}
1260
1261#elif defined(__mips__)
1262
1263int cpu_signal_handler(int host_signum, void *pinfo,
1264 void *puc)
1265{
1266 siginfo_t *info = pinfo;
1267 struct ucontext *uc = puc;
1268 greg_t pc = uc->uc_mcontext.pc;
1269 int is_write;
1270
1271 /* XXX: compute is_write */
1272 is_write = 0;
1273 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1274 is_write, &uc->uc_sigmask, puc);
1275}
1276
1277#elif defined(__hppa__)
1278
1279int cpu_signal_handler(int host_signum, void *pinfo,
1280 void *puc)
1281{
1282 struct siginfo *info = pinfo;
1283 struct ucontext *uc = puc;
David Turner24cd25a2010-09-10 14:22:27 +02001284 unsigned long pc = uc->uc_mcontext.sc_iaoq[0];
1285 uint32_t insn = *(uint32_t *)pc;
1286 int is_write = 0;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001287
David Turner24cd25a2010-09-10 14:22:27 +02001288 /* XXX: need kernel patch to get write flag faster. */
1289 switch (insn >> 26) {
1290 case 0x1a: /* STW */
1291 case 0x19: /* STH */
1292 case 0x18: /* STB */
1293 case 0x1b: /* STWM */
1294 is_write = 1;
1295 break;
1296
1297 case 0x09: /* CSTWX, FSTWX, FSTWS */
1298 case 0x0b: /* CSTDX, FSTDX, FSTDS */
1299 /* Distinguish from coprocessor load ... */
1300 is_write = (insn >> 9) & 1;
1301 break;
1302
1303 case 0x03:
1304 switch ((insn >> 6) & 15) {
1305 case 0xa: /* STWS */
1306 case 0x9: /* STHS */
1307 case 0x8: /* STBS */
1308 case 0xe: /* STWAS */
1309 case 0xc: /* STBYS */
1310 is_write = 1;
1311 }
1312 break;
1313 }
1314
David 'Digit' Turnerf645f7d2011-05-11 00:44:05 +02001315 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
David Turner24cd25a2010-09-10 14:22:27 +02001316 is_write, &uc->uc_sigmask, puc);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001317}
1318
1319#else
1320
1321#error host CPU specific signal handler needed
1322
1323#endif
1324
1325#endif /* !defined(CONFIG_SOFTMMU) */