blob: cf7c1fba7ea8bc0a249ab6931705b8b714d7eeb4 [file] [log] [blame]
bellard7d132992003-03-06 23:23:54 +00001/*
2 * i386 emulator main execution loop
ths5fafdf22007-09-16 21:08:06 +00003 *
bellard66321a12005-04-06 20:47:48 +00004 * Copyright (c) 2003-2005 Fabrice Bellard
bellard7d132992003-03-06 23:23:54 +00005 *
bellard3ef693a2003-03-23 20:17:16 +00006 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
bellard7d132992003-03-06 23:23:54 +000010 *
bellard3ef693a2003-03-23 20:17:16 +000011 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
bellard7d132992003-03-06 23:23:54 +000015 *
bellard3ef693a2003-03-23 20:17:16 +000016 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
aurel32fad6cb12009-01-04 22:05:52 +000018 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA
bellard7d132992003-03-06 23:23:54 +000019 */
bellarde4533c72003-06-15 19:51:39 +000020#include "config.h"
bellard93ac68b2003-09-30 20:57:29 +000021#include "exec.h"
bellard956034d2003-04-29 20:40:53 +000022#include "disas.h"
bellard7cb69ca2008-05-10 10:55:51 +000023#include "tcg.h"
aliguori7ba1e612008-11-05 16:04:33 +000024#include "kvm.h"
bellard7d132992003-03-06 23:23:54 +000025
bellardfbf9eeb2004-04-25 21:21:33 +000026#if !defined(CONFIG_SOFTMMU)
27#undef EAX
28#undef ECX
29#undef EDX
30#undef EBX
31#undef ESP
32#undef EBP
33#undef ESI
34#undef EDI
35#undef EIP
36#include <signal.h>
blueswir184778502008-10-26 20:33:16 +000037#ifdef __linux__
bellardfbf9eeb2004-04-25 21:21:33 +000038#include <sys/ucontext.h>
39#endif
blueswir184778502008-10-26 20:33:16 +000040#endif
bellardfbf9eeb2004-04-25 21:21:33 +000041
blueswir1572a9d42008-05-17 07:38:10 +000042#if defined(__sparc__) && !defined(HOST_SOLARIS)
43// Work around ugly bugs in glibc that mangle global register contents
44#undef env
45#define env cpu_single_env
46#endif
47
bellard36bdbe52003-11-19 22:12:02 +000048int tb_invalidated_flag;
49
bellarddc990652003-03-19 00:00:28 +000050//#define DEBUG_EXEC
bellard9de5e442003-03-23 16:49:39 +000051//#define DEBUG_SIGNAL
bellard7d132992003-03-06 23:23:54 +000052
bellarde4533c72003-06-15 19:51:39 +000053void cpu_loop_exit(void)
54{
thsbfed01f2007-06-03 17:44:37 +000055 /* NOTE: the register at this point must be saved by hand because
56 longjmp restore them */
57 regs_to_env();
bellarde4533c72003-06-15 19:51:39 +000058 longjmp(env->jmp_env, 1);
59}
thsbfed01f2007-06-03 17:44:37 +000060
bellardfbf9eeb2004-04-25 21:21:33 +000061/* exit the current TB from a signal handler. The host registers are
62 restored in a state compatible with the CPU emulator
63 */
ths5fafdf22007-09-16 21:08:06 +000064void cpu_resume_from_signal(CPUState *env1, void *puc)
bellardfbf9eeb2004-04-25 21:21:33 +000065{
66#if !defined(CONFIG_SOFTMMU)
blueswir184778502008-10-26 20:33:16 +000067#ifdef __linux__
bellardfbf9eeb2004-04-25 21:21:33 +000068 struct ucontext *uc = puc;
blueswir184778502008-10-26 20:33:16 +000069#elif defined(__OpenBSD__)
70 struct sigcontext *uc = puc;
71#endif
bellardfbf9eeb2004-04-25 21:21:33 +000072#endif
73
74 env = env1;
75
76 /* XXX: restore cpu registers saved in host registers */
77
78#if !defined(CONFIG_SOFTMMU)
79 if (puc) {
80 /* XXX: use siglongjmp ? */
blueswir184778502008-10-26 20:33:16 +000081#ifdef __linux__
bellardfbf9eeb2004-04-25 21:21:33 +000082 sigprocmask(SIG_SETMASK, &uc->uc_sigmask, NULL);
blueswir184778502008-10-26 20:33:16 +000083#elif defined(__OpenBSD__)
84 sigprocmask(SIG_SETMASK, &uc->sc_mask, NULL);
85#endif
bellardfbf9eeb2004-04-25 21:21:33 +000086 }
87#endif
pbrook9a3ea652008-12-19 12:49:13 +000088 env->exception_index = -1;
bellardfbf9eeb2004-04-25 21:21:33 +000089 longjmp(env->jmp_env, 1);
90}
91
pbrook2e70f6e2008-06-29 01:03:05 +000092/* Execute the code without caching the generated code. An interpreter
93 could be used if available. */
94static void cpu_exec_nocache(int max_cycles, TranslationBlock *orig_tb)
95{
96 unsigned long next_tb;
97 TranslationBlock *tb;
98
99 /* Should never happen.
100 We only end up here when an existing TB is too long. */
101 if (max_cycles > CF_COUNT_MASK)
102 max_cycles = CF_COUNT_MASK;
103
104 tb = tb_gen_code(env, orig_tb->pc, orig_tb->cs_base, orig_tb->flags,
105 max_cycles);
106 env->current_tb = tb;
107 /* execute the generated code */
108 next_tb = tcg_qemu_tb_exec(tb->tc_ptr);
109
110 if ((next_tb & 3) == 2) {
111 /* Restore PC. This may happen if async event occurs before
112 the TB starts executing. */
aliguori622ed362008-11-18 19:36:03 +0000113 cpu_pc_from_tb(env, tb);
pbrook2e70f6e2008-06-29 01:03:05 +0000114 }
115 tb_phys_invalidate(tb, -1);
116 tb_free(tb);
117}
118
bellard8a40a182005-11-20 10:35:40 +0000119static TranslationBlock *tb_find_slow(target_ulong pc,
120 target_ulong cs_base,
j_mayerc0686882007-09-20 22:47:42 +0000121 uint64_t flags)
bellard8a40a182005-11-20 10:35:40 +0000122{
123 TranslationBlock *tb, **ptb1;
bellard8a40a182005-11-20 10:35:40 +0000124 unsigned int h;
125 target_ulong phys_pc, phys_page1, phys_page2, virt_page2;
ths3b46e622007-09-17 08:09:54 +0000126
bellard8a40a182005-11-20 10:35:40 +0000127 tb_invalidated_flag = 0;
ths3b46e622007-09-17 08:09:54 +0000128
bellard8a40a182005-11-20 10:35:40 +0000129 regs_to_env(); /* XXX: do it just before cpu_gen_code() */
ths3b46e622007-09-17 08:09:54 +0000130
bellard8a40a182005-11-20 10:35:40 +0000131 /* find translated block using physical mappings */
132 phys_pc = get_phys_addr_code(env, pc);
133 phys_page1 = phys_pc & TARGET_PAGE_MASK;
134 phys_page2 = -1;
135 h = tb_phys_hash_func(phys_pc);
136 ptb1 = &tb_phys_hash[h];
137 for(;;) {
138 tb = *ptb1;
139 if (!tb)
140 goto not_found;
ths5fafdf22007-09-16 21:08:06 +0000141 if (tb->pc == pc &&
bellard8a40a182005-11-20 10:35:40 +0000142 tb->page_addr[0] == phys_page1 &&
ths5fafdf22007-09-16 21:08:06 +0000143 tb->cs_base == cs_base &&
bellard8a40a182005-11-20 10:35:40 +0000144 tb->flags == flags) {
145 /* check next page if needed */
146 if (tb->page_addr[1] != -1) {
ths5fafdf22007-09-16 21:08:06 +0000147 virt_page2 = (pc & TARGET_PAGE_MASK) +
bellard8a40a182005-11-20 10:35:40 +0000148 TARGET_PAGE_SIZE;
149 phys_page2 = get_phys_addr_code(env, virt_page2);
150 if (tb->page_addr[1] == phys_page2)
151 goto found;
152 } else {
153 goto found;
154 }
155 }
156 ptb1 = &tb->phys_hash_next;
157 }
158 not_found:
pbrook2e70f6e2008-06-29 01:03:05 +0000159 /* if no translated code available, then translate it now */
160 tb = tb_gen_code(env, pc, cs_base, flags, 0);
ths3b46e622007-09-17 08:09:54 +0000161
bellard8a40a182005-11-20 10:35:40 +0000162 found:
bellard8a40a182005-11-20 10:35:40 +0000163 /* we add the TB in the virtual pc hash table */
164 env->tb_jmp_cache[tb_jmp_cache_hash_func(pc)] = tb;
bellard8a40a182005-11-20 10:35:40 +0000165 return tb;
166}
167
168static inline TranslationBlock *tb_find_fast(void)
169{
170 TranslationBlock *tb;
171 target_ulong cs_base, pc;
aliguori6b917542008-11-18 19:46:41 +0000172 int flags;
bellard8a40a182005-11-20 10:35:40 +0000173
174 /* we record a subset of the CPU state. It will
175 always be the same before a given translated block
176 is executed. */
aliguori6b917542008-11-18 19:46:41 +0000177 cpu_get_tb_cpu_state(env, &pc, &cs_base, &flags);
bellardbce61842008-02-01 22:18:51 +0000178 tb = env->tb_jmp_cache[tb_jmp_cache_hash_func(pc)];
ths551bd272008-07-03 17:57:36 +0000179 if (unlikely(!tb || tb->pc != pc || tb->cs_base != cs_base ||
180 tb->flags != flags)) {
bellard8a40a182005-11-20 10:35:40 +0000181 tb = tb_find_slow(pc, cs_base, flags);
182 }
183 return tb;
184}
185
aliguoridde23672008-11-18 20:50:36 +0000186static CPUDebugExcpHandler *debug_excp_handler;
187
188CPUDebugExcpHandler *cpu_set_debug_excp_handler(CPUDebugExcpHandler *handler)
189{
190 CPUDebugExcpHandler *old_handler = debug_excp_handler;
191
192 debug_excp_handler = handler;
193 return old_handler;
194}
195
aliguori6e140f22008-11-18 20:37:55 +0000196static void cpu_handle_debug_exception(CPUState *env)
197{
198 CPUWatchpoint *wp;
199
200 if (!env->watchpoint_hit)
aliguoric0ce9982008-11-25 22:13:57 +0000201 TAILQ_FOREACH(wp, &env->watchpoints, entry)
aliguori6e140f22008-11-18 20:37:55 +0000202 wp->flags &= ~BP_WATCHPOINT_HIT;
aliguoridde23672008-11-18 20:50:36 +0000203
204 if (debug_excp_handler)
205 debug_excp_handler(env);
aliguori6e140f22008-11-18 20:37:55 +0000206}
207
bellard7d132992003-03-06 23:23:54 +0000208/* main execution loop */
209
bellarde4533c72003-06-15 19:51:39 +0000210int cpu_exec(CPUState *env1)
bellard7d132992003-03-06 23:23:54 +0000211{
pbrook1057eaa2007-02-04 13:37:44 +0000212#define DECLARE_HOST_REGS 1
213#include "hostregs_helper.h"
bellard8a40a182005-11-20 10:35:40 +0000214 int ret, interrupt_request;
bellard8a40a182005-11-20 10:35:40 +0000215 TranslationBlock *tb;
bellardc27004e2005-01-03 23:35:10 +0000216 uint8_t *tc_ptr;
pbrookd5975362008-06-07 20:50:51 +0000217 unsigned long next_tb;
bellard8c6939c2003-06-09 15:28:00 +0000218
thsbfed01f2007-06-03 17:44:37 +0000219 if (cpu_halted(env1) == EXCP_HALTED)
220 return EXCP_HALTED;
bellard5a1e3cf2005-11-23 21:02:53 +0000221
ths5fafdf22007-09-16 21:08:06 +0000222 cpu_single_env = env1;
bellard6a00d602005-11-21 23:25:50 +0000223
bellard7d132992003-03-06 23:23:54 +0000224 /* first we save global registers */
pbrook1057eaa2007-02-04 13:37:44 +0000225#define SAVE_HOST_REGS 1
226#include "hostregs_helper.h"
bellardc27004e2005-01-03 23:35:10 +0000227 env = env1;
bellarde4533c72003-06-15 19:51:39 +0000228
bellard0d1a29f2004-10-12 22:01:28 +0000229 env_to_regs();
thsecb644f2007-06-03 18:45:53 +0000230#if defined(TARGET_I386)
bellard9de5e442003-03-23 16:49:39 +0000231 /* put eflags in CPU temporary format */
bellardfc2b4c42003-03-29 16:52:44 +0000232 CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
233 DF = 1 - (2 * ((env->eflags >> 10) & 1));
bellard9de5e442003-03-23 16:49:39 +0000234 CC_OP = CC_OP_EFLAGS;
bellardfc2b4c42003-03-29 16:52:44 +0000235 env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
bellard93ac68b2003-09-30 20:57:29 +0000236#elif defined(TARGET_SPARC)
pbrooke6e59062006-10-22 00:18:54 +0000237#elif defined(TARGET_M68K)
238 env->cc_op = CC_OP_FLAGS;
239 env->cc_dest = env->sr & 0xf;
240 env->cc_x = (env->sr >> 4) & 1;
thsecb644f2007-06-03 18:45:53 +0000241#elif defined(TARGET_ALPHA)
242#elif defined(TARGET_ARM)
243#elif defined(TARGET_PPC)
bellard6af0bf92005-07-02 14:58:51 +0000244#elif defined(TARGET_MIPS)
bellardfdf9b3e2006-04-27 21:07:38 +0000245#elif defined(TARGET_SH4)
thsf1ccf902007-10-08 13:16:14 +0000246#elif defined(TARGET_CRIS)
bellardfdf9b3e2006-04-27 21:07:38 +0000247 /* XXXXX */
bellarde4533c72003-06-15 19:51:39 +0000248#else
249#error unsupported target CPU
250#endif
bellard3fb2ded2003-06-24 13:22:59 +0000251 env->exception_index = -1;
bellard9d27abd2003-05-10 13:13:54 +0000252
bellard7d132992003-03-06 23:23:54 +0000253 /* prepare setjmp context for exception handling */
bellard3fb2ded2003-06-24 13:22:59 +0000254 for(;;) {
255 if (setjmp(env->jmp_env) == 0) {
bellardee8b7022004-02-03 23:35:10 +0000256 env->current_tb = NULL;
bellard3fb2ded2003-06-24 13:22:59 +0000257 /* if an exception is pending, we execute it here */
258 if (env->exception_index >= 0) {
259 if (env->exception_index >= EXCP_INTERRUPT) {
260 /* exit request from the cpu execution loop */
261 ret = env->exception_index;
aliguori6e140f22008-11-18 20:37:55 +0000262 if (ret == EXCP_DEBUG)
263 cpu_handle_debug_exception(env);
bellard3fb2ded2003-06-24 13:22:59 +0000264 break;
aurel3272d239e2009-01-14 19:40:27 +0000265 } else {
266#if defined(CONFIG_USER_ONLY)
bellard3fb2ded2003-06-24 13:22:59 +0000267 /* if user mode only, we simulate a fake exception
ths9f083492006-12-07 18:28:42 +0000268 which will be handled outside the cpu execution
bellard3fb2ded2003-06-24 13:22:59 +0000269 loop */
bellard83479e72003-06-25 16:12:37 +0000270#if defined(TARGET_I386)
ths5fafdf22007-09-16 21:08:06 +0000271 do_interrupt_user(env->exception_index,
272 env->exception_is_int,
273 env->error_code,
bellard3fb2ded2003-06-24 13:22:59 +0000274 env->exception_next_eip);
bellardeba01622008-05-12 12:04:40 +0000275 /* successfully delivered */
276 env->old_exception = -1;
bellard83479e72003-06-25 16:12:37 +0000277#endif
bellard3fb2ded2003-06-24 13:22:59 +0000278 ret = env->exception_index;
279 break;
aurel3272d239e2009-01-14 19:40:27 +0000280#else
bellard83479e72003-06-25 16:12:37 +0000281#if defined(TARGET_I386)
bellard3fb2ded2003-06-24 13:22:59 +0000282 /* simulate a real cpu exception. On i386, it can
283 trigger new exceptions, but we do not handle
284 double or triple faults yet. */
ths5fafdf22007-09-16 21:08:06 +0000285 do_interrupt(env->exception_index,
286 env->exception_is_int,
287 env->error_code,
bellardd05e66d2003-08-20 21:34:35 +0000288 env->exception_next_eip, 0);
ths678dde12007-03-31 20:28:52 +0000289 /* successfully delivered */
290 env->old_exception = -1;
bellardce097762004-01-04 23:53:18 +0000291#elif defined(TARGET_PPC)
292 do_interrupt(env);
bellard6af0bf92005-07-02 14:58:51 +0000293#elif defined(TARGET_MIPS)
294 do_interrupt(env);
bellarde95c8d52004-09-30 22:22:08 +0000295#elif defined(TARGET_SPARC)
blueswir1f2bc7e72008-05-27 17:35:30 +0000296 do_interrupt(env);
bellardb5ff1b32005-11-26 10:38:39 +0000297#elif defined(TARGET_ARM)
298 do_interrupt(env);
bellardfdf9b3e2006-04-27 21:07:38 +0000299#elif defined(TARGET_SH4)
300 do_interrupt(env);
j_mayereddf68a2007-04-05 07:22:49 +0000301#elif defined(TARGET_ALPHA)
302 do_interrupt(env);
thsf1ccf902007-10-08 13:16:14 +0000303#elif defined(TARGET_CRIS)
304 do_interrupt(env);
pbrook06338792007-05-23 19:58:11 +0000305#elif defined(TARGET_M68K)
306 do_interrupt(0);
bellard83479e72003-06-25 16:12:37 +0000307#endif
aurel3272d239e2009-01-14 19:40:27 +0000308#endif
bellard3fb2ded2003-06-24 13:22:59 +0000309 }
310 env->exception_index = -1;
ths5fafdf22007-09-16 21:08:06 +0000311 }
bellard9df217a2005-02-10 22:05:51 +0000312#ifdef USE_KQEMU
aurel32be214e62009-03-06 21:48:00 +0000313 if (kqemu_is_ok(env) && env->interrupt_request == 0 && env->exit_request == 0) {
bellard9df217a2005-02-10 22:05:51 +0000314 int ret;
pbrooka7812ae2008-11-17 14:43:54 +0000315 env->eflags = env->eflags | helper_cc_compute_all(CC_OP) | (DF & DF_MASK);
bellard9df217a2005-02-10 22:05:51 +0000316 ret = kqemu_cpu_exec(env);
317 /* put eflags in CPU temporary format */
318 CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
319 DF = 1 - (2 * ((env->eflags >> 10) & 1));
320 CC_OP = CC_OP_EFLAGS;
321 env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
322 if (ret == 1) {
323 /* exception */
324 longjmp(env->jmp_env, 1);
325 } else if (ret == 2) {
326 /* softmmu execution needed */
327 } else {
aurel32be214e62009-03-06 21:48:00 +0000328 if (env->interrupt_request != 0 || env->exit_request != 0) {
bellard9df217a2005-02-10 22:05:51 +0000329 /* hardware interrupt will be executed just after */
330 } else {
331 /* otherwise, we restart */
332 longjmp(env->jmp_env, 1);
333 }
334 }
bellard9de5e442003-03-23 16:49:39 +0000335 }
bellard9df217a2005-02-10 22:05:51 +0000336#endif
337
aliguori7ba1e612008-11-05 16:04:33 +0000338 if (kvm_enabled()) {
aliguoribecfc392008-11-10 15:55:14 +0000339 kvm_cpu_exec(env);
340 longjmp(env->jmp_env, 1);
aliguori7ba1e612008-11-05 16:04:33 +0000341 }
342
blueswir1b5fc09a2008-05-04 06:38:18 +0000343 next_tb = 0; /* force lookup of first TB */
bellard3fb2ded2003-06-24 13:22:59 +0000344 for(;;) {
bellard68a79312003-06-30 13:12:32 +0000345 interrupt_request = env->interrupt_request;
malce1638bd2008-11-06 18:54:46 +0000346 if (unlikely(interrupt_request)) {
347 if (unlikely(env->singlestep_enabled & SSTEP_NOIRQ)) {
348 /* Mask out external interrupts for this step. */
349 interrupt_request &= ~(CPU_INTERRUPT_HARD |
350 CPU_INTERRUPT_FIQ |
351 CPU_INTERRUPT_SMI |
352 CPU_INTERRUPT_NMI);
353 }
pbrook6658ffb2007-03-16 23:58:11 +0000354 if (interrupt_request & CPU_INTERRUPT_DEBUG) {
355 env->interrupt_request &= ~CPU_INTERRUPT_DEBUG;
356 env->exception_index = EXCP_DEBUG;
357 cpu_loop_exit();
358 }
balroga90b7312007-05-01 01:28:01 +0000359#if defined(TARGET_ARM) || defined(TARGET_SPARC) || defined(TARGET_MIPS) || \
thsf1ccf902007-10-08 13:16:14 +0000360 defined(TARGET_PPC) || defined(TARGET_ALPHA) || defined(TARGET_CRIS)
balroga90b7312007-05-01 01:28:01 +0000361 if (interrupt_request & CPU_INTERRUPT_HALT) {
362 env->interrupt_request &= ~CPU_INTERRUPT_HALT;
363 env->halted = 1;
364 env->exception_index = EXCP_HLT;
365 cpu_loop_exit();
366 }
367#endif
bellard68a79312003-06-30 13:12:32 +0000368#if defined(TARGET_I386)
bellarddb620f42008-06-04 17:02:19 +0000369 if (env->hflags2 & HF2_GIF_MASK) {
370 if ((interrupt_request & CPU_INTERRUPT_SMI) &&
371 !(env->hflags & HF_SMM_MASK)) {
372 svm_check_intercept(SVM_EXIT_SMI);
373 env->interrupt_request &= ~CPU_INTERRUPT_SMI;
374 do_smm_enter();
375 next_tb = 0;
376 } else if ((interrupt_request & CPU_INTERRUPT_NMI) &&
377 !(env->hflags2 & HF2_NMI_MASK)) {
378 env->interrupt_request &= ~CPU_INTERRUPT_NMI;
379 env->hflags2 |= HF2_NMI_MASK;
380 do_interrupt(EXCP02_NMI, 0, 0, 0, 1);
381 next_tb = 0;
382 } else if ((interrupt_request & CPU_INTERRUPT_HARD) &&
383 (((env->hflags2 & HF2_VINTR_MASK) &&
384 (env->hflags2 & HF2_HIF_MASK)) ||
385 (!(env->hflags2 & HF2_VINTR_MASK) &&
386 (env->eflags & IF_MASK &&
387 !(env->hflags & HF_INHIBIT_IRQ_MASK))))) {
388 int intno;
389 svm_check_intercept(SVM_EXIT_INTR);
390 env->interrupt_request &= ~(CPU_INTERRUPT_HARD | CPU_INTERRUPT_VIRQ);
391 intno = cpu_get_pic_interrupt(env);
aliguori93fcfe32009-01-15 22:34:14 +0000392 qemu_log_mask(CPU_LOG_TB_IN_ASM, "Servicing hardware INT=0x%02x\n", intno);
bellarddb620f42008-06-04 17:02:19 +0000393 do_interrupt(intno, 0, 0, 0, 1);
394 /* ensure that no TB jump will be modified as
395 the program flow was changed */
396 next_tb = 0;
ths0573fbf2007-09-23 15:28:04 +0000397#if !defined(CONFIG_USER_ONLY)
bellarddb620f42008-06-04 17:02:19 +0000398 } else if ((interrupt_request & CPU_INTERRUPT_VIRQ) &&
399 (env->eflags & IF_MASK) &&
400 !(env->hflags & HF_INHIBIT_IRQ_MASK)) {
401 int intno;
402 /* FIXME: this should respect TPR */
403 svm_check_intercept(SVM_EXIT_VINTR);
bellarddb620f42008-06-04 17:02:19 +0000404 intno = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_vector));
aliguori93fcfe32009-01-15 22:34:14 +0000405 qemu_log_mask(CPU_LOG_TB_IN_ASM, "Servicing virtual hardware INT=0x%02x\n", intno);
bellarddb620f42008-06-04 17:02:19 +0000406 do_interrupt(intno, 0, 0, 0, 1);
aurel32d40c54d2008-12-13 12:33:02 +0000407 env->interrupt_request &= ~CPU_INTERRUPT_VIRQ;
bellarddb620f42008-06-04 17:02:19 +0000408 next_tb = 0;
ths0573fbf2007-09-23 15:28:04 +0000409#endif
bellarddb620f42008-06-04 17:02:19 +0000410 }
bellard68a79312003-06-30 13:12:32 +0000411 }
bellardce097762004-01-04 23:53:18 +0000412#elif defined(TARGET_PPC)
bellard9fddaa02004-05-21 12:59:32 +0000413#if 0
414 if ((interrupt_request & CPU_INTERRUPT_RESET)) {
415 cpu_ppc_reset(env);
416 }
417#endif
j_mayer47103572007-03-30 09:38:04 +0000418 if (interrupt_request & CPU_INTERRUPT_HARD) {
j_mayere9df0142007-04-09 22:45:36 +0000419 ppc_hw_interrupt(env);
420 if (env->pending_interrupts == 0)
421 env->interrupt_request &= ~CPU_INTERRUPT_HARD;
blueswir1b5fc09a2008-05-04 06:38:18 +0000422 next_tb = 0;
bellardce097762004-01-04 23:53:18 +0000423 }
bellard6af0bf92005-07-02 14:58:51 +0000424#elif defined(TARGET_MIPS)
425 if ((interrupt_request & CPU_INTERRUPT_HARD) &&
ths24c7b0e2007-03-30 16:44:54 +0000426 (env->CP0_Status & env->CP0_Cause & CP0Ca_IP_mask) &&
bellard6af0bf92005-07-02 14:58:51 +0000427 (env->CP0_Status & (1 << CP0St_IE)) &&
ths24c7b0e2007-03-30 16:44:54 +0000428 !(env->CP0_Status & (1 << CP0St_EXL)) &&
429 !(env->CP0_Status & (1 << CP0St_ERL)) &&
bellard6af0bf92005-07-02 14:58:51 +0000430 !(env->hflags & MIPS_HFLAG_DM)) {
431 /* Raise it */
432 env->exception_index = EXCP_EXT_INTERRUPT;
433 env->error_code = 0;
434 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000435 next_tb = 0;
bellard6af0bf92005-07-02 14:58:51 +0000436 }
bellarde95c8d52004-09-30 22:22:08 +0000437#elif defined(TARGET_SPARC)
bellard66321a12005-04-06 20:47:48 +0000438 if ((interrupt_request & CPU_INTERRUPT_HARD) &&
439 (env->psret != 0)) {
440 int pil = env->interrupt_index & 15;
441 int type = env->interrupt_index & 0xf0;
442
443 if (((type == TT_EXTINT) &&
444 (pil == 15 || pil > env->psrpil)) ||
445 type != TT_EXTINT) {
446 env->interrupt_request &= ~CPU_INTERRUPT_HARD;
blueswir1f2bc7e72008-05-27 17:35:30 +0000447 env->exception_index = env->interrupt_index;
448 do_interrupt(env);
bellard66321a12005-04-06 20:47:48 +0000449 env->interrupt_index = 0;
blueswir1327ac2e2007-08-04 10:50:30 +0000450#if !defined(TARGET_SPARC64) && !defined(CONFIG_USER_ONLY)
451 cpu_check_irqs(env);
452#endif
blueswir1b5fc09a2008-05-04 06:38:18 +0000453 next_tb = 0;
bellard66321a12005-04-06 20:47:48 +0000454 }
bellarde95c8d52004-09-30 22:22:08 +0000455 } else if (interrupt_request & CPU_INTERRUPT_TIMER) {
456 //do_interrupt(0, 0, 0, 0, 0);
457 env->interrupt_request &= ~CPU_INTERRUPT_TIMER;
balroga90b7312007-05-01 01:28:01 +0000458 }
bellardb5ff1b32005-11-26 10:38:39 +0000459#elif defined(TARGET_ARM)
460 if (interrupt_request & CPU_INTERRUPT_FIQ
461 && !(env->uncached_cpsr & CPSR_F)) {
462 env->exception_index = EXCP_FIQ;
463 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000464 next_tb = 0;
bellardb5ff1b32005-11-26 10:38:39 +0000465 }
pbrook9ee6e8b2007-11-11 00:04:49 +0000466 /* ARMv7-M interrupt return works by loading a magic value
467 into the PC. On real hardware the load causes the
468 return to occur. The qemu implementation performs the
469 jump normally, then does the exception return when the
470 CPU tries to execute code at the magic address.
471 This will cause the magic PC value to be pushed to
472 the stack if an interrupt occured at the wrong time.
473 We avoid this by disabling interrupts when
474 pc contains a magic address. */
bellardb5ff1b32005-11-26 10:38:39 +0000475 if (interrupt_request & CPU_INTERRUPT_HARD
pbrook9ee6e8b2007-11-11 00:04:49 +0000476 && ((IS_M(env) && env->regs[15] < 0xfffffff0)
477 || !(env->uncached_cpsr & CPSR_I))) {
bellardb5ff1b32005-11-26 10:38:39 +0000478 env->exception_index = EXCP_IRQ;
479 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000480 next_tb = 0;
bellardb5ff1b32005-11-26 10:38:39 +0000481 }
bellardfdf9b3e2006-04-27 21:07:38 +0000482#elif defined(TARGET_SH4)
thse96e2042007-12-02 06:18:24 +0000483 if (interrupt_request & CPU_INTERRUPT_HARD) {
484 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000485 next_tb = 0;
thse96e2042007-12-02 06:18:24 +0000486 }
j_mayereddf68a2007-04-05 07:22:49 +0000487#elif defined(TARGET_ALPHA)
488 if (interrupt_request & CPU_INTERRUPT_HARD) {
489 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000490 next_tb = 0;
j_mayereddf68a2007-04-05 07:22:49 +0000491 }
thsf1ccf902007-10-08 13:16:14 +0000492#elif defined(TARGET_CRIS)
edgar_igl1b1a38b2008-06-09 23:18:06 +0000493 if (interrupt_request & CPU_INTERRUPT_HARD
494 && (env->pregs[PR_CCS] & I_FLAG)) {
495 env->exception_index = EXCP_IRQ;
496 do_interrupt(env);
497 next_tb = 0;
498 }
499 if (interrupt_request & CPU_INTERRUPT_NMI
500 && (env->pregs[PR_CCS] & M_FLAG)) {
501 env->exception_index = EXCP_NMI;
thsf1ccf902007-10-08 13:16:14 +0000502 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000503 next_tb = 0;
thsf1ccf902007-10-08 13:16:14 +0000504 }
pbrook06338792007-05-23 19:58:11 +0000505#elif defined(TARGET_M68K)
506 if (interrupt_request & CPU_INTERRUPT_HARD
507 && ((env->sr & SR_I) >> SR_I_SHIFT)
508 < env->pending_level) {
509 /* Real hardware gets the interrupt vector via an
510 IACK cycle at this point. Current emulated
511 hardware doesn't rely on this, so we
512 provide/save the vector when the interrupt is
513 first signalled. */
514 env->exception_index = env->pending_vector;
515 do_interrupt(1);
blueswir1b5fc09a2008-05-04 06:38:18 +0000516 next_tb = 0;
pbrook06338792007-05-23 19:58:11 +0000517 }
bellard68a79312003-06-30 13:12:32 +0000518#endif
bellard9d050952006-05-22 22:03:52 +0000519 /* Don't use the cached interupt_request value,
520 do_interrupt may have updated the EXITTB flag. */
bellardb5ff1b32005-11-26 10:38:39 +0000521 if (env->interrupt_request & CPU_INTERRUPT_EXITTB) {
bellardbf3e8bf2004-02-16 21:58:54 +0000522 env->interrupt_request &= ~CPU_INTERRUPT_EXITTB;
523 /* ensure that no TB jump will be modified as
524 the program flow was changed */
blueswir1b5fc09a2008-05-04 06:38:18 +0000525 next_tb = 0;
bellardbf3e8bf2004-02-16 21:58:54 +0000526 }
aurel32be214e62009-03-06 21:48:00 +0000527 }
528 if (unlikely(env->exit_request)) {
529 env->exit_request = 0;
530 env->exception_index = EXCP_INTERRUPT;
531 cpu_loop_exit();
bellard3fb2ded2003-06-24 13:22:59 +0000532 }
533#ifdef DEBUG_EXEC
aliguori8fec2b82009-01-15 22:36:53 +0000534 if (qemu_loglevel_mask(CPU_LOG_TB_CPU)) {
bellard3fb2ded2003-06-24 13:22:59 +0000535 /* restore flags in standard format */
thsecb644f2007-06-03 18:45:53 +0000536 regs_to_env();
537#if defined(TARGET_I386)
pbrooka7812ae2008-11-17 14:43:54 +0000538 env->eflags = env->eflags | helper_cc_compute_all(CC_OP) | (DF & DF_MASK);
aliguori93fcfe32009-01-15 22:34:14 +0000539 log_cpu_state(env, X86_DUMP_CCOP);
bellard3fb2ded2003-06-24 13:22:59 +0000540 env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
bellarde4533c72003-06-15 19:51:39 +0000541#elif defined(TARGET_ARM)
aliguori93fcfe32009-01-15 22:34:14 +0000542 log_cpu_state(env, 0);
bellard93ac68b2003-09-30 20:57:29 +0000543#elif defined(TARGET_SPARC)
aliguori93fcfe32009-01-15 22:34:14 +0000544 log_cpu_state(env, 0);
bellard67867302003-11-23 17:05:30 +0000545#elif defined(TARGET_PPC)
aliguori93fcfe32009-01-15 22:34:14 +0000546 log_cpu_state(env, 0);
pbrooke6e59062006-10-22 00:18:54 +0000547#elif defined(TARGET_M68K)
548 cpu_m68k_flush_flags(env, env->cc_op);
549 env->cc_op = CC_OP_FLAGS;
550 env->sr = (env->sr & 0xffe0)
551 | env->cc_dest | (env->cc_x << 4);
aliguori93fcfe32009-01-15 22:34:14 +0000552 log_cpu_state(env, 0);
bellard6af0bf92005-07-02 14:58:51 +0000553#elif defined(TARGET_MIPS)
aliguori93fcfe32009-01-15 22:34:14 +0000554 log_cpu_state(env, 0);
bellardfdf9b3e2006-04-27 21:07:38 +0000555#elif defined(TARGET_SH4)
aliguori93fcfe32009-01-15 22:34:14 +0000556 log_cpu_state(env, 0);
j_mayereddf68a2007-04-05 07:22:49 +0000557#elif defined(TARGET_ALPHA)
aliguori93fcfe32009-01-15 22:34:14 +0000558 log_cpu_state(env, 0);
thsf1ccf902007-10-08 13:16:14 +0000559#elif defined(TARGET_CRIS)
aliguori93fcfe32009-01-15 22:34:14 +0000560 log_cpu_state(env, 0);
bellarde4533c72003-06-15 19:51:39 +0000561#else
ths5fafdf22007-09-16 21:08:06 +0000562#error unsupported target CPU
bellarde4533c72003-06-15 19:51:39 +0000563#endif
bellard3fb2ded2003-06-24 13:22:59 +0000564 }
bellard7d132992003-03-06 23:23:54 +0000565#endif
pbrookd5975362008-06-07 20:50:51 +0000566 spin_lock(&tb_lock);
bellard8a40a182005-11-20 10:35:40 +0000567 tb = tb_find_fast();
pbrookd5975362008-06-07 20:50:51 +0000568 /* Note: we do it here to avoid a gcc bug on Mac OS X when
569 doing it in tb_find_slow */
570 if (tb_invalidated_flag) {
571 /* as some TB could have been invalidated because
572 of memory exceptions while generating the code, we
573 must recompute the hash index here */
574 next_tb = 0;
pbrook2e70f6e2008-06-29 01:03:05 +0000575 tb_invalidated_flag = 0;
pbrookd5975362008-06-07 20:50:51 +0000576 }
bellard9d27abd2003-05-10 13:13:54 +0000577#ifdef DEBUG_EXEC
aliguori93fcfe32009-01-15 22:34:14 +0000578 qemu_log_mask(CPU_LOG_EXEC, "Trace 0x%08lx [" TARGET_FMT_lx "] %s\n",
579 (long)tb->tc_ptr, tb->pc,
580 lookup_symbol(tb->pc));
bellard9d27abd2003-05-10 13:13:54 +0000581#endif
bellard8a40a182005-11-20 10:35:40 +0000582 /* see if we can patch the calling TB. When the TB
583 spans two pages, we cannot safely do a direct
584 jump. */
bellardc27004e2005-01-03 23:35:10 +0000585 {
blueswir1b5fc09a2008-05-04 06:38:18 +0000586 if (next_tb != 0 &&
blueswir14d7a0882008-05-10 10:14:22 +0000587#ifdef USE_KQEMU
bellardf32fc642006-02-08 22:43:39 +0000588 (env->kqemu_enabled != 2) &&
589#endif
bellardec6338b2007-11-08 14:25:03 +0000590 tb->page_addr[1] == -1) {
blueswir1b5fc09a2008-05-04 06:38:18 +0000591 tb_add_jump((TranslationBlock *)(next_tb & ~3), next_tb & 3, tb);
bellard3fb2ded2003-06-24 13:22:59 +0000592 }
bellardc27004e2005-01-03 23:35:10 +0000593 }
pbrookd5975362008-06-07 20:50:51 +0000594 spin_unlock(&tb_lock);
bellard83479e72003-06-25 16:12:37 +0000595 env->current_tb = tb;
malc55e8b852008-11-04 14:18:13 +0000596
597 /* cpu_interrupt might be called while translating the
598 TB, but before it is linked into a potentially
599 infinite loop and becomes env->current_tb. Avoid
600 starting execution if there is a pending interrupt. */
aurel32be214e62009-03-06 21:48:00 +0000601 if (unlikely (env->exit_request))
malc55e8b852008-11-04 14:18:13 +0000602 env->current_tb = NULL;
603
pbrook2e70f6e2008-06-29 01:03:05 +0000604 while (env->current_tb) {
605 tc_ptr = tb->tc_ptr;
bellard3fb2ded2003-06-24 13:22:59 +0000606 /* execute the generated code */
blueswir1572a9d42008-05-17 07:38:10 +0000607#if defined(__sparc__) && !defined(HOST_SOLARIS)
608#undef env
pbrook2e70f6e2008-06-29 01:03:05 +0000609 env = cpu_single_env;
blueswir1572a9d42008-05-17 07:38:10 +0000610#define env cpu_single_env
611#endif
pbrook2e70f6e2008-06-29 01:03:05 +0000612 next_tb = tcg_qemu_tb_exec(tc_ptr);
613 env->current_tb = NULL;
614 if ((next_tb & 3) == 2) {
thsbf20dc02008-06-30 17:22:19 +0000615 /* Instruction counter expired. */
pbrook2e70f6e2008-06-29 01:03:05 +0000616 int insns_left;
617 tb = (TranslationBlock *)(long)(next_tb & ~3);
618 /* Restore PC. */
aliguori622ed362008-11-18 19:36:03 +0000619 cpu_pc_from_tb(env, tb);
pbrook2e70f6e2008-06-29 01:03:05 +0000620 insns_left = env->icount_decr.u32;
621 if (env->icount_extra && insns_left >= 0) {
622 /* Refill decrementer and continue execution. */
623 env->icount_extra += insns_left;
624 if (env->icount_extra > 0xffff) {
625 insns_left = 0xffff;
626 } else {
627 insns_left = env->icount_extra;
628 }
629 env->icount_extra -= insns_left;
630 env->icount_decr.u16.low = insns_left;
631 } else {
632 if (insns_left > 0) {
633 /* Execute remaining instructions. */
634 cpu_exec_nocache(insns_left, tb);
635 }
636 env->exception_index = EXCP_INTERRUPT;
637 next_tb = 0;
638 cpu_loop_exit();
639 }
640 }
641 }
bellard4cbf74b2003-08-10 21:48:43 +0000642 /* reset soft MMU for next block (it can currently
643 only be set by a memory fault) */
bellardf32fc642006-02-08 22:43:39 +0000644#if defined(USE_KQEMU)
645#define MIN_CYCLE_BEFORE_SWITCH (100 * 1000)
646 if (kqemu_is_ok(env) &&
647 (cpu_get_time_fast() - env->last_io_time) >= MIN_CYCLE_BEFORE_SWITCH) {
648 cpu_loop_exit();
649 }
650#endif
ths50a518e2007-06-03 18:52:15 +0000651 } /* for(;;) */
bellard3fb2ded2003-06-24 13:22:59 +0000652 } else {
bellard0d1a29f2004-10-12 22:01:28 +0000653 env_to_regs();
bellard7d132992003-03-06 23:23:54 +0000654 }
bellard3fb2ded2003-06-24 13:22:59 +0000655 } /* for(;;) */
656
bellard7d132992003-03-06 23:23:54 +0000657
bellarde4533c72003-06-15 19:51:39 +0000658#if defined(TARGET_I386)
bellard9de5e442003-03-23 16:49:39 +0000659 /* restore flags in standard format */
pbrooka7812ae2008-11-17 14:43:54 +0000660 env->eflags = env->eflags | helper_cc_compute_all(CC_OP) | (DF & DF_MASK);
bellarde4533c72003-06-15 19:51:39 +0000661#elif defined(TARGET_ARM)
bellardb7bcbe92005-02-22 19:27:29 +0000662 /* XXX: Save/restore host fpu exception state?. */
bellard93ac68b2003-09-30 20:57:29 +0000663#elif defined(TARGET_SPARC)
bellard67867302003-11-23 17:05:30 +0000664#elif defined(TARGET_PPC)
pbrooke6e59062006-10-22 00:18:54 +0000665#elif defined(TARGET_M68K)
666 cpu_m68k_flush_flags(env, env->cc_op);
667 env->cc_op = CC_OP_FLAGS;
668 env->sr = (env->sr & 0xffe0)
669 | env->cc_dest | (env->cc_x << 4);
bellard6af0bf92005-07-02 14:58:51 +0000670#elif defined(TARGET_MIPS)
bellardfdf9b3e2006-04-27 21:07:38 +0000671#elif defined(TARGET_SH4)
j_mayereddf68a2007-04-05 07:22:49 +0000672#elif defined(TARGET_ALPHA)
thsf1ccf902007-10-08 13:16:14 +0000673#elif defined(TARGET_CRIS)
bellardfdf9b3e2006-04-27 21:07:38 +0000674 /* XXXXX */
bellarde4533c72003-06-15 19:51:39 +0000675#else
676#error unsupported target CPU
677#endif
pbrook1057eaa2007-02-04 13:37:44 +0000678
679 /* restore global registers */
pbrook1057eaa2007-02-04 13:37:44 +0000680#include "hostregs_helper.h"
681
bellard6a00d602005-11-21 23:25:50 +0000682 /* fail safe : never use cpu_single_env outside cpu_exec() */
ths5fafdf22007-09-16 21:08:06 +0000683 cpu_single_env = NULL;
bellard7d132992003-03-06 23:23:54 +0000684 return ret;
685}
bellard6dbad632003-03-16 18:05:05 +0000686
bellardfbf9eeb2004-04-25 21:21:33 +0000687/* must only be called from the generated code as an exception can be
688 generated */
689void tb_invalidate_page_range(target_ulong start, target_ulong end)
690{
bellarddc5d0b32004-06-22 18:43:30 +0000691 /* XXX: cannot enable it yet because it yields to MMU exception
692 where NIP != read address on PowerPC */
693#if 0
bellardfbf9eeb2004-04-25 21:21:33 +0000694 target_ulong phys_addr;
695 phys_addr = get_phys_addr_code(env, start);
696 tb_invalidate_phys_page_range(phys_addr, phys_addr + end - start, 0);
bellarddc5d0b32004-06-22 18:43:30 +0000697#endif
bellardfbf9eeb2004-04-25 21:21:33 +0000698}
699
bellard1a18c712003-10-30 01:07:51 +0000700#if defined(TARGET_I386) && defined(CONFIG_USER_ONLY)
bellarde4533c72003-06-15 19:51:39 +0000701
bellard6dbad632003-03-16 18:05:05 +0000702void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector)
703{
704 CPUX86State *saved_env;
705
706 saved_env = env;
707 env = s;
bellarda412ac52003-07-26 18:01:40 +0000708 if (!(env->cr[0] & CR0_PE_MASK) || (env->eflags & VM_MASK)) {
bellarda513fe12003-05-27 23:29:48 +0000709 selector &= 0xffff;
ths5fafdf22007-09-16 21:08:06 +0000710 cpu_x86_load_seg_cache(env, seg_reg, selector,
bellardc27004e2005-01-03 23:35:10 +0000711 (selector << 4), 0xffff, 0);
bellarda513fe12003-05-27 23:29:48 +0000712 } else {
bellard5d975592008-05-12 22:05:33 +0000713 helper_load_seg(seg_reg, selector);
bellarda513fe12003-05-27 23:29:48 +0000714 }
bellard6dbad632003-03-16 18:05:05 +0000715 env = saved_env;
716}
bellard9de5e442003-03-23 16:49:39 +0000717
bellard6f12a2a2007-11-11 22:16:56 +0000718void cpu_x86_fsave(CPUX86State *s, target_ulong ptr, int data32)
bellardd0a1ffc2003-05-29 20:04:28 +0000719{
720 CPUX86State *saved_env;
721
722 saved_env = env;
723 env = s;
ths3b46e622007-09-17 08:09:54 +0000724
bellard6f12a2a2007-11-11 22:16:56 +0000725 helper_fsave(ptr, data32);
bellardd0a1ffc2003-05-29 20:04:28 +0000726
727 env = saved_env;
728}
729
bellard6f12a2a2007-11-11 22:16:56 +0000730void cpu_x86_frstor(CPUX86State *s, target_ulong ptr, int data32)
bellardd0a1ffc2003-05-29 20:04:28 +0000731{
732 CPUX86State *saved_env;
733
734 saved_env = env;
735 env = s;
ths3b46e622007-09-17 08:09:54 +0000736
bellard6f12a2a2007-11-11 22:16:56 +0000737 helper_frstor(ptr, data32);
bellardd0a1ffc2003-05-29 20:04:28 +0000738
739 env = saved_env;
740}
741
bellarde4533c72003-06-15 19:51:39 +0000742#endif /* TARGET_I386 */
743
bellard67b915a2004-03-31 23:37:16 +0000744#if !defined(CONFIG_SOFTMMU)
745
bellard3fb2ded2003-06-24 13:22:59 +0000746#if defined(TARGET_I386)
747
bellardb56dad12003-05-08 15:38:04 +0000748/* 'pc' is the host PC at which the exception was raised. 'address' is
bellardfd6ce8f2003-05-14 19:00:11 +0000749 the effective address of the memory exception. 'is_write' is 1 if a
750 write caused the exception and otherwise 0'. 'old_set' is the
751 signal set which should be restored */
bellard2b413142003-05-14 23:01:10 +0000752static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
ths5fafdf22007-09-16 21:08:06 +0000753 int is_write, sigset_t *old_set,
bellardbf3e8bf2004-02-16 21:58:54 +0000754 void *puc)
bellard9de5e442003-03-23 16:49:39 +0000755{
bellarda513fe12003-05-27 23:29:48 +0000756 TranslationBlock *tb;
757 int ret;
bellard68a79312003-06-30 13:12:32 +0000758
bellard83479e72003-06-25 16:12:37 +0000759 if (cpu_single_env)
760 env = cpu_single_env; /* XXX: find a correct solution for multithread */
bellardfd6ce8f2003-05-14 19:00:11 +0000761#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000762 qemu_printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellardbf3e8bf2004-02-16 21:58:54 +0000763 pc, address, is_write, *(unsigned long *)old_set);
bellard9de5e442003-03-23 16:49:39 +0000764#endif
bellard25eb4482003-05-14 21:50:54 +0000765 /* XXX: locking issue */
pbrook53a59602006-03-25 19:31:22 +0000766 if (is_write && page_unprotect(h2g(address), pc, puc)) {
bellardfd6ce8f2003-05-14 19:00:11 +0000767 return 1;
768 }
bellardfbf9eeb2004-04-25 21:21:33 +0000769
bellard3fb2ded2003-06-24 13:22:59 +0000770 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +0000771 ret = cpu_x86_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellard3fb2ded2003-06-24 13:22:59 +0000772 if (ret < 0)
773 return 0; /* not an MMU fault */
774 if (ret == 0)
775 return 1; /* the MMU fault was handled without causing real CPU fault */
776 /* now we have a real cpu fault */
bellarda513fe12003-05-27 23:29:48 +0000777 tb = tb_find_pc(pc);
778 if (tb) {
bellard9de5e442003-03-23 16:49:39 +0000779 /* the PC is inside the translated code. It means that we have
780 a virtual CPU fault */
bellardbf3e8bf2004-02-16 21:58:54 +0000781 cpu_restore_state(tb, env, pc, puc);
bellard3fb2ded2003-06-24 13:22:59 +0000782 }
bellard4cbf74b2003-08-10 21:48:43 +0000783 if (ret == 1) {
bellard3fb2ded2003-06-24 13:22:59 +0000784#if 0
ths5fafdf22007-09-16 21:08:06 +0000785 printf("PF exception: EIP=0x%08x CR2=0x%08x error=0x%x\n",
bellard4cbf74b2003-08-10 21:48:43 +0000786 env->eip, env->cr[2], env->error_code);
bellard3fb2ded2003-06-24 13:22:59 +0000787#endif
bellard4cbf74b2003-08-10 21:48:43 +0000788 /* we restore the process signal mask as the sigreturn should
789 do it (XXX: use sigsetjmp) */
790 sigprocmask(SIG_SETMASK, old_set, NULL);
bellard54ca9092005-12-04 18:46:06 +0000791 raise_exception_err(env->exception_index, env->error_code);
bellard4cbf74b2003-08-10 21:48:43 +0000792 } else {
793 /* activate soft MMU for this block */
bellard3f337312003-08-20 23:02:09 +0000794 env->hflags |= HF_SOFTMMU_MASK;
bellardfbf9eeb2004-04-25 21:21:33 +0000795 cpu_resume_from_signal(env, puc);
bellard4cbf74b2003-08-10 21:48:43 +0000796 }
bellard3fb2ded2003-06-24 13:22:59 +0000797 /* never comes here */
798 return 1;
799}
800
bellarde4533c72003-06-15 19:51:39 +0000801#elif defined(TARGET_ARM)
bellard3fb2ded2003-06-24 13:22:59 +0000802static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
bellardbf3e8bf2004-02-16 21:58:54 +0000803 int is_write, sigset_t *old_set,
804 void *puc)
bellard3fb2ded2003-06-24 13:22:59 +0000805{
bellard68016c62005-02-07 23:12:27 +0000806 TranslationBlock *tb;
807 int ret;
808
809 if (cpu_single_env)
810 env = cpu_single_env; /* XXX: find a correct solution for multithread */
811#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000812 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellard68016c62005-02-07 23:12:27 +0000813 pc, address, is_write, *(unsigned long *)old_set);
814#endif
bellard9f0777e2005-02-02 20:42:01 +0000815 /* XXX: locking issue */
pbrook53a59602006-03-25 19:31:22 +0000816 if (is_write && page_unprotect(h2g(address), pc, puc)) {
bellard9f0777e2005-02-02 20:42:01 +0000817 return 1;
818 }
bellard68016c62005-02-07 23:12:27 +0000819 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +0000820 ret = cpu_arm_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellard68016c62005-02-07 23:12:27 +0000821 if (ret < 0)
822 return 0; /* not an MMU fault */
823 if (ret == 0)
824 return 1; /* the MMU fault was handled without causing real CPU fault */
825 /* now we have a real cpu fault */
826 tb = tb_find_pc(pc);
827 if (tb) {
828 /* the PC is inside the translated code. It means that we have
829 a virtual CPU fault */
830 cpu_restore_state(tb, env, pc, puc);
831 }
832 /* we restore the process signal mask as the sigreturn should
833 do it (XXX: use sigsetjmp) */
834 sigprocmask(SIG_SETMASK, old_set, NULL);
835 cpu_loop_exit();
aurel32968c74d2008-04-11 04:55:17 +0000836 /* never comes here */
837 return 1;
bellard3fb2ded2003-06-24 13:22:59 +0000838}
bellard93ac68b2003-09-30 20:57:29 +0000839#elif defined(TARGET_SPARC)
840static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
bellardbf3e8bf2004-02-16 21:58:54 +0000841 int is_write, sigset_t *old_set,
842 void *puc)
bellard93ac68b2003-09-30 20:57:29 +0000843{
bellard68016c62005-02-07 23:12:27 +0000844 TranslationBlock *tb;
845 int ret;
846
847 if (cpu_single_env)
848 env = cpu_single_env; /* XXX: find a correct solution for multithread */
849#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000850 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellard68016c62005-02-07 23:12:27 +0000851 pc, address, is_write, *(unsigned long *)old_set);
852#endif
bellardb453b702004-01-04 15:45:21 +0000853 /* XXX: locking issue */
pbrook53a59602006-03-25 19:31:22 +0000854 if (is_write && page_unprotect(h2g(address), pc, puc)) {
bellardb453b702004-01-04 15:45:21 +0000855 return 1;
856 }
bellard68016c62005-02-07 23:12:27 +0000857 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +0000858 ret = cpu_sparc_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellard68016c62005-02-07 23:12:27 +0000859 if (ret < 0)
860 return 0; /* not an MMU fault */
861 if (ret == 0)
862 return 1; /* the MMU fault was handled without causing real CPU fault */
863 /* now we have a real cpu fault */
864 tb = tb_find_pc(pc);
865 if (tb) {
866 /* the PC is inside the translated code. It means that we have
867 a virtual CPU fault */
868 cpu_restore_state(tb, env, pc, puc);
869 }
870 /* we restore the process signal mask as the sigreturn should
871 do it (XXX: use sigsetjmp) */
872 sigprocmask(SIG_SETMASK, old_set, NULL);
873 cpu_loop_exit();
aurel32968c74d2008-04-11 04:55:17 +0000874 /* never comes here */
875 return 1;
bellard93ac68b2003-09-30 20:57:29 +0000876}
bellard67867302003-11-23 17:05:30 +0000877#elif defined (TARGET_PPC)
878static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
bellardbf3e8bf2004-02-16 21:58:54 +0000879 int is_write, sigset_t *old_set,
880 void *puc)
bellard67867302003-11-23 17:05:30 +0000881{
882 TranslationBlock *tb;
bellardce097762004-01-04 23:53:18 +0000883 int ret;
ths3b46e622007-09-17 08:09:54 +0000884
bellard67867302003-11-23 17:05:30 +0000885 if (cpu_single_env)
886 env = cpu_single_env; /* XXX: find a correct solution for multithread */
bellard67867302003-11-23 17:05:30 +0000887#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000888 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellard67867302003-11-23 17:05:30 +0000889 pc, address, is_write, *(unsigned long *)old_set);
890#endif
891 /* XXX: locking issue */
pbrook53a59602006-03-25 19:31:22 +0000892 if (is_write && page_unprotect(h2g(address), pc, puc)) {
bellard67867302003-11-23 17:05:30 +0000893 return 1;
894 }
895
bellardce097762004-01-04 23:53:18 +0000896 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +0000897 ret = cpu_ppc_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellardce097762004-01-04 23:53:18 +0000898 if (ret < 0)
899 return 0; /* not an MMU fault */
900 if (ret == 0)
901 return 1; /* the MMU fault was handled without causing real CPU fault */
902
bellard67867302003-11-23 17:05:30 +0000903 /* now we have a real cpu fault */
904 tb = tb_find_pc(pc);
905 if (tb) {
906 /* the PC is inside the translated code. It means that we have
907 a virtual CPU fault */
bellardbf3e8bf2004-02-16 21:58:54 +0000908 cpu_restore_state(tb, env, pc, puc);
bellard67867302003-11-23 17:05:30 +0000909 }
bellardce097762004-01-04 23:53:18 +0000910 if (ret == 1) {
bellard67867302003-11-23 17:05:30 +0000911#if 0
ths5fafdf22007-09-16 21:08:06 +0000912 printf("PF exception: NIP=0x%08x error=0x%x %p\n",
bellardce097762004-01-04 23:53:18 +0000913 env->nip, env->error_code, tb);
bellard67867302003-11-23 17:05:30 +0000914#endif
915 /* we restore the process signal mask as the sigreturn should
916 do it (XXX: use sigsetjmp) */
bellardbf3e8bf2004-02-16 21:58:54 +0000917 sigprocmask(SIG_SETMASK, old_set, NULL);
aurel32e06fcd72008-12-11 22:42:14 +0000918 cpu_loop_exit();
bellardce097762004-01-04 23:53:18 +0000919 } else {
920 /* activate soft MMU for this block */
bellardfbf9eeb2004-04-25 21:21:33 +0000921 cpu_resume_from_signal(env, puc);
bellardce097762004-01-04 23:53:18 +0000922 }
bellard67867302003-11-23 17:05:30 +0000923 /* never comes here */
924 return 1;
925}
bellard6af0bf92005-07-02 14:58:51 +0000926
pbrooke6e59062006-10-22 00:18:54 +0000927#elif defined(TARGET_M68K)
928static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
929 int is_write, sigset_t *old_set,
930 void *puc)
931{
932 TranslationBlock *tb;
933 int ret;
934
935 if (cpu_single_env)
936 env = cpu_single_env; /* XXX: find a correct solution for multithread */
937#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000938 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
pbrooke6e59062006-10-22 00:18:54 +0000939 pc, address, is_write, *(unsigned long *)old_set);
940#endif
941 /* XXX: locking issue */
942 if (is_write && page_unprotect(address, pc, puc)) {
943 return 1;
944 }
945 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +0000946 ret = cpu_m68k_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
pbrooke6e59062006-10-22 00:18:54 +0000947 if (ret < 0)
948 return 0; /* not an MMU fault */
949 if (ret == 0)
950 return 1; /* the MMU fault was handled without causing real CPU fault */
951 /* now we have a real cpu fault */
952 tb = tb_find_pc(pc);
953 if (tb) {
954 /* the PC is inside the translated code. It means that we have
955 a virtual CPU fault */
956 cpu_restore_state(tb, env, pc, puc);
957 }
958 /* we restore the process signal mask as the sigreturn should
959 do it (XXX: use sigsetjmp) */
960 sigprocmask(SIG_SETMASK, old_set, NULL);
961 cpu_loop_exit();
962 /* never comes here */
963 return 1;
964}
965
bellard6af0bf92005-07-02 14:58:51 +0000966#elif defined (TARGET_MIPS)
967static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
968 int is_write, sigset_t *old_set,
969 void *puc)
970{
971 TranslationBlock *tb;
972 int ret;
ths3b46e622007-09-17 08:09:54 +0000973
bellard6af0bf92005-07-02 14:58:51 +0000974 if (cpu_single_env)
975 env = cpu_single_env; /* XXX: find a correct solution for multithread */
976#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000977 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellard6af0bf92005-07-02 14:58:51 +0000978 pc, address, is_write, *(unsigned long *)old_set);
979#endif
980 /* XXX: locking issue */
pbrook53a59602006-03-25 19:31:22 +0000981 if (is_write && page_unprotect(h2g(address), pc, puc)) {
bellard6af0bf92005-07-02 14:58:51 +0000982 return 1;
983 }
984
985 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +0000986 ret = cpu_mips_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellard6af0bf92005-07-02 14:58:51 +0000987 if (ret < 0)
988 return 0; /* not an MMU fault */
989 if (ret == 0)
990 return 1; /* the MMU fault was handled without causing real CPU fault */
991
992 /* now we have a real cpu fault */
993 tb = tb_find_pc(pc);
994 if (tb) {
995 /* the PC is inside the translated code. It means that we have
996 a virtual CPU fault */
997 cpu_restore_state(tb, env, pc, puc);
998 }
999 if (ret == 1) {
1000#if 0
ths5fafdf22007-09-16 21:08:06 +00001001 printf("PF exception: PC=0x" TARGET_FMT_lx " error=0x%x %p\n",
ths1eb52072007-05-12 16:57:42 +00001002 env->PC, env->error_code, tb);
bellard6af0bf92005-07-02 14:58:51 +00001003#endif
1004 /* we restore the process signal mask as the sigreturn should
1005 do it (XXX: use sigsetjmp) */
1006 sigprocmask(SIG_SETMASK, old_set, NULL);
thsf9480ff2008-12-20 19:42:14 +00001007 cpu_loop_exit();
bellard6af0bf92005-07-02 14:58:51 +00001008 } else {
1009 /* activate soft MMU for this block */
1010 cpu_resume_from_signal(env, puc);
1011 }
1012 /* never comes here */
1013 return 1;
1014}
1015
bellardfdf9b3e2006-04-27 21:07:38 +00001016#elif defined (TARGET_SH4)
1017static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
1018 int is_write, sigset_t *old_set,
1019 void *puc)
1020{
1021 TranslationBlock *tb;
1022 int ret;
ths3b46e622007-09-17 08:09:54 +00001023
bellardfdf9b3e2006-04-27 21:07:38 +00001024 if (cpu_single_env)
1025 env = cpu_single_env; /* XXX: find a correct solution for multithread */
1026#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +00001027 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellardfdf9b3e2006-04-27 21:07:38 +00001028 pc, address, is_write, *(unsigned long *)old_set);
1029#endif
1030 /* XXX: locking issue */
1031 if (is_write && page_unprotect(h2g(address), pc, puc)) {
1032 return 1;
1033 }
1034
1035 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +00001036 ret = cpu_sh4_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellardfdf9b3e2006-04-27 21:07:38 +00001037 if (ret < 0)
1038 return 0; /* not an MMU fault */
1039 if (ret == 0)
1040 return 1; /* the MMU fault was handled without causing real CPU fault */
1041
1042 /* now we have a real cpu fault */
1043 tb = tb_find_pc(pc);
1044 if (tb) {
1045 /* the PC is inside the translated code. It means that we have
1046 a virtual CPU fault */
1047 cpu_restore_state(tb, env, pc, puc);
1048 }
bellardfdf9b3e2006-04-27 21:07:38 +00001049#if 0
ths5fafdf22007-09-16 21:08:06 +00001050 printf("PF exception: NIP=0x%08x error=0x%x %p\n",
bellardfdf9b3e2006-04-27 21:07:38 +00001051 env->nip, env->error_code, tb);
1052#endif
1053 /* we restore the process signal mask as the sigreturn should
1054 do it (XXX: use sigsetjmp) */
pbrook355fb232006-06-17 19:58:25 +00001055 sigprocmask(SIG_SETMASK, old_set, NULL);
1056 cpu_loop_exit();
bellardfdf9b3e2006-04-27 21:07:38 +00001057 /* never comes here */
1058 return 1;
1059}
j_mayereddf68a2007-04-05 07:22:49 +00001060
1061#elif defined (TARGET_ALPHA)
1062static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
1063 int is_write, sigset_t *old_set,
1064 void *puc)
1065{
1066 TranslationBlock *tb;
1067 int ret;
ths3b46e622007-09-17 08:09:54 +00001068
j_mayereddf68a2007-04-05 07:22:49 +00001069 if (cpu_single_env)
1070 env = cpu_single_env; /* XXX: find a correct solution for multithread */
1071#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +00001072 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
j_mayereddf68a2007-04-05 07:22:49 +00001073 pc, address, is_write, *(unsigned long *)old_set);
1074#endif
1075 /* XXX: locking issue */
1076 if (is_write && page_unprotect(h2g(address), pc, puc)) {
1077 return 1;
1078 }
1079
1080 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +00001081 ret = cpu_alpha_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
j_mayereddf68a2007-04-05 07:22:49 +00001082 if (ret < 0)
1083 return 0; /* not an MMU fault */
1084 if (ret == 0)
1085 return 1; /* the MMU fault was handled without causing real CPU fault */
1086
1087 /* now we have a real cpu fault */
1088 tb = tb_find_pc(pc);
1089 if (tb) {
1090 /* the PC is inside the translated code. It means that we have
1091 a virtual CPU fault */
1092 cpu_restore_state(tb, env, pc, puc);
1093 }
1094#if 0
ths5fafdf22007-09-16 21:08:06 +00001095 printf("PF exception: NIP=0x%08x error=0x%x %p\n",
j_mayereddf68a2007-04-05 07:22:49 +00001096 env->nip, env->error_code, tb);
1097#endif
1098 /* we restore the process signal mask as the sigreturn should
1099 do it (XXX: use sigsetjmp) */
1100 sigprocmask(SIG_SETMASK, old_set, NULL);
1101 cpu_loop_exit();
1102 /* never comes here */
1103 return 1;
1104}
thsf1ccf902007-10-08 13:16:14 +00001105#elif defined (TARGET_CRIS)
1106static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
1107 int is_write, sigset_t *old_set,
1108 void *puc)
1109{
1110 TranslationBlock *tb;
1111 int ret;
1112
1113 if (cpu_single_env)
1114 env = cpu_single_env; /* XXX: find a correct solution for multithread */
1115#if defined(DEBUG_SIGNAL)
1116 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
1117 pc, address, is_write, *(unsigned long *)old_set);
1118#endif
1119 /* XXX: locking issue */
1120 if (is_write && page_unprotect(h2g(address), pc, puc)) {
1121 return 1;
1122 }
1123
1124 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +00001125 ret = cpu_cris_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
thsf1ccf902007-10-08 13:16:14 +00001126 if (ret < 0)
1127 return 0; /* not an MMU fault */
1128 if (ret == 0)
1129 return 1; /* the MMU fault was handled without causing real CPU fault */
1130
1131 /* now we have a real cpu fault */
1132 tb = tb_find_pc(pc);
1133 if (tb) {
1134 /* the PC is inside the translated code. It means that we have
1135 a virtual CPU fault */
1136 cpu_restore_state(tb, env, pc, puc);
1137 }
thsf1ccf902007-10-08 13:16:14 +00001138 /* we restore the process signal mask as the sigreturn should
1139 do it (XXX: use sigsetjmp) */
1140 sigprocmask(SIG_SETMASK, old_set, NULL);
1141 cpu_loop_exit();
1142 /* never comes here */
1143 return 1;
1144}
1145
bellarde4533c72003-06-15 19:51:39 +00001146#else
1147#error unsupported target CPU
1148#endif
bellard9de5e442003-03-23 16:49:39 +00001149
bellard2b413142003-05-14 23:01:10 +00001150#if defined(__i386__)
1151
bellardd8ecc0b2007-02-05 21:41:46 +00001152#if defined(__APPLE__)
1153# include <sys/ucontext.h>
1154
1155# define EIP_sig(context) (*((unsigned long*)&(context)->uc_mcontext->ss.eip))
1156# define TRAP_sig(context) ((context)->uc_mcontext->es.trapno)
1157# define ERROR_sig(context) ((context)->uc_mcontext->es.err)
1158#else
1159# define EIP_sig(context) ((context)->uc_mcontext.gregs[REG_EIP])
1160# define TRAP_sig(context) ((context)->uc_mcontext.gregs[REG_TRAPNO])
1161# define ERROR_sig(context) ((context)->uc_mcontext.gregs[REG_ERR])
1162#endif
1163
ths5fafdf22007-09-16 21:08:06 +00001164int cpu_signal_handler(int host_signum, void *pinfo,
bellarde4533c72003-06-15 19:51:39 +00001165 void *puc)
bellard9de5e442003-03-23 16:49:39 +00001166{
ths5a7b5422007-01-31 12:16:51 +00001167 siginfo_t *info = pinfo;
bellard9de5e442003-03-23 16:49:39 +00001168 struct ucontext *uc = puc;
1169 unsigned long pc;
bellardbf3e8bf2004-02-16 21:58:54 +00001170 int trapno;
bellard97eb5b12004-02-25 23:19:55 +00001171
bellardd691f662003-03-24 21:58:34 +00001172#ifndef REG_EIP
1173/* for glibc 2.1 */
bellardfd6ce8f2003-05-14 19:00:11 +00001174#define REG_EIP EIP
1175#define REG_ERR ERR
1176#define REG_TRAPNO TRAPNO
bellardd691f662003-03-24 21:58:34 +00001177#endif
bellardd8ecc0b2007-02-05 21:41:46 +00001178 pc = EIP_sig(uc);
1179 trapno = TRAP_sig(uc);
bellardec6338b2007-11-08 14:25:03 +00001180 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1181 trapno == 0xe ?
1182 (ERROR_sig(uc) >> 1) & 1 : 0,
1183 &uc->uc_sigmask, puc);
bellard2b413142003-05-14 23:01:10 +00001184}
1185
bellardbc51c5c2004-03-17 23:46:04 +00001186#elif defined(__x86_64__)
1187
blueswir1b3efe5c2008-12-05 17:55:45 +00001188#ifdef __NetBSD__
1189#define REG_ERR _REG_ERR
1190#define REG_TRAPNO _REG_TRAPNO
1191
1192#define QEMU_UC_MCONTEXT_GREGS(uc, reg) (uc)->uc_mcontext.__gregs[(reg)]
1193#define QEMU_UC_MACHINE_PC(uc) _UC_MACHINE_PC(uc)
1194#else
1195#define QEMU_UC_MCONTEXT_GREGS(uc, reg) (uc)->uc_mcontext.gregs[(reg)]
1196#define QEMU_UC_MACHINE_PC(uc) QEMU_UC_MCONTEXT_GREGS(uc, REG_RIP)
1197#endif
1198
ths5a7b5422007-01-31 12:16:51 +00001199int cpu_signal_handler(int host_signum, void *pinfo,
bellardbc51c5c2004-03-17 23:46:04 +00001200 void *puc)
1201{
ths5a7b5422007-01-31 12:16:51 +00001202 siginfo_t *info = pinfo;
bellardbc51c5c2004-03-17 23:46:04 +00001203 unsigned long pc;
blueswir1b3efe5c2008-12-05 17:55:45 +00001204#ifdef __NetBSD__
1205 ucontext_t *uc = puc;
1206#else
1207 struct ucontext *uc = puc;
1208#endif
bellardbc51c5c2004-03-17 23:46:04 +00001209
blueswir1b3efe5c2008-12-05 17:55:45 +00001210 pc = QEMU_UC_MACHINE_PC(uc);
ths5fafdf22007-09-16 21:08:06 +00001211 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
blueswir1b3efe5c2008-12-05 17:55:45 +00001212 QEMU_UC_MCONTEXT_GREGS(uc, REG_TRAPNO) == 0xe ?
1213 (QEMU_UC_MCONTEXT_GREGS(uc, REG_ERR) >> 1) & 1 : 0,
bellardbc51c5c2004-03-17 23:46:04 +00001214 &uc->uc_sigmask, puc);
1215}
1216
malce58ffeb2009-01-14 18:39:49 +00001217#elif defined(_ARCH_PPC)
bellard2b413142003-05-14 23:01:10 +00001218
bellard83fb7ad2004-07-05 21:25:26 +00001219/***********************************************************************
1220 * signal context platform-specific definitions
1221 * From Wine
1222 */
1223#ifdef linux
1224/* All Registers access - only for local access */
1225# define REG_sig(reg_name, context) ((context)->uc_mcontext.regs->reg_name)
1226/* Gpr Registers access */
1227# define GPR_sig(reg_num, context) REG_sig(gpr[reg_num], context)
1228# define IAR_sig(context) REG_sig(nip, context) /* Program counter */
1229# define MSR_sig(context) REG_sig(msr, context) /* Machine State Register (Supervisor) */
1230# define CTR_sig(context) REG_sig(ctr, context) /* Count register */
1231# define XER_sig(context) REG_sig(xer, context) /* User's integer exception register */
1232# define LR_sig(context) REG_sig(link, context) /* Link register */
1233# define CR_sig(context) REG_sig(ccr, context) /* Condition register */
1234/* Float Registers access */
1235# define FLOAT_sig(reg_num, context) (((double*)((char*)((context)->uc_mcontext.regs+48*4)))[reg_num])
1236# define FPSCR_sig(context) (*(int*)((char*)((context)->uc_mcontext.regs+(48+32*2)*4)))
1237/* Exception Registers access */
1238# define DAR_sig(context) REG_sig(dar, context)
1239# define DSISR_sig(context) REG_sig(dsisr, context)
1240# define TRAP_sig(context) REG_sig(trap, context)
1241#endif /* linux */
1242
1243#ifdef __APPLE__
1244# include <sys/ucontext.h>
1245typedef struct ucontext SIGCONTEXT;
1246/* All Registers access - only for local access */
1247# define REG_sig(reg_name, context) ((context)->uc_mcontext->ss.reg_name)
1248# define FLOATREG_sig(reg_name, context) ((context)->uc_mcontext->fs.reg_name)
1249# define EXCEPREG_sig(reg_name, context) ((context)->uc_mcontext->es.reg_name)
1250# define VECREG_sig(reg_name, context) ((context)->uc_mcontext->vs.reg_name)
1251/* Gpr Registers access */
1252# define GPR_sig(reg_num, context) REG_sig(r##reg_num, context)
1253# define IAR_sig(context) REG_sig(srr0, context) /* Program counter */
1254# define MSR_sig(context) REG_sig(srr1, context) /* Machine State Register (Supervisor) */
1255# define CTR_sig(context) REG_sig(ctr, context)
1256# define XER_sig(context) REG_sig(xer, context) /* Link register */
1257# define LR_sig(context) REG_sig(lr, context) /* User's integer exception register */
1258# define CR_sig(context) REG_sig(cr, context) /* Condition register */
1259/* Float Registers access */
1260# define FLOAT_sig(reg_num, context) FLOATREG_sig(fpregs[reg_num], context)
1261# define FPSCR_sig(context) ((double)FLOATREG_sig(fpscr, context))
1262/* Exception Registers access */
1263# define DAR_sig(context) EXCEPREG_sig(dar, context) /* Fault registers for coredump */
1264# define DSISR_sig(context) EXCEPREG_sig(dsisr, context)
1265# define TRAP_sig(context) EXCEPREG_sig(exception, context) /* number of powerpc exception taken */
1266#endif /* __APPLE__ */
1267
ths5fafdf22007-09-16 21:08:06 +00001268int cpu_signal_handler(int host_signum, void *pinfo,
bellarde4533c72003-06-15 19:51:39 +00001269 void *puc)
bellard2b413142003-05-14 23:01:10 +00001270{
ths5a7b5422007-01-31 12:16:51 +00001271 siginfo_t *info = pinfo;
bellard25eb4482003-05-14 21:50:54 +00001272 struct ucontext *uc = puc;
bellard25eb4482003-05-14 21:50:54 +00001273 unsigned long pc;
bellard25eb4482003-05-14 21:50:54 +00001274 int is_write;
1275
bellard83fb7ad2004-07-05 21:25:26 +00001276 pc = IAR_sig(uc);
bellard25eb4482003-05-14 21:50:54 +00001277 is_write = 0;
1278#if 0
1279 /* ppc 4xx case */
bellard83fb7ad2004-07-05 21:25:26 +00001280 if (DSISR_sig(uc) & 0x00800000)
bellard25eb4482003-05-14 21:50:54 +00001281 is_write = 1;
bellard9de5e442003-03-23 16:49:39 +00001282#else
bellard83fb7ad2004-07-05 21:25:26 +00001283 if (TRAP_sig(uc) != 0x400 && (DSISR_sig(uc) & 0x02000000))
bellard25eb4482003-05-14 21:50:54 +00001284 is_write = 1;
1285#endif
ths5fafdf22007-09-16 21:08:06 +00001286 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellardbf3e8bf2004-02-16 21:58:54 +00001287 is_write, &uc->uc_sigmask, puc);
bellard9de5e442003-03-23 16:49:39 +00001288}
bellard2b413142003-05-14 23:01:10 +00001289
bellard2f87c602003-06-02 20:38:09 +00001290#elif defined(__alpha__)
1291
ths5fafdf22007-09-16 21:08:06 +00001292int cpu_signal_handler(int host_signum, void *pinfo,
bellard2f87c602003-06-02 20:38:09 +00001293 void *puc)
1294{
ths5a7b5422007-01-31 12:16:51 +00001295 siginfo_t *info = pinfo;
bellard2f87c602003-06-02 20:38:09 +00001296 struct ucontext *uc = puc;
1297 uint32_t *pc = uc->uc_mcontext.sc_pc;
1298 uint32_t insn = *pc;
1299 int is_write = 0;
1300
bellard8c6939c2003-06-09 15:28:00 +00001301 /* XXX: need kernel patch to get write flag faster */
bellard2f87c602003-06-02 20:38:09 +00001302 switch (insn >> 26) {
1303 case 0x0d: // stw
1304 case 0x0e: // stb
1305 case 0x0f: // stq_u
1306 case 0x24: // stf
1307 case 0x25: // stg
1308 case 0x26: // sts
1309 case 0x27: // stt
1310 case 0x2c: // stl
1311 case 0x2d: // stq
1312 case 0x2e: // stl_c
1313 case 0x2f: // stq_c
1314 is_write = 1;
1315 }
1316
ths5fafdf22007-09-16 21:08:06 +00001317 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellardbf3e8bf2004-02-16 21:58:54 +00001318 is_write, &uc->uc_sigmask, puc);
bellard2f87c602003-06-02 20:38:09 +00001319}
bellard8c6939c2003-06-09 15:28:00 +00001320#elif defined(__sparc__)
1321
ths5fafdf22007-09-16 21:08:06 +00001322int cpu_signal_handler(int host_signum, void *pinfo,
bellarde4533c72003-06-15 19:51:39 +00001323 void *puc)
bellard8c6939c2003-06-09 15:28:00 +00001324{
ths5a7b5422007-01-31 12:16:51 +00001325 siginfo_t *info = pinfo;
bellard8c6939c2003-06-09 15:28:00 +00001326 int is_write;
1327 uint32_t insn;
blueswir16b4c11c2008-05-19 17:20:01 +00001328#if !defined(__arch64__) || defined(HOST_SOLARIS)
blueswir1c9e1e2b2008-05-18 06:40:16 +00001329 uint32_t *regs = (uint32_t *)(info + 1);
1330 void *sigmask = (regs + 20);
bellard8c6939c2003-06-09 15:28:00 +00001331 /* XXX: is there a standard glibc define ? */
blueswir1c9e1e2b2008-05-18 06:40:16 +00001332 unsigned long pc = regs[1];
1333#else
blueswir184778502008-10-26 20:33:16 +00001334#ifdef __linux__
blueswir1c9e1e2b2008-05-18 06:40:16 +00001335 struct sigcontext *sc = puc;
1336 unsigned long pc = sc->sigc_regs.tpc;
1337 void *sigmask = (void *)sc->sigc_mask;
blueswir184778502008-10-26 20:33:16 +00001338#elif defined(__OpenBSD__)
1339 struct sigcontext *uc = puc;
1340 unsigned long pc = uc->sc_pc;
1341 void *sigmask = (void *)(long)uc->sc_mask;
1342#endif
blueswir1c9e1e2b2008-05-18 06:40:16 +00001343#endif
1344
bellard8c6939c2003-06-09 15:28:00 +00001345 /* XXX: need kernel patch to get write flag faster */
1346 is_write = 0;
1347 insn = *(uint32_t *)pc;
1348 if ((insn >> 30) == 3) {
1349 switch((insn >> 19) & 0x3f) {
1350 case 0x05: // stb
1351 case 0x06: // sth
1352 case 0x04: // st
1353 case 0x07: // std
1354 case 0x24: // stf
1355 case 0x27: // stdf
1356 case 0x25: // stfsr
1357 is_write = 1;
1358 break;
1359 }
1360 }
ths5fafdf22007-09-16 21:08:06 +00001361 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellardbf3e8bf2004-02-16 21:58:54 +00001362 is_write, sigmask, NULL);
bellard8c6939c2003-06-09 15:28:00 +00001363}
1364
1365#elif defined(__arm__)
1366
ths5fafdf22007-09-16 21:08:06 +00001367int cpu_signal_handler(int host_signum, void *pinfo,
bellarde4533c72003-06-15 19:51:39 +00001368 void *puc)
bellard8c6939c2003-06-09 15:28:00 +00001369{
ths5a7b5422007-01-31 12:16:51 +00001370 siginfo_t *info = pinfo;
bellard8c6939c2003-06-09 15:28:00 +00001371 struct ucontext *uc = puc;
1372 unsigned long pc;
1373 int is_write;
ths3b46e622007-09-17 08:09:54 +00001374
blueswir148bbf112008-07-08 18:35:02 +00001375#if (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ <= 3))
balrog5c49b362008-06-02 01:01:18 +00001376 pc = uc->uc_mcontext.gregs[R15];
1377#else
balrog4eee57f2008-05-06 14:47:19 +00001378 pc = uc->uc_mcontext.arm_pc;
balrog5c49b362008-06-02 01:01:18 +00001379#endif
bellard8c6939c2003-06-09 15:28:00 +00001380 /* XXX: compute is_write */
1381 is_write = 0;
ths5fafdf22007-09-16 21:08:06 +00001382 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellard8c6939c2003-06-09 15:28:00 +00001383 is_write,
pbrookf3a96762006-07-29 19:09:31 +00001384 &uc->uc_sigmask, puc);
bellard8c6939c2003-06-09 15:28:00 +00001385}
1386
bellard38e584a2003-08-10 22:14:22 +00001387#elif defined(__mc68000)
1388
ths5fafdf22007-09-16 21:08:06 +00001389int cpu_signal_handler(int host_signum, void *pinfo,
bellard38e584a2003-08-10 22:14:22 +00001390 void *puc)
1391{
ths5a7b5422007-01-31 12:16:51 +00001392 siginfo_t *info = pinfo;
bellard38e584a2003-08-10 22:14:22 +00001393 struct ucontext *uc = puc;
1394 unsigned long pc;
1395 int is_write;
ths3b46e622007-09-17 08:09:54 +00001396
bellard38e584a2003-08-10 22:14:22 +00001397 pc = uc->uc_mcontext.gregs[16];
1398 /* XXX: compute is_write */
1399 is_write = 0;
ths5fafdf22007-09-16 21:08:06 +00001400 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellard38e584a2003-08-10 22:14:22 +00001401 is_write,
bellardbf3e8bf2004-02-16 21:58:54 +00001402 &uc->uc_sigmask, puc);
bellard38e584a2003-08-10 22:14:22 +00001403}
1404
bellardb8076a72005-04-07 22:20:31 +00001405#elif defined(__ia64)
1406
1407#ifndef __ISR_VALID
1408 /* This ought to be in <bits/siginfo.h>... */
1409# define __ISR_VALID 1
bellardb8076a72005-04-07 22:20:31 +00001410#endif
1411
ths5a7b5422007-01-31 12:16:51 +00001412int cpu_signal_handler(int host_signum, void *pinfo, void *puc)
bellardb8076a72005-04-07 22:20:31 +00001413{
ths5a7b5422007-01-31 12:16:51 +00001414 siginfo_t *info = pinfo;
bellardb8076a72005-04-07 22:20:31 +00001415 struct ucontext *uc = puc;
1416 unsigned long ip;
1417 int is_write = 0;
1418
1419 ip = uc->uc_mcontext.sc_ip;
1420 switch (host_signum) {
1421 case SIGILL:
1422 case SIGFPE:
1423 case SIGSEGV:
1424 case SIGBUS:
1425 case SIGTRAP:
bellardfd4a43e2006-04-24 20:32:17 +00001426 if (info->si_code && (info->si_segvflags & __ISR_VALID))
bellardb8076a72005-04-07 22:20:31 +00001427 /* ISR.W (write-access) is bit 33: */
1428 is_write = (info->si_isr >> 33) & 1;
1429 break;
1430
1431 default:
1432 break;
1433 }
1434 return handle_cpu_signal(ip, (unsigned long)info->si_addr,
1435 is_write,
1436 &uc->uc_sigmask, puc);
1437}
1438
bellard90cb9492005-07-24 15:11:38 +00001439#elif defined(__s390__)
1440
ths5fafdf22007-09-16 21:08:06 +00001441int cpu_signal_handler(int host_signum, void *pinfo,
bellard90cb9492005-07-24 15:11:38 +00001442 void *puc)
1443{
ths5a7b5422007-01-31 12:16:51 +00001444 siginfo_t *info = pinfo;
bellard90cb9492005-07-24 15:11:38 +00001445 struct ucontext *uc = puc;
1446 unsigned long pc;
1447 int is_write;
ths3b46e622007-09-17 08:09:54 +00001448
bellard90cb9492005-07-24 15:11:38 +00001449 pc = uc->uc_mcontext.psw.addr;
1450 /* XXX: compute is_write */
1451 is_write = 0;
ths5fafdf22007-09-16 21:08:06 +00001452 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
thsc4b89d12007-05-05 19:23:11 +00001453 is_write, &uc->uc_sigmask, puc);
1454}
1455
1456#elif defined(__mips__)
1457
ths5fafdf22007-09-16 21:08:06 +00001458int cpu_signal_handler(int host_signum, void *pinfo,
thsc4b89d12007-05-05 19:23:11 +00001459 void *puc)
1460{
ths9617efe2007-05-08 21:05:55 +00001461 siginfo_t *info = pinfo;
thsc4b89d12007-05-05 19:23:11 +00001462 struct ucontext *uc = puc;
1463 greg_t pc = uc->uc_mcontext.pc;
1464 int is_write;
ths3b46e622007-09-17 08:09:54 +00001465
thsc4b89d12007-05-05 19:23:11 +00001466 /* XXX: compute is_write */
1467 is_write = 0;
ths5fafdf22007-09-16 21:08:06 +00001468 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
thsc4b89d12007-05-05 19:23:11 +00001469 is_write, &uc->uc_sigmask, puc);
bellard90cb9492005-07-24 15:11:38 +00001470}
1471
aurel32f54b3f92008-04-12 20:14:54 +00001472#elif defined(__hppa__)
1473
1474int cpu_signal_handler(int host_signum, void *pinfo,
1475 void *puc)
1476{
1477 struct siginfo *info = pinfo;
1478 struct ucontext *uc = puc;
1479 unsigned long pc;
1480 int is_write;
1481
1482 pc = uc->uc_mcontext.sc_iaoq[0];
1483 /* FIXME: compute is_write */
1484 is_write = 0;
1485 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1486 is_write,
1487 &uc->uc_sigmask, puc);
1488}
1489
bellard2b413142003-05-14 23:01:10 +00001490#else
1491
bellard3fb2ded2003-06-24 13:22:59 +00001492#error host CPU specific signal handler needed
bellard2b413142003-05-14 23:01:10 +00001493
1494#endif
bellard67b915a2004-03-31 23:37:16 +00001495
1496#endif /* !defined(CONFIG_SOFTMMU) */