blob: 7b513374a703cc6c32f38fed19b662d3316c95a7 [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"
David 'Digit' Turnera889d352014-03-20 12:35:32 +010020#include "cpu.h"
21#include "dyngen-exec.h"
David 'Digit' Turnercc33b2d2013-12-15 00:09:42 +010022#include "disas/disas.h"
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080023#include "tcg.h"
David 'Digit' Turner34c48ff2013-12-15 00:25:03 +010024#include "sysemu/kvm.h"
David 'Digit' Turnere1e03df2013-12-15 00:42:21 +010025#include "exec/hax.h"
26#include "qemu/atomic.h"
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080027
28#if !defined(CONFIG_SOFTMMU)
29#undef EAX
30#undef ECX
31#undef EDX
32#undef EBX
33#undef ESP
34#undef EBP
35#undef ESI
36#undef EDI
37#undef EIP
38#include <signal.h>
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -070039#ifdef __linux__
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080040#include <sys/ucontext.h>
41#endif
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -070042#endif
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080043
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080044int tb_invalidated_flag;
45
David 'Digit' Turnera5d41202010-05-10 18:37:10 -070046//#define CONFIG_DEBUG_EXEC
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080047//#define DEBUG_SIGNAL
48
David 'Digit' Turner7f7d9a92014-03-18 14:48:18 +010049bool qemu_cpu_has_work(CPUOldState *env)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -070050{
51 return cpu_has_work(env);
52}
53
David 'Digit' Turnera6810012014-03-18 09:24:22 +010054void cpu_loop_exit(CPUArchState* env)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080055{
David 'Digit' Turnera6810012014-03-18 09:24:22 +010056 env->current_tb = NULL;
57 longjmp(env->jmp_env, 1);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080058}
59
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080060/* exit the current TB from a signal handler. The host registers are
61 restored in a state compatible with the CPU emulator
62 */
David 'Digit' Turnera6810012014-03-18 09:24:22 +010063void cpu_resume_from_signal(CPUArchState *env, void *puc)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080064{
65#if !defined(CONFIG_SOFTMMU)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -070066#ifdef __linux__
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080067 struct ucontext *uc = puc;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -070068#elif defined(__OpenBSD__)
69 struct sigcontext *uc = puc;
70#endif
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080071#endif
72
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080073 /* XXX: restore cpu registers saved in host registers */
74
75#if !defined(CONFIG_SOFTMMU)
76 if (puc) {
77 /* XXX: use siglongjmp ? */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -070078#ifdef __linux__
David Turner24cd25a2010-09-10 14:22:27 +020079#ifdef __ia64
80 sigprocmask(SIG_SETMASK, (sigset_t *)&uc->uc_sigmask, NULL);
81#else
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080082 sigprocmask(SIG_SETMASK, &uc->uc_sigmask, NULL);
David Turner24cd25a2010-09-10 14:22:27 +020083#endif
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -070084#elif defined(__OpenBSD__)
85 sigprocmask(SIG_SETMASK, &uc->sc_mask, NULL);
86#endif
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080087 }
88#endif
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -070089 env->exception_index = -1;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080090 longjmp(env->jmp_env, 1);
91}
92
93/* Execute the code without caching the generated code. An interpreter
94 could be used if available. */
David 'Digit' Turnera6810012014-03-18 09:24:22 +010095static void cpu_exec_nocache(CPUArchState *env, int max_cycles, TranslationBlock *orig_tb)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080096{
David 'Digit' Turner53a08ed2014-03-18 11:54:59 +010097 tcg_target_ulong next_tb;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080098 TranslationBlock *tb;
99
100 /* Should never happen.
101 We only end up here when an existing TB is too long. */
102 if (max_cycles > CF_COUNT_MASK)
103 max_cycles = CF_COUNT_MASK;
104
105 tb = tb_gen_code(env, orig_tb->pc, orig_tb->cs_base, orig_tb->flags,
106 max_cycles);
107 env->current_tb = tb;
108 /* execute the generated code */
David 'Digit' Turnera6810012014-03-18 09:24:22 +0100109 next_tb = tcg_qemu_tb_exec(env, tb->tc_ptr);
David Turner24cd25a2010-09-10 14:22:27 +0200110 env->current_tb = NULL;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800111
112 if ((next_tb & 3) == 2) {
113 /* Restore PC. This may happen if async event occurs before
114 the TB starts executing. */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700115 cpu_pc_from_tb(env, tb);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800116 }
117 tb_phys_invalidate(tb, -1);
118 tb_free(tb);
119}
120
David 'Digit' Turnera6810012014-03-18 09:24:22 +0100121static TranslationBlock *tb_find_slow(CPUArchState *env,
122 target_ulong pc,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800123 target_ulong cs_base,
124 uint64_t flags)
125{
126 TranslationBlock *tb, **ptb1;
127 unsigned int h;
128 target_ulong phys_pc, phys_page1, phys_page2, virt_page2;
129
130 tb_invalidated_flag = 0;
131
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800132 /* find translated block using physical mappings */
David 'Digit' Turner13487772014-02-17 21:16:46 +0100133 phys_pc = get_page_addr_code(env, pc);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800134 phys_page1 = phys_pc & TARGET_PAGE_MASK;
135 phys_page2 = -1;
136 h = tb_phys_hash_func(phys_pc);
David 'Digit' Turner13487772014-02-17 21:16:46 +0100137 ptb1 = &tcg_ctx.tb_ctx.tb_phys_hash[h];
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800138 for(;;) {
139 tb = *ptb1;
140 if (!tb)
141 goto not_found;
142 if (tb->pc == pc &&
143 tb->page_addr[0] == phys_page1 &&
144 tb->cs_base == cs_base &&
145 tb->flags == flags) {
146 /* check next page if needed */
147 if (tb->page_addr[1] != -1) {
148 virt_page2 = (pc & TARGET_PAGE_MASK) +
149 TARGET_PAGE_SIZE;
David 'Digit' Turner13487772014-02-17 21:16:46 +0100150 phys_page2 = get_page_addr_code(env, virt_page2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800151 if (tb->page_addr[1] == phys_page2)
152 goto found;
153 } else {
154 goto found;
155 }
156 }
157 ptb1 = &tb->phys_hash_next;
158 }
159 not_found:
160 /* if no translated code available, then translate it now */
161 tb = tb_gen_code(env, pc, cs_base, flags, 0);
162
163 found:
David 'Digit' Turner52858642011-06-03 13:41:05 +0200164 /* Move the last found TB to the head of the list */
165 if (likely(*ptb1)) {
166 *ptb1 = tb->phys_hash_next;
David 'Digit' Turner13487772014-02-17 21:16:46 +0100167 tb->phys_hash_next = tcg_ctx.tb_ctx.tb_phys_hash[h];
168 tcg_ctx.tb_ctx.tb_phys_hash[h] = tb;
David 'Digit' Turner52858642011-06-03 13:41:05 +0200169 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800170 /* we add the TB in the virtual pc hash table */
171 env->tb_jmp_cache[tb_jmp_cache_hash_func(pc)] = tb;
172 return tb;
173}
174
David 'Digit' Turnera6810012014-03-18 09:24:22 +0100175static inline TranslationBlock *tb_find_fast(CPUArchState *env)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800176{
177 TranslationBlock *tb;
178 target_ulong cs_base, pc;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700179 int flags;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800180
181 /* we record a subset of the CPU state. It will
182 always be the same before a given translated block
183 is executed. */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700184 cpu_get_tb_cpu_state(env, &pc, &cs_base, &flags);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800185 tb = env->tb_jmp_cache[tb_jmp_cache_hash_func(pc)];
186 if (unlikely(!tb || tb->pc != pc || tb->cs_base != cs_base ||
187 tb->flags != flags)) {
David 'Digit' Turnera6810012014-03-18 09:24:22 +0100188 tb = tb_find_slow(env, pc, cs_base, flags);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800189 }
190 return tb;
191}
192
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700193static CPUDebugExcpHandler *debug_excp_handler;
194
David 'Digit' Turner13487772014-02-17 21:16:46 +0100195void cpu_set_debug_excp_handler(CPUDebugExcpHandler *handler)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700196{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700197 debug_excp_handler = handler;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700198}
199
David 'Digit' Turnere2678e12014-01-16 15:56:43 +0100200static void cpu_handle_debug_exception(CPUOldState *env)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700201{
202 CPUWatchpoint *wp;
203
David 'Digit' Turner42760382011-05-11 01:48:19 +0200204 if (!env->watchpoint_hit) {
205 QTAILQ_FOREACH(wp, &env->watchpoints, entry) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700206 wp->flags &= ~BP_WATCHPOINT_HIT;
David 'Digit' Turner42760382011-05-11 01:48:19 +0200207 }
208 }
209 if (debug_excp_handler) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700210 debug_excp_handler(env);
David 'Digit' Turner42760382011-05-11 01:48:19 +0200211 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700212}
213
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800214/* main execution loop */
215
David Turner24cd25a2010-09-10 14:22:27 +0200216volatile sig_atomic_t exit_request;
217
Jun Nakajimaa381ef02011-12-17 19:13:25 -0800218/*
219 * Qemu emulation can happen because of MMIO or emulation mode,
220 * i.e. non-PG mode. For MMIO cases, the pending interrupt should not
221 * be emulated in qemu because MMIO is emulated for only one
222 * instruction now and then back to the HAX kernel module.
223 */
David 'Digit' Turnere2678e12014-01-16 15:56:43 +0100224int need_handle_intr_request(CPUOldState *env)
Jun Nakajimaa381ef02011-12-17 19:13:25 -0800225{
226#ifdef CONFIG_HAX
227 if (!hax_enabled() || hax_vcpu_emulation_mode(env))
228 return env->interrupt_request;
229 return 0;
230#else
231 return env->interrupt_request;
232#endif
233}
234
David 'Digit' Turnera6810012014-03-18 09:24:22 +0100235int cpu_exec(CPUOldState *env)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800236{
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800237 int ret, interrupt_request;
238 TranslationBlock *tb;
239 uint8_t *tc_ptr;
David 'Digit' Turner53a08ed2014-03-18 11:54:59 +0100240 tcg_target_ulong next_tb;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800241
David 'Digit' Turnera6810012014-03-18 09:24:22 +0100242 if (env->halted) {
243 if (!cpu_has_work(env)) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800244 return EXCP_HALTED;
David 'Digit' Turner52858642011-06-03 13:41:05 +0200245 }
246
David 'Digit' Turnera6810012014-03-18 09:24:22 +0100247 env->halted = 0;
David 'Digit' Turner52858642011-06-03 13:41:05 +0200248 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800249
David 'Digit' Turnera6810012014-03-18 09:24:22 +0100250 cpu_single_env = env;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800251
David Turner24cd25a2010-09-10 14:22:27 +0200252 if (unlikely(exit_request)) {
253 env->exit_request = 1;
254 }
255
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800256#if defined(TARGET_I386)
David Turner24cd25a2010-09-10 14:22:27 +0200257 if (!kvm_enabled()) {
258 /* put eflags in CPU temporary format */
259 CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
260 DF = 1 - (2 * ((env->eflags >> 10) & 1));
261 CC_OP = CC_OP_EFLAGS;
262 env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
263 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800264#elif defined(TARGET_SPARC)
265#elif defined(TARGET_M68K)
266 env->cc_op = CC_OP_FLAGS;
267 env->cc_dest = env->sr & 0xf;
268 env->cc_x = (env->sr >> 4) & 1;
269#elif defined(TARGET_ALPHA)
270#elif defined(TARGET_ARM)
David 'Digit' Turner42760382011-05-11 01:48:19 +0200271#elif defined(TARGET_UNICORE32)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800272#elif defined(TARGET_PPC)
David 'Digit' Turner42760382011-05-11 01:48:19 +0200273#elif defined(TARGET_LM32)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700274#elif defined(TARGET_MICROBLAZE)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800275#elif defined(TARGET_MIPS)
276#elif defined(TARGET_SH4)
277#elif defined(TARGET_CRIS)
David 'Digit' Turnera5d41202010-05-10 18:37:10 -0700278#elif defined(TARGET_S390X)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800279 /* XXXXX */
280#else
281#error unsupported target CPU
282#endif
283 env->exception_index = -1;
284
285 /* prepare setjmp context for exception handling */
286 for(;;) {
287 if (setjmp(env->jmp_env) == 0) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800288 /* if an exception is pending, we execute it here */
289 if (env->exception_index >= 0) {
290 if (env->exception_index >= EXCP_INTERRUPT) {
291 /* exit request from the cpu execution loop */
292 ret = env->exception_index;
David 'Digit' Turner42760382011-05-11 01:48:19 +0200293 if (ret == EXCP_DEBUG) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700294 cpu_handle_debug_exception(env);
David 'Digit' Turner42760382011-05-11 01:48:19 +0200295 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800296 break;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700297 } else {
298#if defined(CONFIG_USER_ONLY)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800299 /* if user mode only, we simulate a fake exception
300 which will be handled outside the cpu execution
301 loop */
302#if defined(TARGET_I386)
David 'Digit' Turnerbf2340f2014-03-18 14:41:25 +0100303 do_interrupt(env);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800304#endif
305 ret = env->exception_index;
306 break;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700307#else
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800308 do_interrupt(env);
David 'Digit' Turnera5d41202010-05-10 18:37:10 -0700309 env->exception_index = -1;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700310#endif
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800311 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800312 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800313
Jun Nakajimaa381ef02011-12-17 19:13:25 -0800314#ifdef CONFIG_HAX
315 if (hax_enabled() && !hax_vcpu_exec(env))
316 longjmp(env->jmp_env, 1);
317#endif
318
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700319 if (kvm_enabled()) {
320 kvm_cpu_exec(env);
321 longjmp(env->jmp_env, 1);
322 }
323
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800324 next_tb = 0; /* force lookup of first TB */
325 for(;;) {
326 interrupt_request = env->interrupt_request;
Jun Nakajimaa381ef02011-12-17 19:13:25 -0800327 if (unlikely(need_handle_intr_request(env))) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700328 if (unlikely(env->singlestep_enabled & SSTEP_NOIRQ)) {
329 /* Mask out external interrupts for this step. */
David 'Digit' Turner52858642011-06-03 13:41:05 +0200330 interrupt_request &= ~CPU_INTERRUPT_SSTEP_MASK;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700331 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800332 if (interrupt_request & CPU_INTERRUPT_DEBUG) {
333 env->interrupt_request &= ~CPU_INTERRUPT_DEBUG;
334 env->exception_index = EXCP_DEBUG;
David 'Digit' Turner85c62202014-02-16 20:53:40 +0100335 cpu_loop_exit(env);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800336 }
337#if defined(TARGET_ARM) || defined(TARGET_SPARC) || defined(TARGET_MIPS) || \
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700338 defined(TARGET_PPC) || defined(TARGET_ALPHA) || defined(TARGET_CRIS) || \
David 'Digit' Turner42760382011-05-11 01:48:19 +0200339 defined(TARGET_MICROBLAZE) || defined(TARGET_LM32) || defined(TARGET_UNICORE32)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800340 if (interrupt_request & CPU_INTERRUPT_HALT) {
341 env->interrupt_request &= ~CPU_INTERRUPT_HALT;
342 env->halted = 1;
343 env->exception_index = EXCP_HLT;
David 'Digit' Turner85c62202014-02-16 20:53:40 +0100344 cpu_loop_exit(env);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800345 }
346#endif
347#if defined(TARGET_I386)
David 'Digit' Turnera5d41202010-05-10 18:37:10 -0700348 if (interrupt_request & CPU_INTERRUPT_INIT) {
David 'Digit' Turnerbf2340f2014-03-18 14:41:25 +0100349 svm_check_intercept(env, SVM_EXIT_INIT);
David 'Digit' Turnera5d41202010-05-10 18:37:10 -0700350 do_cpu_init(env);
351 env->exception_index = EXCP_HALTED;
David 'Digit' Turner85c62202014-02-16 20:53:40 +0100352 cpu_loop_exit(env);
David 'Digit' Turnera5d41202010-05-10 18:37:10 -0700353 } else if (interrupt_request & CPU_INTERRUPT_SIPI) {
354 do_cpu_sipi(env);
355 } else if (env->hflags2 & HF2_GIF_MASK) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800356 if ((interrupt_request & CPU_INTERRUPT_SMI) &&
357 !(env->hflags & HF_SMM_MASK)) {
David 'Digit' Turnerbf2340f2014-03-18 14:41:25 +0100358 svm_check_intercept(env, SVM_EXIT_SMI);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800359 env->interrupt_request &= ~CPU_INTERRUPT_SMI;
David 'Digit' Turnerbf2340f2014-03-18 14:41:25 +0100360 do_smm_enter(env);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800361 next_tb = 0;
362 } else if ((interrupt_request & CPU_INTERRUPT_NMI) &&
363 !(env->hflags2 & HF2_NMI_MASK)) {
364 env->interrupt_request &= ~CPU_INTERRUPT_NMI;
365 env->hflags2 |= HF2_NMI_MASK;
David 'Digit' Turnerbf2340f2014-03-18 14:41:25 +0100366 do_interrupt_x86_hardirq(env, EXCP02_NMI, 1);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800367 next_tb = 0;
David 'Digit' Turnera5d41202010-05-10 18:37:10 -0700368 } else if (interrupt_request & CPU_INTERRUPT_MCE) {
369 env->interrupt_request &= ~CPU_INTERRUPT_MCE;
David 'Digit' Turnerbf2340f2014-03-18 14:41:25 +0100370 do_interrupt_x86_hardirq(env, EXCP12_MCHK, 0);
David 'Digit' Turnera5d41202010-05-10 18:37:10 -0700371 next_tb = 0;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800372 } else if ((interrupt_request & CPU_INTERRUPT_HARD) &&
David 'Digit' Turnerf645f7d2011-05-11 00:44:05 +0200373 (((env->hflags2 & HF2_VINTR_MASK) &&
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800374 (env->hflags2 & HF2_HIF_MASK)) ||
David 'Digit' Turnerf645f7d2011-05-11 00:44:05 +0200375 (!(env->hflags2 & HF2_VINTR_MASK) &&
376 (env->eflags & IF_MASK &&
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800377 !(env->hflags & HF_INHIBIT_IRQ_MASK))))) {
378 int intno;
David 'Digit' Turnerbf2340f2014-03-18 14:41:25 +0100379 svm_check_intercept(env, SVM_EXIT_INTR);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800380 env->interrupt_request &= ~(CPU_INTERRUPT_HARD | CPU_INTERRUPT_VIRQ);
381 intno = cpu_get_pic_interrupt(env);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700382 qemu_log_mask(CPU_LOG_TB_IN_ASM, "Servicing hardware INT=0x%02x\n", intno);
David 'Digit' Turnerbf2340f2014-03-18 14:41:25 +0100383 do_interrupt_x86_hardirq(env, intno, 1);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800384 /* ensure that no TB jump will be modified as
385 the program flow was changed */
386 next_tb = 0;
387#if !defined(CONFIG_USER_ONLY)
388 } else if ((interrupt_request & CPU_INTERRUPT_VIRQ) &&
David 'Digit' Turnerf645f7d2011-05-11 00:44:05 +0200389 (env->eflags & IF_MASK) &&
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800390 !(env->hflags & HF_INHIBIT_IRQ_MASK)) {
391 int intno;
392 /* FIXME: this should respect TPR */
David 'Digit' Turnerbf2340f2014-03-18 14:41:25 +0100393 svm_check_intercept(env, SVM_EXIT_VINTR);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800394 intno = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_vector));
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700395 qemu_log_mask(CPU_LOG_TB_IN_ASM, "Servicing virtual hardware INT=0x%02x\n", intno);
David 'Digit' Turnerbf2340f2014-03-18 14:41:25 +0100396 do_interrupt_x86_hardirq(env, intno, 1);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700397 env->interrupt_request &= ~CPU_INTERRUPT_VIRQ;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800398 next_tb = 0;
399#endif
400 }
401 }
402#elif defined(TARGET_PPC)
403#if 0
404 if ((interrupt_request & CPU_INTERRUPT_RESET)) {
David 'Digit' Turnera5d41202010-05-10 18:37:10 -0700405 cpu_reset(env);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800406 }
407#endif
408 if (interrupt_request & CPU_INTERRUPT_HARD) {
409 ppc_hw_interrupt(env);
410 if (env->pending_interrupts == 0)
411 env->interrupt_request &= ~CPU_INTERRUPT_HARD;
412 next_tb = 0;
413 }
David 'Digit' Turner42760382011-05-11 01:48:19 +0200414#elif defined(TARGET_LM32)
415 if ((interrupt_request & CPU_INTERRUPT_HARD)
416 && (env->ie & IE_IE)) {
417 env->exception_index = EXCP_IRQ;
418 do_interrupt(env);
419 next_tb = 0;
420 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700421#elif defined(TARGET_MICROBLAZE)
422 if ((interrupt_request & CPU_INTERRUPT_HARD)
423 && (env->sregs[SR_MSR] & MSR_IE)
424 && !(env->sregs[SR_MSR] & (MSR_EIP | MSR_BIP))
425 && !(env->iflags & (D_FLAG | IMM_FLAG))) {
426 env->exception_index = EXCP_IRQ;
427 do_interrupt(env);
428 next_tb = 0;
429 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800430#elif defined(TARGET_MIPS)
431 if ((interrupt_request & CPU_INTERRUPT_HARD) &&
David 'Digit' Turner42760382011-05-11 01:48:19 +0200432 cpu_mips_hw_interrupts_pending(env)) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800433 /* Raise it */
434 env->exception_index = EXCP_EXT_INTERRUPT;
435 env->error_code = 0;
436 do_interrupt(env);
437 next_tb = 0;
438 }
439#elif defined(TARGET_SPARC)
David Turner24cd25a2010-09-10 14:22:27 +0200440 if (interrupt_request & CPU_INTERRUPT_HARD) {
441 if (cpu_interrupts_enabled(env) &&
442 env->interrupt_index > 0) {
443 int pil = env->interrupt_index & 0xf;
444 int type = env->interrupt_index & 0xf0;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800445
David Turner24cd25a2010-09-10 14:22:27 +0200446 if (((type == TT_EXTINT) &&
447 cpu_pil_allowed(env, pil)) ||
448 type != TT_EXTINT) {
449 env->exception_index = env->interrupt_index;
450 do_interrupt(env);
451 next_tb = 0;
452 }
453 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800454 }
455#elif defined(TARGET_ARM)
456 if (interrupt_request & CPU_INTERRUPT_FIQ
457 && !(env->uncached_cpsr & CPSR_F)) {
458 env->exception_index = EXCP_FIQ;
459 do_interrupt(env);
460 next_tb = 0;
461 }
462 /* ARMv7-M interrupt return works by loading a magic value
463 into the PC. On real hardware the load causes the
464 return to occur. The qemu implementation performs the
465 jump normally, then does the exception return when the
466 CPU tries to execute code at the magic address.
467 This will cause the magic PC value to be pushed to
David 'Digit' Turner52858642011-06-03 13:41:05 +0200468 the stack if an interrupt occurred at the wrong time.
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800469 We avoid this by disabling interrupts when
470 pc contains a magic address. */
471 if (interrupt_request & CPU_INTERRUPT_HARD
472 && ((IS_M(env) && env->regs[15] < 0xfffffff0)
473 || !(env->uncached_cpsr & CPSR_I))) {
474 env->exception_index = EXCP_IRQ;
475 do_interrupt(env);
476 next_tb = 0;
477 }
David 'Digit' Turner42760382011-05-11 01:48:19 +0200478#elif defined(TARGET_UNICORE32)
479 if (interrupt_request & CPU_INTERRUPT_HARD
480 && !(env->uncached_asr & ASR_I)) {
481 do_interrupt(env);
482 next_tb = 0;
483 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800484#elif defined(TARGET_SH4)
485 if (interrupt_request & CPU_INTERRUPT_HARD) {
486 do_interrupt(env);
487 next_tb = 0;
488 }
489#elif defined(TARGET_ALPHA)
490 if (interrupt_request & CPU_INTERRUPT_HARD) {
491 do_interrupt(env);
492 next_tb = 0;
493 }
494#elif defined(TARGET_CRIS)
495 if (interrupt_request & CPU_INTERRUPT_HARD
David Turner24cd25a2010-09-10 14:22:27 +0200496 && (env->pregs[PR_CCS] & I_FLAG)
497 && !env->locked_irq) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800498 env->exception_index = EXCP_IRQ;
499 do_interrupt(env);
500 next_tb = 0;
501 }
502 if (interrupt_request & CPU_INTERRUPT_NMI
503 && (env->pregs[PR_CCS] & M_FLAG)) {
504 env->exception_index = EXCP_NMI;
505 do_interrupt(env);
506 next_tb = 0;
507 }
508#elif defined(TARGET_M68K)
509 if (interrupt_request & CPU_INTERRUPT_HARD
510 && ((env->sr & SR_I) >> SR_I_SHIFT)
511 < env->pending_level) {
512 /* Real hardware gets the interrupt vector via an
513 IACK cycle at this point. Current emulated
514 hardware doesn't rely on this, so we
515 provide/save the vector when the interrupt is
516 first signalled. */
517 env->exception_index = env->pending_vector;
David 'Digit' Turnerbf2340f2014-03-18 14:41:25 +0100518 do_interrupt_m68k_hardirq(env, 1);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800519 next_tb = 0;
520 }
David 'Digit' Turner42760382011-05-11 01:48:19 +0200521#elif defined(TARGET_S390X) && !defined(CONFIG_USER_ONLY)
522 if ((interrupt_request & CPU_INTERRUPT_HARD) &&
523 (env->psw.mask & PSW_MASK_EXT)) {
524 do_interrupt(env);
525 next_tb = 0;
526 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800527#endif
David 'Digit' Turner52858642011-06-03 13:41:05 +0200528 /* Don't use the cached interrupt_request value,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800529 do_interrupt may have updated the EXITTB flag. */
530 if (env->interrupt_request & CPU_INTERRUPT_EXITTB) {
531 env->interrupt_request &= ~CPU_INTERRUPT_EXITTB;
532 /* ensure that no TB jump will be modified as
533 the program flow was changed */
534 next_tb = 0;
535 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700536 }
537 if (unlikely(env->exit_request)) {
538 env->exit_request = 0;
539 env->exception_index = EXCP_INTERRUPT;
David 'Digit' Turner85c62202014-02-16 20:53:40 +0100540 cpu_loop_exit(env);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800541 }
David Turner24cd25a2010-09-10 14:22:27 +0200542#if defined(DEBUG_DISAS) || defined(CONFIG_DEBUG_EXEC)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700543 if (qemu_loglevel_mask(CPU_LOG_TB_CPU)) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800544 /* restore flags in standard format */
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800545#if defined(TARGET_I386)
David 'Digit' Turnerbf2340f2014-03-18 14:41:25 +0100546 env->eflags = env->eflags | cpu_cc_compute_all(env, CC_OP)
547 | (DF & DF_MASK);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700548 log_cpu_state(env, X86_DUMP_CCOP);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800549 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 -0800550#elif defined(TARGET_M68K)
551 cpu_m68k_flush_flags(env, env->cc_op);
552 env->cc_op = CC_OP_FLAGS;
553 env->sr = (env->sr & 0xffe0)
554 | env->cc_dest | (env->cc_x << 4);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700555 log_cpu_state(env, 0);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800556#else
David Turner24cd25a2010-09-10 14:22:27 +0200557 log_cpu_state(env, 0);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800558#endif
559 }
David Turner24cd25a2010-09-10 14:22:27 +0200560#endif /* DEBUG_DISAS || CONFIG_DEBUG_EXEC */
David 'Digit' Turner13487772014-02-17 21:16:46 +0100561 spin_lock(&tcg_ctx.tb_ctx.tb_lock);
David 'Digit' Turnera6810012014-03-18 09:24:22 +0100562 tb = tb_find_fast(env);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800563 /* Note: we do it here to avoid a gcc bug on Mac OS X when
564 doing it in tb_find_slow */
565 if (tb_invalidated_flag) {
566 /* as some TB could have been invalidated because
567 of memory exceptions while generating the code, we
568 must recompute the hash index here */
569 next_tb = 0;
570 tb_invalidated_flag = 0;
571 }
David Turner24cd25a2010-09-10 14:22:27 +0200572#ifdef CONFIG_DEBUG_EXEC
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700573 qemu_log_mask(CPU_LOG_EXEC, "Trace 0x%08lx [" TARGET_FMT_lx "] %s\n",
574 (long)tb->tc_ptr, tb->pc,
575 lookup_symbol(tb->pc));
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800576#endif
577 /* see if we can patch the calling TB. When the TB
578 spans two pages, we cannot safely do a direct
579 jump. */
David Turner24cd25a2010-09-10 14:22:27 +0200580 if (next_tb != 0 && tb->page_addr[1] == -1) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800581 tb_add_jump((TranslationBlock *)(next_tb & ~3), next_tb & 3, tb);
582 }
David 'Digit' Turner13487772014-02-17 21:16:46 +0100583 spin_unlock(&tcg_ctx.tb_ctx.tb_lock);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700584
585 /* cpu_interrupt might be called while translating the
586 TB, but before it is linked into a potentially
587 infinite loop and becomes env->current_tb. Avoid
588 starting execution if there is a pending interrupt. */
David Turner24cd25a2010-09-10 14:22:27 +0200589 env->current_tb = tb;
590 barrier();
591 if (likely(!env->exit_request)) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800592 tc_ptr = tb->tc_ptr;
593 /* execute the generated code */
David 'Digit' Turnera6810012014-03-18 09:24:22 +0100594 next_tb = tcg_qemu_tb_exec(env, tc_ptr);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800595 if ((next_tb & 3) == 2) {
596 /* Instruction counter expired. */
597 int insns_left;
598 tb = (TranslationBlock *)(long)(next_tb & ~3);
599 /* Restore PC. */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700600 cpu_pc_from_tb(env, tb);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800601 insns_left = env->icount_decr.u32;
602 if (env->icount_extra && insns_left >= 0) {
603 /* Refill decrementer and continue execution. */
604 env->icount_extra += insns_left;
605 if (env->icount_extra > 0xffff) {
606 insns_left = 0xffff;
607 } else {
608 insns_left = env->icount_extra;
609 }
610 env->icount_extra -= insns_left;
611 env->icount_decr.u16.low = insns_left;
612 } else {
613 if (insns_left > 0) {
614 /* Execute remaining instructions. */
David 'Digit' Turnera6810012014-03-18 09:24:22 +0100615 cpu_exec_nocache(env, insns_left, tb);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800616 }
617 env->exception_index = EXCP_INTERRUPT;
618 next_tb = 0;
David 'Digit' Turner85c62202014-02-16 20:53:40 +0100619 cpu_loop_exit(env);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800620 }
621 }
622 }
David Turner24cd25a2010-09-10 14:22:27 +0200623 env->current_tb = NULL;
Jun Nakajimaa381ef02011-12-17 19:13:25 -0800624#ifdef CONFIG_HAX
625 if (hax_enabled() && hax_stop_emulation(env))
David 'Digit' Turner85c62202014-02-16 20:53:40 +0100626 cpu_loop_exit(env);
Jun Nakajimaa381ef02011-12-17 19:13:25 -0800627#endif
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800628 /* reset soft MMU for next block (it can currently
629 only be set by a memory fault) */
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800630 } /* for(;;) */
David 'Digit' Turner730dce72014-03-18 16:54:13 +0100631 } else {
632 /* Reload env after longjmp - the compiler may have smashed all
633 * local variables as longjmp is marked 'noreturn'. */
634 env = cpu_single_env;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800635 }
636 } /* for(;;) */
637
638
639#if defined(TARGET_I386)
640 /* restore flags in standard format */
David 'Digit' Turnerbf2340f2014-03-18 14:41:25 +0100641 env->eflags = env->eflags | cpu_cc_compute_all(env, CC_OP)
642 | (DF & DF_MASK);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800643#elif defined(TARGET_ARM)
644 /* XXX: Save/restore host fpu exception state?. */
David 'Digit' Turner42760382011-05-11 01:48:19 +0200645#elif defined(TARGET_UNICORE32)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800646#elif defined(TARGET_SPARC)
647#elif defined(TARGET_PPC)
David 'Digit' Turner42760382011-05-11 01:48:19 +0200648#elif defined(TARGET_LM32)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800649#elif defined(TARGET_M68K)
650 cpu_m68k_flush_flags(env, env->cc_op);
651 env->cc_op = CC_OP_FLAGS;
652 env->sr = (env->sr & 0xffe0)
653 | env->cc_dest | (env->cc_x << 4);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700654#elif defined(TARGET_MICROBLAZE)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800655#elif defined(TARGET_MIPS)
656#elif defined(TARGET_SH4)
657#elif defined(TARGET_ALPHA)
658#elif defined(TARGET_CRIS)
David Turner24cd25a2010-09-10 14:22:27 +0200659#elif defined(TARGET_S390X)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800660 /* XXXXX */
661#else
662#error unsupported target CPU
663#endif
664
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800665 /* fail safe : never use cpu_single_env outside cpu_exec() */
666 cpu_single_env = NULL;
667 return ret;
668}
669
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800670#if defined(TARGET_I386) && defined(CONFIG_USER_ONLY)
671
672void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector)
673{
674 CPUX86State *saved_env;
675
676 saved_env = env;
677 env = s;
678 if (!(env->cr[0] & CR0_PE_MASK) || (env->eflags & VM_MASK)) {
679 selector &= 0xffff;
680 cpu_x86_load_seg_cache(env, seg_reg, selector,
681 (selector << 4), 0xffff, 0);
682 } else {
683 helper_load_seg(seg_reg, selector);
684 }
685 env = saved_env;
686}
687
688void cpu_x86_fsave(CPUX86State *s, target_ulong ptr, int data32)
689{
690 CPUX86State *saved_env;
691
692 saved_env = env;
693 env = s;
694
695 helper_fsave(ptr, data32);
696
697 env = saved_env;
698}
699
700void cpu_x86_frstor(CPUX86State *s, target_ulong ptr, int data32)
701{
702 CPUX86State *saved_env;
703
704 saved_env = env;
705 env = s;
706
707 helper_frstor(ptr, data32);
708
709 env = saved_env;
710}
711
712#endif /* TARGET_I386 */
713
714#if !defined(CONFIG_SOFTMMU)
715
716#if defined(TARGET_I386)
David Turner24cd25a2010-09-10 14:22:27 +0200717#define EXCEPTION_ACTION raise_exception_err(env->exception_index, env->error_code)
718#else
David 'Digit' Turner85c62202014-02-16 20:53:40 +0100719#define EXCEPTION_ACTION cpu_loop_exit(env)
David Turner24cd25a2010-09-10 14:22:27 +0200720#endif
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800721
722/* 'pc' is the host PC at which the exception was raised. 'address' is
723 the effective address of the memory exception. 'is_write' is 1 if a
724 write caused the exception and otherwise 0'. 'old_set' is the
725 signal set which should be restored */
726static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
727 int is_write, sigset_t *old_set,
728 void *puc)
729{
730 TranslationBlock *tb;
731 int ret;
732
733 if (cpu_single_env)
734 env = cpu_single_env; /* XXX: find a correct solution for multithread */
735#if defined(DEBUG_SIGNAL)
736 qemu_printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
737 pc, address, is_write, *(unsigned long *)old_set);
738#endif
739 /* XXX: locking issue */
740 if (is_write && page_unprotect(h2g(address), pc, puc)) {
741 return 1;
742 }
743
744 /* see if it is an MMU fault */
David Turner24cd25a2010-09-10 14:22:27 +0200745 ret = cpu_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800746 if (ret < 0)
747 return 0; /* not an MMU fault */
748 if (ret == 0)
749 return 1; /* the MMU fault was handled without causing real CPU fault */
750 /* now we have a real cpu fault */
751 tb = tb_find_pc(pc);
752 if (tb) {
753 /* the PC is inside the translated code. It means that we have
754 a virtual CPU fault */
David 'Digit' Turner3e0677d2014-03-07 15:01:06 +0100755 cpu_restore_state(env, pc);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800756 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800757
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800758 /* we restore the process signal mask as the sigreturn should
759 do it (XXX: use sigsetjmp) */
760 sigprocmask(SIG_SETMASK, old_set, NULL);
David Turner24cd25a2010-09-10 14:22:27 +0200761 EXCEPTION_ACTION;
762
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800763 /* never comes here */
764 return 1;
765}
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800766
767#if defined(__i386__)
768
769#if defined(__APPLE__)
770# include <sys/ucontext.h>
771
772# define EIP_sig(context) (*((unsigned long*)&(context)->uc_mcontext->ss.eip))
773# define TRAP_sig(context) ((context)->uc_mcontext->es.trapno)
774# define ERROR_sig(context) ((context)->uc_mcontext->es.err)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700775# define MASK_sig(context) ((context)->uc_sigmask)
David Turner24cd25a2010-09-10 14:22:27 +0200776#elif defined (__NetBSD__)
777# include <ucontext.h>
778
779# define EIP_sig(context) ((context)->uc_mcontext.__gregs[_REG_EIP])
780# define TRAP_sig(context) ((context)->uc_mcontext.__gregs[_REG_TRAPNO])
781# define ERROR_sig(context) ((context)->uc_mcontext.__gregs[_REG_ERR])
782# define MASK_sig(context) ((context)->uc_sigmask)
783#elif defined (__FreeBSD__) || defined(__DragonFly__)
784# include <ucontext.h>
785
786# define EIP_sig(context) (*((unsigned long*)&(context)->uc_mcontext.mc_eip))
787# define TRAP_sig(context) ((context)->uc_mcontext.mc_trapno)
788# define ERROR_sig(context) ((context)->uc_mcontext.mc_err)
789# define MASK_sig(context) ((context)->uc_sigmask)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700790#elif defined(__OpenBSD__)
791# define EIP_sig(context) ((context)->sc_eip)
792# define TRAP_sig(context) ((context)->sc_trapno)
793# define ERROR_sig(context) ((context)->sc_err)
794# define MASK_sig(context) ((context)->sc_mask)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800795#else
796# define EIP_sig(context) ((context)->uc_mcontext.gregs[REG_EIP])
797# define TRAP_sig(context) ((context)->uc_mcontext.gregs[REG_TRAPNO])
798# define ERROR_sig(context) ((context)->uc_mcontext.gregs[REG_ERR])
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700799# define MASK_sig(context) ((context)->uc_sigmask)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800800#endif
801
802int cpu_signal_handler(int host_signum, void *pinfo,
803 void *puc)
804{
805 siginfo_t *info = pinfo;
David Turner24cd25a2010-09-10 14:22:27 +0200806#if defined(__NetBSD__) || defined (__FreeBSD__) || defined(__DragonFly__)
807 ucontext_t *uc = puc;
808#elif defined(__OpenBSD__)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700809 struct sigcontext *uc = puc;
810#else
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800811 struct ucontext *uc = puc;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700812#endif
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800813 unsigned long pc;
814 int trapno;
815
816#ifndef REG_EIP
817/* for glibc 2.1 */
818#define REG_EIP EIP
819#define REG_ERR ERR
820#define REG_TRAPNO TRAPNO
821#endif
822 pc = EIP_sig(uc);
823 trapno = TRAP_sig(uc);
824 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
825 trapno == 0xe ?
826 (ERROR_sig(uc) >> 1) & 1 : 0,
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700827 &MASK_sig(uc), puc);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800828}
829
830#elif defined(__x86_64__)
831
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700832#ifdef __NetBSD__
833#define PC_sig(context) _UC_MACHINE_PC(context)
834#define TRAP_sig(context) ((context)->uc_mcontext.__gregs[_REG_TRAPNO])
835#define ERROR_sig(context) ((context)->uc_mcontext.__gregs[_REG_ERR])
836#define MASK_sig(context) ((context)->uc_sigmask)
837#elif defined(__OpenBSD__)
838#define PC_sig(context) ((context)->sc_rip)
839#define TRAP_sig(context) ((context)->sc_trapno)
840#define ERROR_sig(context) ((context)->sc_err)
841#define MASK_sig(context) ((context)->sc_mask)
David Turner24cd25a2010-09-10 14:22:27 +0200842#elif defined (__FreeBSD__) || defined(__DragonFly__)
843#include <ucontext.h>
844
845#define PC_sig(context) (*((unsigned long*)&(context)->uc_mcontext.mc_rip))
846#define TRAP_sig(context) ((context)->uc_mcontext.mc_trapno)
847#define ERROR_sig(context) ((context)->uc_mcontext.mc_err)
848#define MASK_sig(context) ((context)->uc_sigmask)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700849#else
850#define PC_sig(context) ((context)->uc_mcontext.gregs[REG_RIP])
851#define TRAP_sig(context) ((context)->uc_mcontext.gregs[REG_TRAPNO])
852#define ERROR_sig(context) ((context)->uc_mcontext.gregs[REG_ERR])
853#define MASK_sig(context) ((context)->uc_sigmask)
854#endif
855
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800856int cpu_signal_handler(int host_signum, void *pinfo,
857 void *puc)
858{
859 siginfo_t *info = pinfo;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800860 unsigned long pc;
David Turner24cd25a2010-09-10 14:22:27 +0200861#if defined(__NetBSD__) || defined (__FreeBSD__) || defined(__DragonFly__)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700862 ucontext_t *uc = puc;
863#elif defined(__OpenBSD__)
864 struct sigcontext *uc = puc;
865#else
866 struct ucontext *uc = puc;
867#endif
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800868
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700869 pc = PC_sig(uc);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800870 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700871 TRAP_sig(uc) == 0xe ?
872 (ERROR_sig(uc) >> 1) & 1 : 0,
873 &MASK_sig(uc), puc);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800874}
875
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700876#elif defined(_ARCH_PPC)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800877
878/***********************************************************************
879 * signal context platform-specific definitions
880 * From Wine
881 */
882#ifdef linux
883/* All Registers access - only for local access */
884# define REG_sig(reg_name, context) ((context)->uc_mcontext.regs->reg_name)
885/* Gpr Registers access */
886# define GPR_sig(reg_num, context) REG_sig(gpr[reg_num], context)
887# define IAR_sig(context) REG_sig(nip, context) /* Program counter */
888# define MSR_sig(context) REG_sig(msr, context) /* Machine State Register (Supervisor) */
889# define CTR_sig(context) REG_sig(ctr, context) /* Count register */
890# define XER_sig(context) REG_sig(xer, context) /* User's integer exception register */
891# define LR_sig(context) REG_sig(link, context) /* Link register */
892# define CR_sig(context) REG_sig(ccr, context) /* Condition register */
893/* Float Registers access */
894# define FLOAT_sig(reg_num, context) (((double*)((char*)((context)->uc_mcontext.regs+48*4)))[reg_num])
895# define FPSCR_sig(context) (*(int*)((char*)((context)->uc_mcontext.regs+(48+32*2)*4)))
896/* Exception Registers access */
897# define DAR_sig(context) REG_sig(dar, context)
898# define DSISR_sig(context) REG_sig(dsisr, context)
899# define TRAP_sig(context) REG_sig(trap, context)
900#endif /* linux */
901
David Turner24cd25a2010-09-10 14:22:27 +0200902#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
903#include <ucontext.h>
904# define IAR_sig(context) ((context)->uc_mcontext.mc_srr0)
905# define MSR_sig(context) ((context)->uc_mcontext.mc_srr1)
906# define CTR_sig(context) ((context)->uc_mcontext.mc_ctr)
907# define XER_sig(context) ((context)->uc_mcontext.mc_xer)
908# define LR_sig(context) ((context)->uc_mcontext.mc_lr)
909# define CR_sig(context) ((context)->uc_mcontext.mc_cr)
910/* Exception Registers access */
911# define DAR_sig(context) ((context)->uc_mcontext.mc_dar)
912# define DSISR_sig(context) ((context)->uc_mcontext.mc_dsisr)
913# define TRAP_sig(context) ((context)->uc_mcontext.mc_exc)
914#endif /* __FreeBSD__|| __FreeBSD_kernel__ */
915
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800916#ifdef __APPLE__
917# include <sys/ucontext.h>
918typedef struct ucontext SIGCONTEXT;
919/* All Registers access - only for local access */
920# define REG_sig(reg_name, context) ((context)->uc_mcontext->ss.reg_name)
921# define FLOATREG_sig(reg_name, context) ((context)->uc_mcontext->fs.reg_name)
922# define EXCEPREG_sig(reg_name, context) ((context)->uc_mcontext->es.reg_name)
923# define VECREG_sig(reg_name, context) ((context)->uc_mcontext->vs.reg_name)
924/* Gpr Registers access */
925# define GPR_sig(reg_num, context) REG_sig(r##reg_num, context)
926# define IAR_sig(context) REG_sig(srr0, context) /* Program counter */
927# define MSR_sig(context) REG_sig(srr1, context) /* Machine State Register (Supervisor) */
928# define CTR_sig(context) REG_sig(ctr, context)
929# define XER_sig(context) REG_sig(xer, context) /* Link register */
930# define LR_sig(context) REG_sig(lr, context) /* User's integer exception register */
931# define CR_sig(context) REG_sig(cr, context) /* Condition register */
932/* Float Registers access */
933# define FLOAT_sig(reg_num, context) FLOATREG_sig(fpregs[reg_num], context)
934# define FPSCR_sig(context) ((double)FLOATREG_sig(fpscr, context))
935/* Exception Registers access */
936# define DAR_sig(context) EXCEPREG_sig(dar, context) /* Fault registers for coredump */
937# define DSISR_sig(context) EXCEPREG_sig(dsisr, context)
938# define TRAP_sig(context) EXCEPREG_sig(exception, context) /* number of powerpc exception taken */
939#endif /* __APPLE__ */
940
941int cpu_signal_handler(int host_signum, void *pinfo,
942 void *puc)
943{
944 siginfo_t *info = pinfo;
David Turner24cd25a2010-09-10 14:22:27 +0200945#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
946 ucontext_t *uc = puc;
947#else
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800948 struct ucontext *uc = puc;
David Turner24cd25a2010-09-10 14:22:27 +0200949#endif
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800950 unsigned long pc;
951 int is_write;
952
953 pc = IAR_sig(uc);
954 is_write = 0;
955#if 0
956 /* ppc 4xx case */
957 if (DSISR_sig(uc) & 0x00800000)
958 is_write = 1;
959#else
960 if (TRAP_sig(uc) != 0x400 && (DSISR_sig(uc) & 0x02000000))
961 is_write = 1;
962#endif
963 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
964 is_write, &uc->uc_sigmask, puc);
965}
966
967#elif defined(__alpha__)
968
969int cpu_signal_handler(int host_signum, void *pinfo,
970 void *puc)
971{
972 siginfo_t *info = pinfo;
973 struct ucontext *uc = puc;
974 uint32_t *pc = uc->uc_mcontext.sc_pc;
975 uint32_t insn = *pc;
976 int is_write = 0;
977
978 /* XXX: need kernel patch to get write flag faster */
979 switch (insn >> 26) {
980 case 0x0d: // stw
981 case 0x0e: // stb
982 case 0x0f: // stq_u
983 case 0x24: // stf
984 case 0x25: // stg
985 case 0x26: // sts
986 case 0x27: // stt
987 case 0x2c: // stl
988 case 0x2d: // stq
989 case 0x2e: // stl_c
990 case 0x2f: // stq_c
991 is_write = 1;
992 }
993
994 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
995 is_write, &uc->uc_sigmask, puc);
996}
997#elif defined(__sparc__)
998
999int cpu_signal_handler(int host_signum, void *pinfo,
1000 void *puc)
1001{
1002 siginfo_t *info = pinfo;
1003 int is_write;
1004 uint32_t insn;
David 'Digit' Turner2c538c82010-05-10 16:48:20 -07001005#if !defined(__arch64__) || defined(CONFIG_SOLARIS)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001006 uint32_t *regs = (uint32_t *)(info + 1);
1007 void *sigmask = (regs + 20);
1008 /* XXX: is there a standard glibc define ? */
1009 unsigned long pc = regs[1];
1010#else
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001011#ifdef __linux__
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001012 struct sigcontext *sc = puc;
1013 unsigned long pc = sc->sigc_regs.tpc;
1014 void *sigmask = (void *)sc->sigc_mask;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001015#elif defined(__OpenBSD__)
1016 struct sigcontext *uc = puc;
1017 unsigned long pc = uc->sc_pc;
1018 void *sigmask = (void *)(long)uc->sc_mask;
1019#endif
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001020#endif
1021
1022 /* XXX: need kernel patch to get write flag faster */
1023 is_write = 0;
1024 insn = *(uint32_t *)pc;
1025 if ((insn >> 30) == 3) {
1026 switch((insn >> 19) & 0x3f) {
1027 case 0x05: // stb
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001028 case 0x15: // stba
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001029 case 0x06: // sth
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001030 case 0x16: // stha
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001031 case 0x04: // st
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001032 case 0x14: // sta
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001033 case 0x07: // std
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001034 case 0x17: // stda
1035 case 0x0e: // stx
1036 case 0x1e: // stxa
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001037 case 0x24: // stf
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001038 case 0x34: // stfa
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001039 case 0x27: // stdf
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001040 case 0x37: // stdfa
1041 case 0x26: // stqf
1042 case 0x36: // stqfa
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001043 case 0x25: // stfsr
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001044 case 0x3c: // casa
1045 case 0x3e: // casxa
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001046 is_write = 1;
1047 break;
1048 }
1049 }
1050 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1051 is_write, sigmask, NULL);
1052}
1053
1054#elif defined(__arm__)
1055
1056int cpu_signal_handler(int host_signum, void *pinfo,
1057 void *puc)
1058{
1059 siginfo_t *info = pinfo;
1060 struct ucontext *uc = puc;
1061 unsigned long pc;
1062 int is_write;
1063
1064#if (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ <= 3))
1065 pc = uc->uc_mcontext.gregs[R15];
1066#else
1067 pc = uc->uc_mcontext.arm_pc;
1068#endif
1069 /* XXX: compute is_write */
1070 is_write = 0;
1071 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1072 is_write,
1073 &uc->uc_sigmask, puc);
1074}
1075
1076#elif defined(__mc68000)
1077
1078int cpu_signal_handler(int host_signum, void *pinfo,
1079 void *puc)
1080{
1081 siginfo_t *info = pinfo;
1082 struct ucontext *uc = puc;
1083 unsigned long pc;
1084 int is_write;
1085
1086 pc = uc->uc_mcontext.gregs[16];
1087 /* XXX: compute is_write */
1088 is_write = 0;
1089 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1090 is_write,
1091 &uc->uc_sigmask, puc);
1092}
1093
1094#elif defined(__ia64)
1095
1096#ifndef __ISR_VALID
1097 /* This ought to be in <bits/siginfo.h>... */
1098# define __ISR_VALID 1
1099#endif
1100
1101int cpu_signal_handler(int host_signum, void *pinfo, void *puc)
1102{
1103 siginfo_t *info = pinfo;
1104 struct ucontext *uc = puc;
1105 unsigned long ip;
1106 int is_write = 0;
1107
1108 ip = uc->uc_mcontext.sc_ip;
1109 switch (host_signum) {
1110 case SIGILL:
1111 case SIGFPE:
1112 case SIGSEGV:
1113 case SIGBUS:
1114 case SIGTRAP:
1115 if (info->si_code && (info->si_segvflags & __ISR_VALID))
1116 /* ISR.W (write-access) is bit 33: */
1117 is_write = (info->si_isr >> 33) & 1;
1118 break;
1119
1120 default:
1121 break;
1122 }
1123 return handle_cpu_signal(ip, (unsigned long)info->si_addr,
1124 is_write,
David Turner24cd25a2010-09-10 14:22:27 +02001125 (sigset_t *)&uc->uc_sigmask, puc);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001126}
1127
1128#elif defined(__s390__)
1129
1130int cpu_signal_handler(int host_signum, void *pinfo,
1131 void *puc)
1132{
1133 siginfo_t *info = pinfo;
1134 struct ucontext *uc = puc;
1135 unsigned long pc;
David Turner24cd25a2010-09-10 14:22:27 +02001136 uint16_t *pinsn;
1137 int is_write = 0;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001138
1139 pc = uc->uc_mcontext.psw.addr;
David Turner24cd25a2010-09-10 14:22:27 +02001140
1141 /* ??? On linux, the non-rt signal handler has 4 (!) arguments instead
1142 of the normal 2 arguments. The 3rd argument contains the "int_code"
1143 from the hardware which does in fact contain the is_write value.
1144 The rt signal handler, as far as I can tell, does not give this value
1145 at all. Not that we could get to it from here even if it were. */
1146 /* ??? This is not even close to complete, since it ignores all
1147 of the read-modify-write instructions. */
1148 pinsn = (uint16_t *)pc;
1149 switch (pinsn[0] >> 8) {
1150 case 0x50: /* ST */
1151 case 0x42: /* STC */
1152 case 0x40: /* STH */
1153 is_write = 1;
1154 break;
1155 case 0xc4: /* RIL format insns */
1156 switch (pinsn[0] & 0xf) {
1157 case 0xf: /* STRL */
1158 case 0xb: /* STGRL */
1159 case 0x7: /* STHRL */
1160 is_write = 1;
1161 }
1162 break;
1163 case 0xe3: /* RXY format insns */
1164 switch (pinsn[2] & 0xff) {
1165 case 0x50: /* STY */
1166 case 0x24: /* STG */
1167 case 0x72: /* STCY */
1168 case 0x70: /* STHY */
1169 case 0x8e: /* STPQ */
1170 case 0x3f: /* STRVH */
1171 case 0x3e: /* STRV */
1172 case 0x2f: /* STRVG */
1173 is_write = 1;
1174 }
1175 break;
1176 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001177 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1178 is_write, &uc->uc_sigmask, puc);
1179}
1180
1181#elif defined(__mips__)
1182
1183int cpu_signal_handler(int host_signum, void *pinfo,
1184 void *puc)
1185{
1186 siginfo_t *info = pinfo;
1187 struct ucontext *uc = puc;
1188 greg_t pc = uc->uc_mcontext.pc;
1189 int is_write;
1190
1191 /* XXX: compute is_write */
1192 is_write = 0;
1193 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1194 is_write, &uc->uc_sigmask, puc);
1195}
1196
1197#elif defined(__hppa__)
1198
1199int cpu_signal_handler(int host_signum, void *pinfo,
1200 void *puc)
1201{
1202 struct siginfo *info = pinfo;
1203 struct ucontext *uc = puc;
David Turner24cd25a2010-09-10 14:22:27 +02001204 unsigned long pc = uc->uc_mcontext.sc_iaoq[0];
1205 uint32_t insn = *(uint32_t *)pc;
1206 int is_write = 0;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001207
David Turner24cd25a2010-09-10 14:22:27 +02001208 /* XXX: need kernel patch to get write flag faster. */
1209 switch (insn >> 26) {
1210 case 0x1a: /* STW */
1211 case 0x19: /* STH */
1212 case 0x18: /* STB */
1213 case 0x1b: /* STWM */
1214 is_write = 1;
1215 break;
1216
1217 case 0x09: /* CSTWX, FSTWX, FSTWS */
1218 case 0x0b: /* CSTDX, FSTDX, FSTDS */
1219 /* Distinguish from coprocessor load ... */
1220 is_write = (insn >> 9) & 1;
1221 break;
1222
1223 case 0x03:
1224 switch ((insn >> 6) & 15) {
1225 case 0xa: /* STWS */
1226 case 0x9: /* STHS */
1227 case 0x8: /* STBS */
1228 case 0xe: /* STWAS */
1229 case 0xc: /* STBYS */
1230 is_write = 1;
1231 }
1232 break;
1233 }
1234
David 'Digit' Turnerf645f7d2011-05-11 00:44:05 +02001235 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
David Turner24cd25a2010-09-10 14:22:27 +02001236 is_write, &uc->uc_sigmask, puc);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001237}
1238
1239#else
1240
1241#error host CPU specific signal handler needed
1242
1243#endif
1244
1245#endif /* !defined(CONFIG_SOFTMMU) */