blob: 79172a2b7a55e0e8ed5393ffc11338fcab56a733 [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' Turner5d8f37a2009-09-14 14:32:27 -070054int qemu_cpu_has_work(CPUState *env)
55{
56 return cpu_has_work(env);
57}
58
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080059void cpu_loop_exit(void)
60{
David Turner24cd25a2010-09-10 14:22:27 +020061 env->current_tb = NULL;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080062 longjmp(env->jmp_env, 1);
63}
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 */
68void cpu_resume_from_signal(CPUState *env1, void *puc)
69{
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 */
139 phys_pc = get_phys_addr_code(env, pc);
140 phys_page1 = phys_pc & TARGET_PAGE_MASK;
141 phys_page2 = -1;
142 h = tb_phys_hash_func(phys_pc);
143 ptb1 = &tb_phys_hash[h];
144 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;
156 phys_page2 = get_phys_addr_code(env, virt_page2);
157 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;
173 tb->phys_hash_next = tb_phys_hash[h];
174 tb_phys_hash[h] = tb;
175 }
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
201CPUDebugExcpHandler *cpu_set_debug_excp_handler(CPUDebugExcpHandler *handler)
202{
203 CPUDebugExcpHandler *old_handler = debug_excp_handler;
204
205 debug_excp_handler = handler;
206 return old_handler;
207}
208
209static void cpu_handle_debug_exception(CPUState *env)
210{
211 CPUWatchpoint *wp;
212
David 'Digit' Turner42760382011-05-11 01:48:19 +0200213 if (!env->watchpoint_hit) {
214 QTAILQ_FOREACH(wp, &env->watchpoints, entry) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700215 wp->flags &= ~BP_WATCHPOINT_HIT;
David 'Digit' Turner42760382011-05-11 01:48:19 +0200216 }
217 }
218 if (debug_excp_handler) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700219 debug_excp_handler(env);
David 'Digit' Turner42760382011-05-11 01:48:19 +0200220 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700221}
222
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800223/* main execution loop */
224
David Turner24cd25a2010-09-10 14:22:27 +0200225volatile sig_atomic_t exit_request;
226
Jun Nakajimaa381ef02011-12-17 19:13:25 -0800227/*
228 * Qemu emulation can happen because of MMIO or emulation mode,
229 * i.e. non-PG mode. For MMIO cases, the pending interrupt should not
230 * be emulated in qemu because MMIO is emulated for only one
231 * instruction now and then back to the HAX kernel module.
232 */
233int need_handle_intr_request(CPUState *env)
234{
235#ifdef CONFIG_HAX
236 if (!hax_enabled() || hax_vcpu_emulation_mode(env))
237 return env->interrupt_request;
238 return 0;
239#else
240 return env->interrupt_request;
241#endif
242}
243
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800244int cpu_exec(CPUState *env1)
245{
David Turner24cd25a2010-09-10 14:22:27 +0200246 volatile host_reg_t saved_env_reg;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800247 int ret, interrupt_request;
248 TranslationBlock *tb;
249 uint8_t *tc_ptr;
250 unsigned long next_tb;
251
David 'Digit' Turner52858642011-06-03 13:41:05 +0200252 if (env1->halted) {
253 if (!cpu_has_work(env1)) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800254 return EXCP_HALTED;
David 'Digit' Turner52858642011-06-03 13:41:05 +0200255 }
256
257 env1->halted = 0;
258 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800259
260 cpu_single_env = env1;
261
David Turner24cd25a2010-09-10 14:22:27 +0200262 /* the access to env below is actually saving the global register's
263 value, so that files not including target-xyz/exec.h are free to
264 use it. */
265 QEMU_BUILD_BUG_ON (sizeof (saved_env_reg) != sizeof (env));
266 saved_env_reg = (host_reg_t) env;
267 barrier();
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800268 env = env1;
269
David Turner24cd25a2010-09-10 14:22:27 +0200270 if (unlikely(exit_request)) {
271 env->exit_request = 1;
272 }
273
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800274#if defined(TARGET_I386)
David Turner24cd25a2010-09-10 14:22:27 +0200275 if (!kvm_enabled()) {
276 /* put eflags in CPU temporary format */
277 CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
278 DF = 1 - (2 * ((env->eflags >> 10) & 1));
279 CC_OP = CC_OP_EFLAGS;
280 env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
281 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800282#elif defined(TARGET_SPARC)
283#elif defined(TARGET_M68K)
284 env->cc_op = CC_OP_FLAGS;
285 env->cc_dest = env->sr & 0xf;
286 env->cc_x = (env->sr >> 4) & 1;
287#elif defined(TARGET_ALPHA)
288#elif defined(TARGET_ARM)
David 'Digit' Turner42760382011-05-11 01:48:19 +0200289#elif defined(TARGET_UNICORE32)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800290#elif defined(TARGET_PPC)
David 'Digit' Turner42760382011-05-11 01:48:19 +0200291#elif defined(TARGET_LM32)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700292#elif defined(TARGET_MICROBLAZE)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800293#elif defined(TARGET_MIPS)
294#elif defined(TARGET_SH4)
295#elif defined(TARGET_CRIS)
David 'Digit' Turnera5d41202010-05-10 18:37:10 -0700296#elif defined(TARGET_S390X)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800297 /* XXXXX */
298#else
299#error unsupported target CPU
300#endif
301 env->exception_index = -1;
302
303 /* prepare setjmp context for exception handling */
304 for(;;) {
305 if (setjmp(env->jmp_env) == 0) {
David 'Digit' Turner2c538c82010-05-10 16:48:20 -0700306#if defined(__sparc__) && !defined(CONFIG_SOLARIS)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700307#undef env
308 env = cpu_single_env;
309#define env cpu_single_env
310#endif
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800311 /* if an exception is pending, we execute it here */
312 if (env->exception_index >= 0) {
313 if (env->exception_index >= EXCP_INTERRUPT) {
314 /* exit request from the cpu execution loop */
315 ret = env->exception_index;
David 'Digit' Turner42760382011-05-11 01:48:19 +0200316 if (ret == EXCP_DEBUG) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700317 cpu_handle_debug_exception(env);
David 'Digit' Turner42760382011-05-11 01:48:19 +0200318 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800319 break;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700320 } else {
321#if defined(CONFIG_USER_ONLY)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800322 /* if user mode only, we simulate a fake exception
323 which will be handled outside the cpu execution
324 loop */
325#if defined(TARGET_I386)
326 do_interrupt_user(env->exception_index,
327 env->exception_is_int,
328 env->error_code,
329 env->exception_next_eip);
330 /* successfully delivered */
331 env->old_exception = -1;
332#endif
333 ret = env->exception_index;
334 break;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700335#else
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800336#if defined(TARGET_I386)
337 /* simulate a real cpu exception. On i386, it can
338 trigger new exceptions, but we do not handle
339 double or triple faults yet. */
340 do_interrupt(env->exception_index,
341 env->exception_is_int,
342 env->error_code,
343 env->exception_next_eip, 0);
344 /* successfully delivered */
345 env->old_exception = -1;
346#elif defined(TARGET_PPC)
347 do_interrupt(env);
David 'Digit' Turner42760382011-05-11 01:48:19 +0200348#elif defined(TARGET_LM32)
349 do_interrupt(env);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700350#elif defined(TARGET_MICROBLAZE)
351 do_interrupt(env);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800352#elif defined(TARGET_MIPS)
353 do_interrupt(env);
354#elif defined(TARGET_SPARC)
355 do_interrupt(env);
356#elif defined(TARGET_ARM)
357 do_interrupt(env);
David 'Digit' Turner42760382011-05-11 01:48:19 +0200358#elif defined(TARGET_UNICORE32)
359 do_interrupt(env);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800360#elif defined(TARGET_SH4)
361 do_interrupt(env);
362#elif defined(TARGET_ALPHA)
363 do_interrupt(env);
364#elif defined(TARGET_CRIS)
365 do_interrupt(env);
366#elif defined(TARGET_M68K)
367 do_interrupt(0);
David 'Digit' Turner42760382011-05-11 01:48:19 +0200368#elif defined(TARGET_S390X)
369 do_interrupt(env);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800370#endif
David 'Digit' Turnera5d41202010-05-10 18:37:10 -0700371 env->exception_index = -1;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700372#endif
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800373 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800374 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800375
Jun Nakajimaa381ef02011-12-17 19:13:25 -0800376#ifdef CONFIG_HAX
377 if (hax_enabled() && !hax_vcpu_exec(env))
378 longjmp(env->jmp_env, 1);
379#endif
380
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700381 if (kvm_enabled()) {
382 kvm_cpu_exec(env);
383 longjmp(env->jmp_env, 1);
384 }
385
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800386 next_tb = 0; /* force lookup of first TB */
387 for(;;) {
388 interrupt_request = env->interrupt_request;
Jun Nakajimaa381ef02011-12-17 19:13:25 -0800389 if (unlikely(need_handle_intr_request(env))) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700390 if (unlikely(env->singlestep_enabled & SSTEP_NOIRQ)) {
391 /* Mask out external interrupts for this step. */
David 'Digit' Turner52858642011-06-03 13:41:05 +0200392 interrupt_request &= ~CPU_INTERRUPT_SSTEP_MASK;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700393 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800394 if (interrupt_request & CPU_INTERRUPT_DEBUG) {
395 env->interrupt_request &= ~CPU_INTERRUPT_DEBUG;
396 env->exception_index = EXCP_DEBUG;
397 cpu_loop_exit();
398 }
399#if defined(TARGET_ARM) || defined(TARGET_SPARC) || defined(TARGET_MIPS) || \
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700400 defined(TARGET_PPC) || defined(TARGET_ALPHA) || defined(TARGET_CRIS) || \
David 'Digit' Turner42760382011-05-11 01:48:19 +0200401 defined(TARGET_MICROBLAZE) || defined(TARGET_LM32) || defined(TARGET_UNICORE32)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800402 if (interrupt_request & CPU_INTERRUPT_HALT) {
403 env->interrupt_request &= ~CPU_INTERRUPT_HALT;
404 env->halted = 1;
405 env->exception_index = EXCP_HLT;
406 cpu_loop_exit();
407 }
408#endif
409#if defined(TARGET_I386)
David 'Digit' Turnera5d41202010-05-10 18:37:10 -0700410 if (interrupt_request & CPU_INTERRUPT_INIT) {
411 svm_check_intercept(SVM_EXIT_INIT);
412 do_cpu_init(env);
413 env->exception_index = EXCP_HALTED;
414 cpu_loop_exit();
415 } else if (interrupt_request & CPU_INTERRUPT_SIPI) {
416 do_cpu_sipi(env);
417 } else if (env->hflags2 & HF2_GIF_MASK) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800418 if ((interrupt_request & CPU_INTERRUPT_SMI) &&
419 !(env->hflags & HF_SMM_MASK)) {
420 svm_check_intercept(SVM_EXIT_SMI);
421 env->interrupt_request &= ~CPU_INTERRUPT_SMI;
422 do_smm_enter();
423 next_tb = 0;
424 } else if ((interrupt_request & CPU_INTERRUPT_NMI) &&
425 !(env->hflags2 & HF2_NMI_MASK)) {
426 env->interrupt_request &= ~CPU_INTERRUPT_NMI;
427 env->hflags2 |= HF2_NMI_MASK;
428 do_interrupt(EXCP02_NMI, 0, 0, 0, 1);
429 next_tb = 0;
David 'Digit' Turnera5d41202010-05-10 18:37:10 -0700430 } else if (interrupt_request & CPU_INTERRUPT_MCE) {
431 env->interrupt_request &= ~CPU_INTERRUPT_MCE;
432 do_interrupt(EXCP12_MCHK, 0, 0, 0, 0);
433 next_tb = 0;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800434 } else if ((interrupt_request & CPU_INTERRUPT_HARD) &&
David 'Digit' Turnerf645f7d2011-05-11 00:44:05 +0200435 (((env->hflags2 & HF2_VINTR_MASK) &&
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800436 (env->hflags2 & HF2_HIF_MASK)) ||
David 'Digit' Turnerf645f7d2011-05-11 00:44:05 +0200437 (!(env->hflags2 & HF2_VINTR_MASK) &&
438 (env->eflags & IF_MASK &&
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800439 !(env->hflags & HF_INHIBIT_IRQ_MASK))))) {
440 int intno;
441 svm_check_intercept(SVM_EXIT_INTR);
442 env->interrupt_request &= ~(CPU_INTERRUPT_HARD | CPU_INTERRUPT_VIRQ);
443 intno = cpu_get_pic_interrupt(env);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700444 qemu_log_mask(CPU_LOG_TB_IN_ASM, "Servicing hardware INT=0x%02x\n", intno);
David 'Digit' Turner2c538c82010-05-10 16:48:20 -0700445#if defined(__sparc__) && !defined(CONFIG_SOLARIS)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700446#undef env
447 env = cpu_single_env;
448#define env cpu_single_env
449#endif
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800450 do_interrupt(intno, 0, 0, 0, 1);
451 /* ensure that no TB jump will be modified as
452 the program flow was changed */
453 next_tb = 0;
454#if !defined(CONFIG_USER_ONLY)
455 } else if ((interrupt_request & CPU_INTERRUPT_VIRQ) &&
David 'Digit' Turnerf645f7d2011-05-11 00:44:05 +0200456 (env->eflags & IF_MASK) &&
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800457 !(env->hflags & HF_INHIBIT_IRQ_MASK)) {
458 int intno;
459 /* FIXME: this should respect TPR */
460 svm_check_intercept(SVM_EXIT_VINTR);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800461 intno = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_vector));
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700462 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 -0800463 do_interrupt(intno, 0, 0, 0, 1);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700464 env->interrupt_request &= ~CPU_INTERRUPT_VIRQ;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800465 next_tb = 0;
466#endif
467 }
468 }
469#elif defined(TARGET_PPC)
470#if 0
471 if ((interrupt_request & CPU_INTERRUPT_RESET)) {
David 'Digit' Turnera5d41202010-05-10 18:37:10 -0700472 cpu_reset(env);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800473 }
474#endif
475 if (interrupt_request & CPU_INTERRUPT_HARD) {
476 ppc_hw_interrupt(env);
477 if (env->pending_interrupts == 0)
478 env->interrupt_request &= ~CPU_INTERRUPT_HARD;
479 next_tb = 0;
480 }
David 'Digit' Turner42760382011-05-11 01:48:19 +0200481#elif defined(TARGET_LM32)
482 if ((interrupt_request & CPU_INTERRUPT_HARD)
483 && (env->ie & IE_IE)) {
484 env->exception_index = EXCP_IRQ;
485 do_interrupt(env);
486 next_tb = 0;
487 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700488#elif defined(TARGET_MICROBLAZE)
489 if ((interrupt_request & CPU_INTERRUPT_HARD)
490 && (env->sregs[SR_MSR] & MSR_IE)
491 && !(env->sregs[SR_MSR] & (MSR_EIP | MSR_BIP))
492 && !(env->iflags & (D_FLAG | IMM_FLAG))) {
493 env->exception_index = EXCP_IRQ;
494 do_interrupt(env);
495 next_tb = 0;
496 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800497#elif defined(TARGET_MIPS)
498 if ((interrupt_request & CPU_INTERRUPT_HARD) &&
David 'Digit' Turner42760382011-05-11 01:48:19 +0200499 cpu_mips_hw_interrupts_pending(env)) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800500 /* Raise it */
501 env->exception_index = EXCP_EXT_INTERRUPT;
502 env->error_code = 0;
503 do_interrupt(env);
504 next_tb = 0;
505 }
506#elif defined(TARGET_SPARC)
David Turner24cd25a2010-09-10 14:22:27 +0200507 if (interrupt_request & CPU_INTERRUPT_HARD) {
508 if (cpu_interrupts_enabled(env) &&
509 env->interrupt_index > 0) {
510 int pil = env->interrupt_index & 0xf;
511 int type = env->interrupt_index & 0xf0;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800512
David Turner24cd25a2010-09-10 14:22:27 +0200513 if (((type == TT_EXTINT) &&
514 cpu_pil_allowed(env, pil)) ||
515 type != TT_EXTINT) {
516 env->exception_index = env->interrupt_index;
517 do_interrupt(env);
518 next_tb = 0;
519 }
520 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800521 }
522#elif defined(TARGET_ARM)
523 if (interrupt_request & CPU_INTERRUPT_FIQ
524 && !(env->uncached_cpsr & CPSR_F)) {
525 env->exception_index = EXCP_FIQ;
526 do_interrupt(env);
527 next_tb = 0;
528 }
529 /* ARMv7-M interrupt return works by loading a magic value
530 into the PC. On real hardware the load causes the
531 return to occur. The qemu implementation performs the
532 jump normally, then does the exception return when the
533 CPU tries to execute code at the magic address.
534 This will cause the magic PC value to be pushed to
David 'Digit' Turner52858642011-06-03 13:41:05 +0200535 the stack if an interrupt occurred at the wrong time.
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800536 We avoid this by disabling interrupts when
537 pc contains a magic address. */
538 if (interrupt_request & CPU_INTERRUPT_HARD
539 && ((IS_M(env) && env->regs[15] < 0xfffffff0)
540 || !(env->uncached_cpsr & CPSR_I))) {
541 env->exception_index = EXCP_IRQ;
542 do_interrupt(env);
543 next_tb = 0;
544 }
David 'Digit' Turner42760382011-05-11 01:48:19 +0200545#elif defined(TARGET_UNICORE32)
546 if (interrupt_request & CPU_INTERRUPT_HARD
547 && !(env->uncached_asr & ASR_I)) {
548 do_interrupt(env);
549 next_tb = 0;
550 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800551#elif defined(TARGET_SH4)
552 if (interrupt_request & CPU_INTERRUPT_HARD) {
553 do_interrupt(env);
554 next_tb = 0;
555 }
556#elif defined(TARGET_ALPHA)
557 if (interrupt_request & CPU_INTERRUPT_HARD) {
558 do_interrupt(env);
559 next_tb = 0;
560 }
561#elif defined(TARGET_CRIS)
562 if (interrupt_request & CPU_INTERRUPT_HARD
David Turner24cd25a2010-09-10 14:22:27 +0200563 && (env->pregs[PR_CCS] & I_FLAG)
564 && !env->locked_irq) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800565 env->exception_index = EXCP_IRQ;
566 do_interrupt(env);
567 next_tb = 0;
568 }
569 if (interrupt_request & CPU_INTERRUPT_NMI
570 && (env->pregs[PR_CCS] & M_FLAG)) {
571 env->exception_index = EXCP_NMI;
572 do_interrupt(env);
573 next_tb = 0;
574 }
575#elif defined(TARGET_M68K)
576 if (interrupt_request & CPU_INTERRUPT_HARD
577 && ((env->sr & SR_I) >> SR_I_SHIFT)
578 < env->pending_level) {
579 /* Real hardware gets the interrupt vector via an
580 IACK cycle at this point. Current emulated
581 hardware doesn't rely on this, so we
582 provide/save the vector when the interrupt is
583 first signalled. */
584 env->exception_index = env->pending_vector;
585 do_interrupt(1);
586 next_tb = 0;
587 }
David 'Digit' Turner42760382011-05-11 01:48:19 +0200588#elif defined(TARGET_S390X) && !defined(CONFIG_USER_ONLY)
589 if ((interrupt_request & CPU_INTERRUPT_HARD) &&
590 (env->psw.mask & PSW_MASK_EXT)) {
591 do_interrupt(env);
592 next_tb = 0;
593 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800594#endif
David 'Digit' Turner52858642011-06-03 13:41:05 +0200595 /* Don't use the cached interrupt_request value,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800596 do_interrupt may have updated the EXITTB flag. */
597 if (env->interrupt_request & CPU_INTERRUPT_EXITTB) {
598 env->interrupt_request &= ~CPU_INTERRUPT_EXITTB;
599 /* ensure that no TB jump will be modified as
600 the program flow was changed */
601 next_tb = 0;
602 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700603 }
604 if (unlikely(env->exit_request)) {
605 env->exit_request = 0;
606 env->exception_index = EXCP_INTERRUPT;
607 cpu_loop_exit();
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800608 }
David Turner24cd25a2010-09-10 14:22:27 +0200609#if defined(DEBUG_DISAS) || defined(CONFIG_DEBUG_EXEC)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700610 if (qemu_loglevel_mask(CPU_LOG_TB_CPU)) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800611 /* restore flags in standard format */
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800612#if defined(TARGET_I386)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700613 env->eflags = env->eflags | helper_cc_compute_all(CC_OP) | (DF & DF_MASK);
614 log_cpu_state(env, X86_DUMP_CCOP);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800615 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 -0800616#elif defined(TARGET_M68K)
617 cpu_m68k_flush_flags(env, env->cc_op);
618 env->cc_op = CC_OP_FLAGS;
619 env->sr = (env->sr & 0xffe0)
620 | env->cc_dest | (env->cc_x << 4);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700621 log_cpu_state(env, 0);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800622#else
David Turner24cd25a2010-09-10 14:22:27 +0200623 log_cpu_state(env, 0);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800624#endif
625 }
David Turner24cd25a2010-09-10 14:22:27 +0200626#endif /* DEBUG_DISAS || CONFIG_DEBUG_EXEC */
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800627 spin_lock(&tb_lock);
628 tb = tb_find_fast();
629 /* Note: we do it here to avoid a gcc bug on Mac OS X when
630 doing it in tb_find_slow */
631 if (tb_invalidated_flag) {
632 /* as some TB could have been invalidated because
633 of memory exceptions while generating the code, we
634 must recompute the hash index here */
635 next_tb = 0;
636 tb_invalidated_flag = 0;
637 }
David Turner24cd25a2010-09-10 14:22:27 +0200638#ifdef CONFIG_DEBUG_EXEC
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700639 qemu_log_mask(CPU_LOG_EXEC, "Trace 0x%08lx [" TARGET_FMT_lx "] %s\n",
640 (long)tb->tc_ptr, tb->pc,
641 lookup_symbol(tb->pc));
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800642#endif
643 /* see if we can patch the calling TB. When the TB
644 spans two pages, we cannot safely do a direct
645 jump. */
David Turner24cd25a2010-09-10 14:22:27 +0200646 if (next_tb != 0 && tb->page_addr[1] == -1) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800647 tb_add_jump((TranslationBlock *)(next_tb & ~3), next_tb & 3, tb);
648 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800649 spin_unlock(&tb_lock);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700650
651 /* cpu_interrupt might be called while translating the
652 TB, but before it is linked into a potentially
653 infinite loop and becomes env->current_tb. Avoid
654 starting execution if there is a pending interrupt. */
David Turner24cd25a2010-09-10 14:22:27 +0200655 env->current_tb = tb;
656 barrier();
657 if (likely(!env->exit_request)) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800658 tc_ptr = tb->tc_ptr;
659 /* execute the generated code */
David 'Digit' Turner2c538c82010-05-10 16:48:20 -0700660#if defined(__sparc__) && !defined(CONFIG_SOLARIS)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800661#undef env
662 env = cpu_single_env;
663#define env cpu_single_env
664#endif
665 next_tb = tcg_qemu_tb_exec(tc_ptr);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800666 if ((next_tb & 3) == 2) {
667 /* Instruction counter expired. */
668 int insns_left;
669 tb = (TranslationBlock *)(long)(next_tb & ~3);
670 /* Restore PC. */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700671 cpu_pc_from_tb(env, tb);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800672 insns_left = env->icount_decr.u32;
673 if (env->icount_extra && insns_left >= 0) {
674 /* Refill decrementer and continue execution. */
675 env->icount_extra += insns_left;
676 if (env->icount_extra > 0xffff) {
677 insns_left = 0xffff;
678 } else {
679 insns_left = env->icount_extra;
680 }
681 env->icount_extra -= insns_left;
682 env->icount_decr.u16.low = insns_left;
683 } else {
684 if (insns_left > 0) {
685 /* Execute remaining instructions. */
686 cpu_exec_nocache(insns_left, tb);
687 }
688 env->exception_index = EXCP_INTERRUPT;
689 next_tb = 0;
690 cpu_loop_exit();
691 }
692 }
693 }
David Turner24cd25a2010-09-10 14:22:27 +0200694 env->current_tb = NULL;
Jun Nakajimaa381ef02011-12-17 19:13:25 -0800695#ifdef CONFIG_HAX
696 if (hax_enabled() && hax_stop_emulation(env))
697 cpu_loop_exit();
698#endif
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800699 /* reset soft MMU for next block (it can currently
700 only be set by a memory fault) */
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800701 } /* for(;;) */
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800702 }
703 } /* for(;;) */
704
705
706#if defined(TARGET_I386)
707 /* restore flags in standard format */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700708 env->eflags = env->eflags | helper_cc_compute_all(CC_OP) | (DF & DF_MASK);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800709#elif defined(TARGET_ARM)
710 /* XXX: Save/restore host fpu exception state?. */
David 'Digit' Turner42760382011-05-11 01:48:19 +0200711#elif defined(TARGET_UNICORE32)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800712#elif defined(TARGET_SPARC)
713#elif defined(TARGET_PPC)
David 'Digit' Turner42760382011-05-11 01:48:19 +0200714#elif defined(TARGET_LM32)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800715#elif defined(TARGET_M68K)
716 cpu_m68k_flush_flags(env, env->cc_op);
717 env->cc_op = CC_OP_FLAGS;
718 env->sr = (env->sr & 0xffe0)
719 | env->cc_dest | (env->cc_x << 4);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700720#elif defined(TARGET_MICROBLAZE)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800721#elif defined(TARGET_MIPS)
722#elif defined(TARGET_SH4)
723#elif defined(TARGET_ALPHA)
724#elif defined(TARGET_CRIS)
David Turner24cd25a2010-09-10 14:22:27 +0200725#elif defined(TARGET_S390X)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800726 /* XXXXX */
727#else
728#error unsupported target CPU
729#endif
730
731 /* restore global registers */
David Turner24cd25a2010-09-10 14:22:27 +0200732 barrier();
733 env = (void *) saved_env_reg;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800734
735 /* fail safe : never use cpu_single_env outside cpu_exec() */
736 cpu_single_env = NULL;
737 return ret;
738}
739
740/* must only be called from the generated code as an exception can be
741 generated */
742void tb_invalidate_page_range(target_ulong start, target_ulong end)
743{
744 /* XXX: cannot enable it yet because it yields to MMU exception
745 where NIP != read address on PowerPC */
746#if 0
747 target_ulong phys_addr;
748 phys_addr = get_phys_addr_code(env, start);
749 tb_invalidate_phys_page_range(phys_addr, phys_addr + end - start, 0);
750#endif
751}
752
753#if defined(TARGET_I386) && defined(CONFIG_USER_ONLY)
754
755void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector)
756{
757 CPUX86State *saved_env;
758
759 saved_env = env;
760 env = s;
761 if (!(env->cr[0] & CR0_PE_MASK) || (env->eflags & VM_MASK)) {
762 selector &= 0xffff;
763 cpu_x86_load_seg_cache(env, seg_reg, selector,
764 (selector << 4), 0xffff, 0);
765 } else {
766 helper_load_seg(seg_reg, selector);
767 }
768 env = saved_env;
769}
770
771void cpu_x86_fsave(CPUX86State *s, target_ulong ptr, int data32)
772{
773 CPUX86State *saved_env;
774
775 saved_env = env;
776 env = s;
777
778 helper_fsave(ptr, data32);
779
780 env = saved_env;
781}
782
783void cpu_x86_frstor(CPUX86State *s, target_ulong ptr, int data32)
784{
785 CPUX86State *saved_env;
786
787 saved_env = env;
788 env = s;
789
790 helper_frstor(ptr, data32);
791
792 env = saved_env;
793}
794
795#endif /* TARGET_I386 */
796
797#if !defined(CONFIG_SOFTMMU)
798
799#if defined(TARGET_I386)
David Turner24cd25a2010-09-10 14:22:27 +0200800#define EXCEPTION_ACTION raise_exception_err(env->exception_index, env->error_code)
801#else
802#define EXCEPTION_ACTION cpu_loop_exit()
803#endif
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800804
805/* 'pc' is the host PC at which the exception was raised. 'address' is
806 the effective address of the memory exception. 'is_write' is 1 if a
807 write caused the exception and otherwise 0'. 'old_set' is the
808 signal set which should be restored */
809static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
810 int is_write, sigset_t *old_set,
811 void *puc)
812{
813 TranslationBlock *tb;
814 int ret;
815
816 if (cpu_single_env)
817 env = cpu_single_env; /* XXX: find a correct solution for multithread */
818#if defined(DEBUG_SIGNAL)
819 qemu_printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
820 pc, address, is_write, *(unsigned long *)old_set);
821#endif
822 /* XXX: locking issue */
823 if (is_write && page_unprotect(h2g(address), pc, puc)) {
824 return 1;
825 }
826
827 /* see if it is an MMU fault */
David Turner24cd25a2010-09-10 14:22:27 +0200828 ret = cpu_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800829 if (ret < 0)
830 return 0; /* not an MMU fault */
831 if (ret == 0)
832 return 1; /* the MMU fault was handled without causing real CPU fault */
833 /* now we have a real cpu fault */
834 tb = tb_find_pc(pc);
835 if (tb) {
836 /* the PC is inside the translated code. It means that we have
837 a virtual CPU fault */
David 'Digit' Turnerf645f7d2011-05-11 00:44:05 +0200838 cpu_restore_state(tb, env, pc);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800839 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800840
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800841 /* we restore the process signal mask as the sigreturn should
842 do it (XXX: use sigsetjmp) */
843 sigprocmask(SIG_SETMASK, old_set, NULL);
David Turner24cd25a2010-09-10 14:22:27 +0200844 EXCEPTION_ACTION;
845
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800846 /* never comes here */
847 return 1;
848}
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800849
850#if defined(__i386__)
851
852#if defined(__APPLE__)
853# include <sys/ucontext.h>
854
855# define EIP_sig(context) (*((unsigned long*)&(context)->uc_mcontext->ss.eip))
856# define TRAP_sig(context) ((context)->uc_mcontext->es.trapno)
857# define ERROR_sig(context) ((context)->uc_mcontext->es.err)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700858# define MASK_sig(context) ((context)->uc_sigmask)
David Turner24cd25a2010-09-10 14:22:27 +0200859#elif defined (__NetBSD__)
860# include <ucontext.h>
861
862# define EIP_sig(context) ((context)->uc_mcontext.__gregs[_REG_EIP])
863# define TRAP_sig(context) ((context)->uc_mcontext.__gregs[_REG_TRAPNO])
864# define ERROR_sig(context) ((context)->uc_mcontext.__gregs[_REG_ERR])
865# define MASK_sig(context) ((context)->uc_sigmask)
866#elif defined (__FreeBSD__) || defined(__DragonFly__)
867# include <ucontext.h>
868
869# define EIP_sig(context) (*((unsigned long*)&(context)->uc_mcontext.mc_eip))
870# define TRAP_sig(context) ((context)->uc_mcontext.mc_trapno)
871# define ERROR_sig(context) ((context)->uc_mcontext.mc_err)
872# define MASK_sig(context) ((context)->uc_sigmask)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700873#elif defined(__OpenBSD__)
874# define EIP_sig(context) ((context)->sc_eip)
875# define TRAP_sig(context) ((context)->sc_trapno)
876# define ERROR_sig(context) ((context)->sc_err)
877# define MASK_sig(context) ((context)->sc_mask)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800878#else
879# define EIP_sig(context) ((context)->uc_mcontext.gregs[REG_EIP])
880# define TRAP_sig(context) ((context)->uc_mcontext.gregs[REG_TRAPNO])
881# define ERROR_sig(context) ((context)->uc_mcontext.gregs[REG_ERR])
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700882# define MASK_sig(context) ((context)->uc_sigmask)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800883#endif
884
885int cpu_signal_handler(int host_signum, void *pinfo,
886 void *puc)
887{
888 siginfo_t *info = pinfo;
David Turner24cd25a2010-09-10 14:22:27 +0200889#if defined(__NetBSD__) || defined (__FreeBSD__) || defined(__DragonFly__)
890 ucontext_t *uc = puc;
891#elif defined(__OpenBSD__)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700892 struct sigcontext *uc = puc;
893#else
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800894 struct ucontext *uc = puc;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700895#endif
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800896 unsigned long pc;
897 int trapno;
898
899#ifndef REG_EIP
900/* for glibc 2.1 */
901#define REG_EIP EIP
902#define REG_ERR ERR
903#define REG_TRAPNO TRAPNO
904#endif
905 pc = EIP_sig(uc);
906 trapno = TRAP_sig(uc);
907 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
908 trapno == 0xe ?
909 (ERROR_sig(uc) >> 1) & 1 : 0,
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700910 &MASK_sig(uc), puc);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800911}
912
913#elif defined(__x86_64__)
914
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700915#ifdef __NetBSD__
916#define PC_sig(context) _UC_MACHINE_PC(context)
917#define TRAP_sig(context) ((context)->uc_mcontext.__gregs[_REG_TRAPNO])
918#define ERROR_sig(context) ((context)->uc_mcontext.__gregs[_REG_ERR])
919#define MASK_sig(context) ((context)->uc_sigmask)
920#elif defined(__OpenBSD__)
921#define PC_sig(context) ((context)->sc_rip)
922#define TRAP_sig(context) ((context)->sc_trapno)
923#define ERROR_sig(context) ((context)->sc_err)
924#define MASK_sig(context) ((context)->sc_mask)
David Turner24cd25a2010-09-10 14:22:27 +0200925#elif defined (__FreeBSD__) || defined(__DragonFly__)
926#include <ucontext.h>
927
928#define PC_sig(context) (*((unsigned long*)&(context)->uc_mcontext.mc_rip))
929#define TRAP_sig(context) ((context)->uc_mcontext.mc_trapno)
930#define ERROR_sig(context) ((context)->uc_mcontext.mc_err)
931#define MASK_sig(context) ((context)->uc_sigmask)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700932#else
933#define PC_sig(context) ((context)->uc_mcontext.gregs[REG_RIP])
934#define TRAP_sig(context) ((context)->uc_mcontext.gregs[REG_TRAPNO])
935#define ERROR_sig(context) ((context)->uc_mcontext.gregs[REG_ERR])
936#define MASK_sig(context) ((context)->uc_sigmask)
937#endif
938
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800939int cpu_signal_handler(int host_signum, void *pinfo,
940 void *puc)
941{
942 siginfo_t *info = pinfo;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800943 unsigned long pc;
David Turner24cd25a2010-09-10 14:22:27 +0200944#if defined(__NetBSD__) || defined (__FreeBSD__) || defined(__DragonFly__)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700945 ucontext_t *uc = puc;
946#elif defined(__OpenBSD__)
947 struct sigcontext *uc = puc;
948#else
949 struct ucontext *uc = puc;
950#endif
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800951
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700952 pc = PC_sig(uc);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800953 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700954 TRAP_sig(uc) == 0xe ?
955 (ERROR_sig(uc) >> 1) & 1 : 0,
956 &MASK_sig(uc), puc);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800957}
958
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700959#elif defined(_ARCH_PPC)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800960
961/***********************************************************************
962 * signal context platform-specific definitions
963 * From Wine
964 */
965#ifdef linux
966/* All Registers access - only for local access */
967# define REG_sig(reg_name, context) ((context)->uc_mcontext.regs->reg_name)
968/* Gpr Registers access */
969# define GPR_sig(reg_num, context) REG_sig(gpr[reg_num], context)
970# define IAR_sig(context) REG_sig(nip, context) /* Program counter */
971# define MSR_sig(context) REG_sig(msr, context) /* Machine State Register (Supervisor) */
972# define CTR_sig(context) REG_sig(ctr, context) /* Count register */
973# define XER_sig(context) REG_sig(xer, context) /* User's integer exception register */
974# define LR_sig(context) REG_sig(link, context) /* Link register */
975# define CR_sig(context) REG_sig(ccr, context) /* Condition register */
976/* Float Registers access */
977# define FLOAT_sig(reg_num, context) (((double*)((char*)((context)->uc_mcontext.regs+48*4)))[reg_num])
978# define FPSCR_sig(context) (*(int*)((char*)((context)->uc_mcontext.regs+(48+32*2)*4)))
979/* Exception Registers access */
980# define DAR_sig(context) REG_sig(dar, context)
981# define DSISR_sig(context) REG_sig(dsisr, context)
982# define TRAP_sig(context) REG_sig(trap, context)
983#endif /* linux */
984
David Turner24cd25a2010-09-10 14:22:27 +0200985#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
986#include <ucontext.h>
987# define IAR_sig(context) ((context)->uc_mcontext.mc_srr0)
988# define MSR_sig(context) ((context)->uc_mcontext.mc_srr1)
989# define CTR_sig(context) ((context)->uc_mcontext.mc_ctr)
990# define XER_sig(context) ((context)->uc_mcontext.mc_xer)
991# define LR_sig(context) ((context)->uc_mcontext.mc_lr)
992# define CR_sig(context) ((context)->uc_mcontext.mc_cr)
993/* Exception Registers access */
994# define DAR_sig(context) ((context)->uc_mcontext.mc_dar)
995# define DSISR_sig(context) ((context)->uc_mcontext.mc_dsisr)
996# define TRAP_sig(context) ((context)->uc_mcontext.mc_exc)
997#endif /* __FreeBSD__|| __FreeBSD_kernel__ */
998
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800999#ifdef __APPLE__
1000# include <sys/ucontext.h>
1001typedef struct ucontext SIGCONTEXT;
1002/* All Registers access - only for local access */
1003# define REG_sig(reg_name, context) ((context)->uc_mcontext->ss.reg_name)
1004# define FLOATREG_sig(reg_name, context) ((context)->uc_mcontext->fs.reg_name)
1005# define EXCEPREG_sig(reg_name, context) ((context)->uc_mcontext->es.reg_name)
1006# define VECREG_sig(reg_name, context) ((context)->uc_mcontext->vs.reg_name)
1007/* Gpr Registers access */
1008# define GPR_sig(reg_num, context) REG_sig(r##reg_num, context)
1009# define IAR_sig(context) REG_sig(srr0, context) /* Program counter */
1010# define MSR_sig(context) REG_sig(srr1, context) /* Machine State Register (Supervisor) */
1011# define CTR_sig(context) REG_sig(ctr, context)
1012# define XER_sig(context) REG_sig(xer, context) /* Link register */
1013# define LR_sig(context) REG_sig(lr, context) /* User's integer exception register */
1014# define CR_sig(context) REG_sig(cr, context) /* Condition register */
1015/* Float Registers access */
1016# define FLOAT_sig(reg_num, context) FLOATREG_sig(fpregs[reg_num], context)
1017# define FPSCR_sig(context) ((double)FLOATREG_sig(fpscr, context))
1018/* Exception Registers access */
1019# define DAR_sig(context) EXCEPREG_sig(dar, context) /* Fault registers for coredump */
1020# define DSISR_sig(context) EXCEPREG_sig(dsisr, context)
1021# define TRAP_sig(context) EXCEPREG_sig(exception, context) /* number of powerpc exception taken */
1022#endif /* __APPLE__ */
1023
1024int cpu_signal_handler(int host_signum, void *pinfo,
1025 void *puc)
1026{
1027 siginfo_t *info = pinfo;
David Turner24cd25a2010-09-10 14:22:27 +02001028#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
1029 ucontext_t *uc = puc;
1030#else
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001031 struct ucontext *uc = puc;
David Turner24cd25a2010-09-10 14:22:27 +02001032#endif
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001033 unsigned long pc;
1034 int is_write;
1035
1036 pc = IAR_sig(uc);
1037 is_write = 0;
1038#if 0
1039 /* ppc 4xx case */
1040 if (DSISR_sig(uc) & 0x00800000)
1041 is_write = 1;
1042#else
1043 if (TRAP_sig(uc) != 0x400 && (DSISR_sig(uc) & 0x02000000))
1044 is_write = 1;
1045#endif
1046 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1047 is_write, &uc->uc_sigmask, puc);
1048}
1049
1050#elif defined(__alpha__)
1051
1052int cpu_signal_handler(int host_signum, void *pinfo,
1053 void *puc)
1054{
1055 siginfo_t *info = pinfo;
1056 struct ucontext *uc = puc;
1057 uint32_t *pc = uc->uc_mcontext.sc_pc;
1058 uint32_t insn = *pc;
1059 int is_write = 0;
1060
1061 /* XXX: need kernel patch to get write flag faster */
1062 switch (insn >> 26) {
1063 case 0x0d: // stw
1064 case 0x0e: // stb
1065 case 0x0f: // stq_u
1066 case 0x24: // stf
1067 case 0x25: // stg
1068 case 0x26: // sts
1069 case 0x27: // stt
1070 case 0x2c: // stl
1071 case 0x2d: // stq
1072 case 0x2e: // stl_c
1073 case 0x2f: // stq_c
1074 is_write = 1;
1075 }
1076
1077 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1078 is_write, &uc->uc_sigmask, puc);
1079}
1080#elif defined(__sparc__)
1081
1082int cpu_signal_handler(int host_signum, void *pinfo,
1083 void *puc)
1084{
1085 siginfo_t *info = pinfo;
1086 int is_write;
1087 uint32_t insn;
David 'Digit' Turner2c538c82010-05-10 16:48:20 -07001088#if !defined(__arch64__) || defined(CONFIG_SOLARIS)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001089 uint32_t *regs = (uint32_t *)(info + 1);
1090 void *sigmask = (regs + 20);
1091 /* XXX: is there a standard glibc define ? */
1092 unsigned long pc = regs[1];
1093#else
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001094#ifdef __linux__
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001095 struct sigcontext *sc = puc;
1096 unsigned long pc = sc->sigc_regs.tpc;
1097 void *sigmask = (void *)sc->sigc_mask;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001098#elif defined(__OpenBSD__)
1099 struct sigcontext *uc = puc;
1100 unsigned long pc = uc->sc_pc;
1101 void *sigmask = (void *)(long)uc->sc_mask;
1102#endif
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001103#endif
1104
1105 /* XXX: need kernel patch to get write flag faster */
1106 is_write = 0;
1107 insn = *(uint32_t *)pc;
1108 if ((insn >> 30) == 3) {
1109 switch((insn >> 19) & 0x3f) {
1110 case 0x05: // stb
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001111 case 0x15: // stba
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001112 case 0x06: // sth
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001113 case 0x16: // stha
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001114 case 0x04: // st
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001115 case 0x14: // sta
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001116 case 0x07: // std
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001117 case 0x17: // stda
1118 case 0x0e: // stx
1119 case 0x1e: // stxa
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001120 case 0x24: // stf
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001121 case 0x34: // stfa
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001122 case 0x27: // stdf
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001123 case 0x37: // stdfa
1124 case 0x26: // stqf
1125 case 0x36: // stqfa
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001126 case 0x25: // stfsr
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001127 case 0x3c: // casa
1128 case 0x3e: // casxa
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001129 is_write = 1;
1130 break;
1131 }
1132 }
1133 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1134 is_write, sigmask, NULL);
1135}
1136
1137#elif defined(__arm__)
1138
1139int cpu_signal_handler(int host_signum, void *pinfo,
1140 void *puc)
1141{
1142 siginfo_t *info = pinfo;
1143 struct ucontext *uc = puc;
1144 unsigned long pc;
1145 int is_write;
1146
1147#if (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ <= 3))
1148 pc = uc->uc_mcontext.gregs[R15];
1149#else
1150 pc = uc->uc_mcontext.arm_pc;
1151#endif
1152 /* XXX: compute is_write */
1153 is_write = 0;
1154 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1155 is_write,
1156 &uc->uc_sigmask, puc);
1157}
1158
1159#elif defined(__mc68000)
1160
1161int cpu_signal_handler(int host_signum, void *pinfo,
1162 void *puc)
1163{
1164 siginfo_t *info = pinfo;
1165 struct ucontext *uc = puc;
1166 unsigned long pc;
1167 int is_write;
1168
1169 pc = uc->uc_mcontext.gregs[16];
1170 /* XXX: compute is_write */
1171 is_write = 0;
1172 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1173 is_write,
1174 &uc->uc_sigmask, puc);
1175}
1176
1177#elif defined(__ia64)
1178
1179#ifndef __ISR_VALID
1180 /* This ought to be in <bits/siginfo.h>... */
1181# define __ISR_VALID 1
1182#endif
1183
1184int cpu_signal_handler(int host_signum, void *pinfo, void *puc)
1185{
1186 siginfo_t *info = pinfo;
1187 struct ucontext *uc = puc;
1188 unsigned long ip;
1189 int is_write = 0;
1190
1191 ip = uc->uc_mcontext.sc_ip;
1192 switch (host_signum) {
1193 case SIGILL:
1194 case SIGFPE:
1195 case SIGSEGV:
1196 case SIGBUS:
1197 case SIGTRAP:
1198 if (info->si_code && (info->si_segvflags & __ISR_VALID))
1199 /* ISR.W (write-access) is bit 33: */
1200 is_write = (info->si_isr >> 33) & 1;
1201 break;
1202
1203 default:
1204 break;
1205 }
1206 return handle_cpu_signal(ip, (unsigned long)info->si_addr,
1207 is_write,
David Turner24cd25a2010-09-10 14:22:27 +02001208 (sigset_t *)&uc->uc_sigmask, puc);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001209}
1210
1211#elif defined(__s390__)
1212
1213int cpu_signal_handler(int host_signum, void *pinfo,
1214 void *puc)
1215{
1216 siginfo_t *info = pinfo;
1217 struct ucontext *uc = puc;
1218 unsigned long pc;
David Turner24cd25a2010-09-10 14:22:27 +02001219 uint16_t *pinsn;
1220 int is_write = 0;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001221
1222 pc = uc->uc_mcontext.psw.addr;
David Turner24cd25a2010-09-10 14:22:27 +02001223
1224 /* ??? On linux, the non-rt signal handler has 4 (!) arguments instead
1225 of the normal 2 arguments. The 3rd argument contains the "int_code"
1226 from the hardware which does in fact contain the is_write value.
1227 The rt signal handler, as far as I can tell, does not give this value
1228 at all. Not that we could get to it from here even if it were. */
1229 /* ??? This is not even close to complete, since it ignores all
1230 of the read-modify-write instructions. */
1231 pinsn = (uint16_t *)pc;
1232 switch (pinsn[0] >> 8) {
1233 case 0x50: /* ST */
1234 case 0x42: /* STC */
1235 case 0x40: /* STH */
1236 is_write = 1;
1237 break;
1238 case 0xc4: /* RIL format insns */
1239 switch (pinsn[0] & 0xf) {
1240 case 0xf: /* STRL */
1241 case 0xb: /* STGRL */
1242 case 0x7: /* STHRL */
1243 is_write = 1;
1244 }
1245 break;
1246 case 0xe3: /* RXY format insns */
1247 switch (pinsn[2] & 0xff) {
1248 case 0x50: /* STY */
1249 case 0x24: /* STG */
1250 case 0x72: /* STCY */
1251 case 0x70: /* STHY */
1252 case 0x8e: /* STPQ */
1253 case 0x3f: /* STRVH */
1254 case 0x3e: /* STRV */
1255 case 0x2f: /* STRVG */
1256 is_write = 1;
1257 }
1258 break;
1259 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001260 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1261 is_write, &uc->uc_sigmask, puc);
1262}
1263
1264#elif defined(__mips__)
1265
1266int cpu_signal_handler(int host_signum, void *pinfo,
1267 void *puc)
1268{
1269 siginfo_t *info = pinfo;
1270 struct ucontext *uc = puc;
1271 greg_t pc = uc->uc_mcontext.pc;
1272 int is_write;
1273
1274 /* XXX: compute is_write */
1275 is_write = 0;
1276 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1277 is_write, &uc->uc_sigmask, puc);
1278}
1279
1280#elif defined(__hppa__)
1281
1282int cpu_signal_handler(int host_signum, void *pinfo,
1283 void *puc)
1284{
1285 struct siginfo *info = pinfo;
1286 struct ucontext *uc = puc;
David Turner24cd25a2010-09-10 14:22:27 +02001287 unsigned long pc = uc->uc_mcontext.sc_iaoq[0];
1288 uint32_t insn = *(uint32_t *)pc;
1289 int is_write = 0;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001290
David Turner24cd25a2010-09-10 14:22:27 +02001291 /* XXX: need kernel patch to get write flag faster. */
1292 switch (insn >> 26) {
1293 case 0x1a: /* STW */
1294 case 0x19: /* STH */
1295 case 0x18: /* STB */
1296 case 0x1b: /* STWM */
1297 is_write = 1;
1298 break;
1299
1300 case 0x09: /* CSTWX, FSTWX, FSTWS */
1301 case 0x0b: /* CSTDX, FSTDX, FSTDS */
1302 /* Distinguish from coprocessor load ... */
1303 is_write = (insn >> 9) & 1;
1304 break;
1305
1306 case 0x03:
1307 switch ((insn >> 6) & 15) {
1308 case 0xa: /* STWS */
1309 case 0x9: /* STHS */
1310 case 0x8: /* STBS */
1311 case 0xe: /* STWAS */
1312 case 0xc: /* STBYS */
1313 is_write = 1;
1314 }
1315 break;
1316 }
1317
David 'Digit' Turnerf645f7d2011-05-11 00:44:05 +02001318 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
David Turner24cd25a2010-09-10 14:22:27 +02001319 is_write, &uc->uc_sigmask, puc);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001320}
1321
1322#else
1323
1324#error host CPU specific signal handler needed
1325
1326#endif
1327
1328#endif /* !defined(CONFIG_SOFTMMU) */