blob: 191d9e4288da818edadc200a78cd16105ca41463 [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
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
bellard7d132992003-03-06 23:23:54 +000019 */
bellarde4533c72003-06-15 19:51:39 +000020#include "config.h"
bellard7cb69ca2008-05-10 10:55:51 +000021#define CPU_NO_GLOBAL_REGS
bellard93ac68b2003-09-30 20:57:29 +000022#include "exec.h"
bellard956034d2003-04-29 20:40:53 +000023#include "disas.h"
bellard7cb69ca2008-05-10 10:55:51 +000024#include "tcg.h"
aliguori7ba1e612008-11-05 16:04:33 +000025#include "kvm.h"
bellard7d132992003-03-06 23:23:54 +000026
bellardfbf9eeb2004-04-25 21:21:33 +000027#if !defined(CONFIG_SOFTMMU)
28#undef EAX
29#undef ECX
30#undef EDX
31#undef EBX
32#undef ESP
33#undef EBP
34#undef ESI
35#undef EDI
36#undef EIP
37#include <signal.h>
blueswir184778502008-10-26 20:33:16 +000038#ifdef __linux__
bellardfbf9eeb2004-04-25 21:21:33 +000039#include <sys/ucontext.h>
40#endif
blueswir184778502008-10-26 20:33:16 +000041#endif
bellardfbf9eeb2004-04-25 21:21:33 +000042
blueswir1572a9d42008-05-17 07:38:10 +000043#if defined(__sparc__) && !defined(HOST_SOLARIS)
44// Work around ugly bugs in glibc that mangle global register contents
45#undef env
46#define env cpu_single_env
47#endif
48
bellard36bdbe52003-11-19 22:12:02 +000049int tb_invalidated_flag;
50
bellarddc990652003-03-19 00:00:28 +000051//#define DEBUG_EXEC
bellard9de5e442003-03-23 16:49:39 +000052//#define DEBUG_SIGNAL
bellard7d132992003-03-06 23:23:54 +000053
bellarde4533c72003-06-15 19:51:39 +000054void cpu_loop_exit(void)
55{
thsbfed01f2007-06-03 17:44:37 +000056 /* NOTE: the register at this point must be saved by hand because
57 longjmp restore them */
58 regs_to_env();
bellarde4533c72003-06-15 19:51:39 +000059 longjmp(env->jmp_env, 1);
60}
thsbfed01f2007-06-03 17:44:37 +000061
bellardfbf9eeb2004-04-25 21:21:33 +000062/* exit the current TB from a signal handler. The host registers are
63 restored in a state compatible with the CPU emulator
64 */
ths5fafdf22007-09-16 21:08:06 +000065void cpu_resume_from_signal(CPUState *env1, void *puc)
bellardfbf9eeb2004-04-25 21:21:33 +000066{
67#if !defined(CONFIG_SOFTMMU)
blueswir184778502008-10-26 20:33:16 +000068#ifdef __linux__
bellardfbf9eeb2004-04-25 21:21:33 +000069 struct ucontext *uc = puc;
blueswir184778502008-10-26 20:33:16 +000070#elif defined(__OpenBSD__)
71 struct sigcontext *uc = puc;
72#endif
bellardfbf9eeb2004-04-25 21:21:33 +000073#endif
74
75 env = env1;
76
77 /* XXX: restore cpu registers saved in host registers */
78
79#if !defined(CONFIG_SOFTMMU)
80 if (puc) {
81 /* XXX: use siglongjmp ? */
blueswir184778502008-10-26 20:33:16 +000082#ifdef __linux__
bellardfbf9eeb2004-04-25 21:21:33 +000083 sigprocmask(SIG_SETMASK, &uc->uc_sigmask, NULL);
blueswir184778502008-10-26 20:33:16 +000084#elif defined(__OpenBSD__)
85 sigprocmask(SIG_SETMASK, &uc->sc_mask, NULL);
86#endif
bellardfbf9eeb2004-04-25 21:21:33 +000087 }
88#endif
89 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
aliguori6e140f22008-11-18 20:37:55 +0000186static void cpu_handle_debug_exception(CPUState *env)
187{
188 CPUWatchpoint *wp;
189
190 if (!env->watchpoint_hit)
191 for (wp = env->watchpoints; wp != NULL; wp = wp->next)
192 wp->flags &= ~BP_WATCHPOINT_HIT;
193}
194
bellard7d132992003-03-06 23:23:54 +0000195/* main execution loop */
196
bellarde4533c72003-06-15 19:51:39 +0000197int cpu_exec(CPUState *env1)
bellard7d132992003-03-06 23:23:54 +0000198{
pbrook1057eaa2007-02-04 13:37:44 +0000199#define DECLARE_HOST_REGS 1
200#include "hostregs_helper.h"
bellard8a40a182005-11-20 10:35:40 +0000201 int ret, interrupt_request;
bellard8a40a182005-11-20 10:35:40 +0000202 TranslationBlock *tb;
bellardc27004e2005-01-03 23:35:10 +0000203 uint8_t *tc_ptr;
pbrookd5975362008-06-07 20:50:51 +0000204 unsigned long next_tb;
bellard8c6939c2003-06-09 15:28:00 +0000205
thsbfed01f2007-06-03 17:44:37 +0000206 if (cpu_halted(env1) == EXCP_HALTED)
207 return EXCP_HALTED;
bellard5a1e3cf2005-11-23 21:02:53 +0000208
ths5fafdf22007-09-16 21:08:06 +0000209 cpu_single_env = env1;
bellard6a00d602005-11-21 23:25:50 +0000210
bellard7d132992003-03-06 23:23:54 +0000211 /* first we save global registers */
pbrook1057eaa2007-02-04 13:37:44 +0000212#define SAVE_HOST_REGS 1
213#include "hostregs_helper.h"
bellardc27004e2005-01-03 23:35:10 +0000214 env = env1;
bellarde4533c72003-06-15 19:51:39 +0000215
bellard0d1a29f2004-10-12 22:01:28 +0000216 env_to_regs();
thsecb644f2007-06-03 18:45:53 +0000217#if defined(TARGET_I386)
bellard9de5e442003-03-23 16:49:39 +0000218 /* put eflags in CPU temporary format */
bellardfc2b4c42003-03-29 16:52:44 +0000219 CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
220 DF = 1 - (2 * ((env->eflags >> 10) & 1));
bellard9de5e442003-03-23 16:49:39 +0000221 CC_OP = CC_OP_EFLAGS;
bellardfc2b4c42003-03-29 16:52:44 +0000222 env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
bellard93ac68b2003-09-30 20:57:29 +0000223#elif defined(TARGET_SPARC)
pbrooke6e59062006-10-22 00:18:54 +0000224#elif defined(TARGET_M68K)
225 env->cc_op = CC_OP_FLAGS;
226 env->cc_dest = env->sr & 0xf;
227 env->cc_x = (env->sr >> 4) & 1;
thsecb644f2007-06-03 18:45:53 +0000228#elif defined(TARGET_ALPHA)
229#elif defined(TARGET_ARM)
230#elif defined(TARGET_PPC)
bellard6af0bf92005-07-02 14:58:51 +0000231#elif defined(TARGET_MIPS)
bellardfdf9b3e2006-04-27 21:07:38 +0000232#elif defined(TARGET_SH4)
thsf1ccf902007-10-08 13:16:14 +0000233#elif defined(TARGET_CRIS)
bellardfdf9b3e2006-04-27 21:07:38 +0000234 /* XXXXX */
bellarde4533c72003-06-15 19:51:39 +0000235#else
236#error unsupported target CPU
237#endif
bellard3fb2ded2003-06-24 13:22:59 +0000238 env->exception_index = -1;
bellard9d27abd2003-05-10 13:13:54 +0000239
bellard7d132992003-03-06 23:23:54 +0000240 /* prepare setjmp context for exception handling */
bellard3fb2ded2003-06-24 13:22:59 +0000241 for(;;) {
242 if (setjmp(env->jmp_env) == 0) {
bellardee8b7022004-02-03 23:35:10 +0000243 env->current_tb = NULL;
bellard3fb2ded2003-06-24 13:22:59 +0000244 /* if an exception is pending, we execute it here */
245 if (env->exception_index >= 0) {
246 if (env->exception_index >= EXCP_INTERRUPT) {
247 /* exit request from the cpu execution loop */
248 ret = env->exception_index;
aliguori6e140f22008-11-18 20:37:55 +0000249 if (ret == EXCP_DEBUG)
250 cpu_handle_debug_exception(env);
bellard3fb2ded2003-06-24 13:22:59 +0000251 break;
252 } else if (env->user_mode_only) {
253 /* if user mode only, we simulate a fake exception
ths9f083492006-12-07 18:28:42 +0000254 which will be handled outside the cpu execution
bellard3fb2ded2003-06-24 13:22:59 +0000255 loop */
bellard83479e72003-06-25 16:12:37 +0000256#if defined(TARGET_I386)
ths5fafdf22007-09-16 21:08:06 +0000257 do_interrupt_user(env->exception_index,
258 env->exception_is_int,
259 env->error_code,
bellard3fb2ded2003-06-24 13:22:59 +0000260 env->exception_next_eip);
bellardeba01622008-05-12 12:04:40 +0000261 /* successfully delivered */
262 env->old_exception = -1;
bellard83479e72003-06-25 16:12:37 +0000263#endif
bellard3fb2ded2003-06-24 13:22:59 +0000264 ret = env->exception_index;
265 break;
266 } else {
bellard83479e72003-06-25 16:12:37 +0000267#if defined(TARGET_I386)
bellard3fb2ded2003-06-24 13:22:59 +0000268 /* simulate a real cpu exception. On i386, it can
269 trigger new exceptions, but we do not handle
270 double or triple faults yet. */
ths5fafdf22007-09-16 21:08:06 +0000271 do_interrupt(env->exception_index,
272 env->exception_is_int,
273 env->error_code,
bellardd05e66d2003-08-20 21:34:35 +0000274 env->exception_next_eip, 0);
ths678dde12007-03-31 20:28:52 +0000275 /* successfully delivered */
276 env->old_exception = -1;
bellardce097762004-01-04 23:53:18 +0000277#elif defined(TARGET_PPC)
278 do_interrupt(env);
bellard6af0bf92005-07-02 14:58:51 +0000279#elif defined(TARGET_MIPS)
280 do_interrupt(env);
bellarde95c8d52004-09-30 22:22:08 +0000281#elif defined(TARGET_SPARC)
blueswir1f2bc7e72008-05-27 17:35:30 +0000282 do_interrupt(env);
bellardb5ff1b32005-11-26 10:38:39 +0000283#elif defined(TARGET_ARM)
284 do_interrupt(env);
bellardfdf9b3e2006-04-27 21:07:38 +0000285#elif defined(TARGET_SH4)
286 do_interrupt(env);
j_mayereddf68a2007-04-05 07:22:49 +0000287#elif defined(TARGET_ALPHA)
288 do_interrupt(env);
thsf1ccf902007-10-08 13:16:14 +0000289#elif defined(TARGET_CRIS)
290 do_interrupt(env);
pbrook06338792007-05-23 19:58:11 +0000291#elif defined(TARGET_M68K)
292 do_interrupt(0);
bellard83479e72003-06-25 16:12:37 +0000293#endif
bellard3fb2ded2003-06-24 13:22:59 +0000294 }
295 env->exception_index = -1;
ths5fafdf22007-09-16 21:08:06 +0000296 }
bellard9df217a2005-02-10 22:05:51 +0000297#ifdef USE_KQEMU
298 if (kqemu_is_ok(env) && env->interrupt_request == 0) {
299 int ret;
pbrooka7812ae2008-11-17 14:43:54 +0000300 env->eflags = env->eflags | helper_cc_compute_all(CC_OP) | (DF & DF_MASK);
bellard9df217a2005-02-10 22:05:51 +0000301 ret = kqemu_cpu_exec(env);
302 /* put eflags in CPU temporary format */
303 CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
304 DF = 1 - (2 * ((env->eflags >> 10) & 1));
305 CC_OP = CC_OP_EFLAGS;
306 env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
307 if (ret == 1) {
308 /* exception */
309 longjmp(env->jmp_env, 1);
310 } else if (ret == 2) {
311 /* softmmu execution needed */
312 } else {
313 if (env->interrupt_request != 0) {
314 /* hardware interrupt will be executed just after */
315 } else {
316 /* otherwise, we restart */
317 longjmp(env->jmp_env, 1);
318 }
319 }
bellard9de5e442003-03-23 16:49:39 +0000320 }
bellard9df217a2005-02-10 22:05:51 +0000321#endif
322
aliguori7ba1e612008-11-05 16:04:33 +0000323 if (kvm_enabled()) {
aliguoribecfc392008-11-10 15:55:14 +0000324 kvm_cpu_exec(env);
325 longjmp(env->jmp_env, 1);
aliguori7ba1e612008-11-05 16:04:33 +0000326 }
327
blueswir1b5fc09a2008-05-04 06:38:18 +0000328 next_tb = 0; /* force lookup of first TB */
bellard3fb2ded2003-06-24 13:22:59 +0000329 for(;;) {
bellard68a79312003-06-30 13:12:32 +0000330 interrupt_request = env->interrupt_request;
malce1638bd2008-11-06 18:54:46 +0000331 if (unlikely(interrupt_request)) {
332 if (unlikely(env->singlestep_enabled & SSTEP_NOIRQ)) {
333 /* Mask out external interrupts for this step. */
334 interrupt_request &= ~(CPU_INTERRUPT_HARD |
335 CPU_INTERRUPT_FIQ |
336 CPU_INTERRUPT_SMI |
337 CPU_INTERRUPT_NMI);
338 }
pbrook6658ffb2007-03-16 23:58:11 +0000339 if (interrupt_request & CPU_INTERRUPT_DEBUG) {
340 env->interrupt_request &= ~CPU_INTERRUPT_DEBUG;
341 env->exception_index = EXCP_DEBUG;
342 cpu_loop_exit();
343 }
balroga90b7312007-05-01 01:28:01 +0000344#if defined(TARGET_ARM) || defined(TARGET_SPARC) || defined(TARGET_MIPS) || \
thsf1ccf902007-10-08 13:16:14 +0000345 defined(TARGET_PPC) || defined(TARGET_ALPHA) || defined(TARGET_CRIS)
balroga90b7312007-05-01 01:28:01 +0000346 if (interrupt_request & CPU_INTERRUPT_HALT) {
347 env->interrupt_request &= ~CPU_INTERRUPT_HALT;
348 env->halted = 1;
349 env->exception_index = EXCP_HLT;
350 cpu_loop_exit();
351 }
352#endif
bellard68a79312003-06-30 13:12:32 +0000353#if defined(TARGET_I386)
bellarddb620f42008-06-04 17:02:19 +0000354 if (env->hflags2 & HF2_GIF_MASK) {
355 if ((interrupt_request & CPU_INTERRUPT_SMI) &&
356 !(env->hflags & HF_SMM_MASK)) {
357 svm_check_intercept(SVM_EXIT_SMI);
358 env->interrupt_request &= ~CPU_INTERRUPT_SMI;
359 do_smm_enter();
360 next_tb = 0;
361 } else if ((interrupt_request & CPU_INTERRUPT_NMI) &&
362 !(env->hflags2 & HF2_NMI_MASK)) {
363 env->interrupt_request &= ~CPU_INTERRUPT_NMI;
364 env->hflags2 |= HF2_NMI_MASK;
365 do_interrupt(EXCP02_NMI, 0, 0, 0, 1);
366 next_tb = 0;
367 } else if ((interrupt_request & CPU_INTERRUPT_HARD) &&
368 (((env->hflags2 & HF2_VINTR_MASK) &&
369 (env->hflags2 & HF2_HIF_MASK)) ||
370 (!(env->hflags2 & HF2_VINTR_MASK) &&
371 (env->eflags & IF_MASK &&
372 !(env->hflags & HF_INHIBIT_IRQ_MASK))))) {
373 int intno;
374 svm_check_intercept(SVM_EXIT_INTR);
375 env->interrupt_request &= ~(CPU_INTERRUPT_HARD | CPU_INTERRUPT_VIRQ);
376 intno = cpu_get_pic_interrupt(env);
377 if (loglevel & CPU_LOG_TB_IN_ASM) {
378 fprintf(logfile, "Servicing hardware INT=0x%02x\n", intno);
379 }
380 do_interrupt(intno, 0, 0, 0, 1);
381 /* ensure that no TB jump will be modified as
382 the program flow was changed */
383 next_tb = 0;
ths0573fbf2007-09-23 15:28:04 +0000384#if !defined(CONFIG_USER_ONLY)
bellarddb620f42008-06-04 17:02:19 +0000385 } else if ((interrupt_request & CPU_INTERRUPT_VIRQ) &&
386 (env->eflags & IF_MASK) &&
387 !(env->hflags & HF_INHIBIT_IRQ_MASK)) {
388 int intno;
389 /* FIXME: this should respect TPR */
390 svm_check_intercept(SVM_EXIT_VINTR);
391 env->interrupt_request &= ~CPU_INTERRUPT_VIRQ;
392 intno = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_vector));
393 if (loglevel & CPU_LOG_TB_IN_ASM)
394 fprintf(logfile, "Servicing virtual hardware INT=0x%02x\n", intno);
395 do_interrupt(intno, 0, 0, 0, 1);
396 next_tb = 0;
ths0573fbf2007-09-23 15:28:04 +0000397#endif
bellarddb620f42008-06-04 17:02:19 +0000398 }
bellard68a79312003-06-30 13:12:32 +0000399 }
bellardce097762004-01-04 23:53:18 +0000400#elif defined(TARGET_PPC)
bellard9fddaa02004-05-21 12:59:32 +0000401#if 0
402 if ((interrupt_request & CPU_INTERRUPT_RESET)) {
403 cpu_ppc_reset(env);
404 }
405#endif
j_mayer47103572007-03-30 09:38:04 +0000406 if (interrupt_request & CPU_INTERRUPT_HARD) {
j_mayere9df0142007-04-09 22:45:36 +0000407 ppc_hw_interrupt(env);
408 if (env->pending_interrupts == 0)
409 env->interrupt_request &= ~CPU_INTERRUPT_HARD;
blueswir1b5fc09a2008-05-04 06:38:18 +0000410 next_tb = 0;
bellardce097762004-01-04 23:53:18 +0000411 }
bellard6af0bf92005-07-02 14:58:51 +0000412#elif defined(TARGET_MIPS)
413 if ((interrupt_request & CPU_INTERRUPT_HARD) &&
ths24c7b0e2007-03-30 16:44:54 +0000414 (env->CP0_Status & env->CP0_Cause & CP0Ca_IP_mask) &&
bellard6af0bf92005-07-02 14:58:51 +0000415 (env->CP0_Status & (1 << CP0St_IE)) &&
ths24c7b0e2007-03-30 16:44:54 +0000416 !(env->CP0_Status & (1 << CP0St_EXL)) &&
417 !(env->CP0_Status & (1 << CP0St_ERL)) &&
bellard6af0bf92005-07-02 14:58:51 +0000418 !(env->hflags & MIPS_HFLAG_DM)) {
419 /* Raise it */
420 env->exception_index = EXCP_EXT_INTERRUPT;
421 env->error_code = 0;
422 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000423 next_tb = 0;
bellard6af0bf92005-07-02 14:58:51 +0000424 }
bellarde95c8d52004-09-30 22:22:08 +0000425#elif defined(TARGET_SPARC)
bellard66321a12005-04-06 20:47:48 +0000426 if ((interrupt_request & CPU_INTERRUPT_HARD) &&
427 (env->psret != 0)) {
428 int pil = env->interrupt_index & 15;
429 int type = env->interrupt_index & 0xf0;
430
431 if (((type == TT_EXTINT) &&
432 (pil == 15 || pil > env->psrpil)) ||
433 type != TT_EXTINT) {
434 env->interrupt_request &= ~CPU_INTERRUPT_HARD;
blueswir1f2bc7e72008-05-27 17:35:30 +0000435 env->exception_index = env->interrupt_index;
436 do_interrupt(env);
bellard66321a12005-04-06 20:47:48 +0000437 env->interrupt_index = 0;
blueswir1327ac2e2007-08-04 10:50:30 +0000438#if !defined(TARGET_SPARC64) && !defined(CONFIG_USER_ONLY)
439 cpu_check_irqs(env);
440#endif
blueswir1b5fc09a2008-05-04 06:38:18 +0000441 next_tb = 0;
bellard66321a12005-04-06 20:47:48 +0000442 }
bellarde95c8d52004-09-30 22:22:08 +0000443 } else if (interrupt_request & CPU_INTERRUPT_TIMER) {
444 //do_interrupt(0, 0, 0, 0, 0);
445 env->interrupt_request &= ~CPU_INTERRUPT_TIMER;
balroga90b7312007-05-01 01:28:01 +0000446 }
bellardb5ff1b32005-11-26 10:38:39 +0000447#elif defined(TARGET_ARM)
448 if (interrupt_request & CPU_INTERRUPT_FIQ
449 && !(env->uncached_cpsr & CPSR_F)) {
450 env->exception_index = EXCP_FIQ;
451 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000452 next_tb = 0;
bellardb5ff1b32005-11-26 10:38:39 +0000453 }
pbrook9ee6e8b2007-11-11 00:04:49 +0000454 /* ARMv7-M interrupt return works by loading a magic value
455 into the PC. On real hardware the load causes the
456 return to occur. The qemu implementation performs the
457 jump normally, then does the exception return when the
458 CPU tries to execute code at the magic address.
459 This will cause the magic PC value to be pushed to
460 the stack if an interrupt occured at the wrong time.
461 We avoid this by disabling interrupts when
462 pc contains a magic address. */
bellardb5ff1b32005-11-26 10:38:39 +0000463 if (interrupt_request & CPU_INTERRUPT_HARD
pbrook9ee6e8b2007-11-11 00:04:49 +0000464 && ((IS_M(env) && env->regs[15] < 0xfffffff0)
465 || !(env->uncached_cpsr & CPSR_I))) {
bellardb5ff1b32005-11-26 10:38:39 +0000466 env->exception_index = EXCP_IRQ;
467 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000468 next_tb = 0;
bellardb5ff1b32005-11-26 10:38:39 +0000469 }
bellardfdf9b3e2006-04-27 21:07:38 +0000470#elif defined(TARGET_SH4)
thse96e2042007-12-02 06:18:24 +0000471 if (interrupt_request & CPU_INTERRUPT_HARD) {
472 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000473 next_tb = 0;
thse96e2042007-12-02 06:18:24 +0000474 }
j_mayereddf68a2007-04-05 07:22:49 +0000475#elif defined(TARGET_ALPHA)
476 if (interrupt_request & CPU_INTERRUPT_HARD) {
477 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000478 next_tb = 0;
j_mayereddf68a2007-04-05 07:22:49 +0000479 }
thsf1ccf902007-10-08 13:16:14 +0000480#elif defined(TARGET_CRIS)
edgar_igl1b1a38b2008-06-09 23:18:06 +0000481 if (interrupt_request & CPU_INTERRUPT_HARD
482 && (env->pregs[PR_CCS] & I_FLAG)) {
483 env->exception_index = EXCP_IRQ;
484 do_interrupt(env);
485 next_tb = 0;
486 }
487 if (interrupt_request & CPU_INTERRUPT_NMI
488 && (env->pregs[PR_CCS] & M_FLAG)) {
489 env->exception_index = EXCP_NMI;
thsf1ccf902007-10-08 13:16:14 +0000490 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000491 next_tb = 0;
thsf1ccf902007-10-08 13:16:14 +0000492 }
pbrook06338792007-05-23 19:58:11 +0000493#elif defined(TARGET_M68K)
494 if (interrupt_request & CPU_INTERRUPT_HARD
495 && ((env->sr & SR_I) >> SR_I_SHIFT)
496 < env->pending_level) {
497 /* Real hardware gets the interrupt vector via an
498 IACK cycle at this point. Current emulated
499 hardware doesn't rely on this, so we
500 provide/save the vector when the interrupt is
501 first signalled. */
502 env->exception_index = env->pending_vector;
503 do_interrupt(1);
blueswir1b5fc09a2008-05-04 06:38:18 +0000504 next_tb = 0;
pbrook06338792007-05-23 19:58:11 +0000505 }
bellard68a79312003-06-30 13:12:32 +0000506#endif
bellard9d050952006-05-22 22:03:52 +0000507 /* Don't use the cached interupt_request value,
508 do_interrupt may have updated the EXITTB flag. */
bellardb5ff1b32005-11-26 10:38:39 +0000509 if (env->interrupt_request & CPU_INTERRUPT_EXITTB) {
bellardbf3e8bf2004-02-16 21:58:54 +0000510 env->interrupt_request &= ~CPU_INTERRUPT_EXITTB;
511 /* ensure that no TB jump will be modified as
512 the program flow was changed */
blueswir1b5fc09a2008-05-04 06:38:18 +0000513 next_tb = 0;
bellardbf3e8bf2004-02-16 21:58:54 +0000514 }
bellard68a79312003-06-30 13:12:32 +0000515 if (interrupt_request & CPU_INTERRUPT_EXIT) {
516 env->interrupt_request &= ~CPU_INTERRUPT_EXIT;
517 env->exception_index = EXCP_INTERRUPT;
518 cpu_loop_exit();
519 }
bellard3fb2ded2003-06-24 13:22:59 +0000520 }
521#ifdef DEBUG_EXEC
bellardb5ff1b32005-11-26 10:38:39 +0000522 if ((loglevel & CPU_LOG_TB_CPU)) {
bellard3fb2ded2003-06-24 13:22:59 +0000523 /* restore flags in standard format */
thsecb644f2007-06-03 18:45:53 +0000524 regs_to_env();
525#if defined(TARGET_I386)
pbrooka7812ae2008-11-17 14:43:54 +0000526 env->eflags = env->eflags | helper_cc_compute_all(CC_OP) | (DF & DF_MASK);
bellard7fe48482004-10-09 18:08:01 +0000527 cpu_dump_state(env, logfile, fprintf, X86_DUMP_CCOP);
bellard3fb2ded2003-06-24 13:22:59 +0000528 env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
bellarde4533c72003-06-15 19:51:39 +0000529#elif defined(TARGET_ARM)
bellard7fe48482004-10-09 18:08:01 +0000530 cpu_dump_state(env, logfile, fprintf, 0);
bellard93ac68b2003-09-30 20:57:29 +0000531#elif defined(TARGET_SPARC)
bellard34751872005-07-02 14:31:34 +0000532 cpu_dump_state(env, logfile, fprintf, 0);
bellard67867302003-11-23 17:05:30 +0000533#elif defined(TARGET_PPC)
bellard7fe48482004-10-09 18:08:01 +0000534 cpu_dump_state(env, logfile, fprintf, 0);
pbrooke6e59062006-10-22 00:18:54 +0000535#elif defined(TARGET_M68K)
536 cpu_m68k_flush_flags(env, env->cc_op);
537 env->cc_op = CC_OP_FLAGS;
538 env->sr = (env->sr & 0xffe0)
539 | env->cc_dest | (env->cc_x << 4);
540 cpu_dump_state(env, logfile, fprintf, 0);
bellard6af0bf92005-07-02 14:58:51 +0000541#elif defined(TARGET_MIPS)
542 cpu_dump_state(env, logfile, fprintf, 0);
bellardfdf9b3e2006-04-27 21:07:38 +0000543#elif defined(TARGET_SH4)
544 cpu_dump_state(env, logfile, fprintf, 0);
j_mayereddf68a2007-04-05 07:22:49 +0000545#elif defined(TARGET_ALPHA)
546 cpu_dump_state(env, logfile, fprintf, 0);
thsf1ccf902007-10-08 13:16:14 +0000547#elif defined(TARGET_CRIS)
548 cpu_dump_state(env, logfile, fprintf, 0);
bellarde4533c72003-06-15 19:51:39 +0000549#else
ths5fafdf22007-09-16 21:08:06 +0000550#error unsupported target CPU
bellarde4533c72003-06-15 19:51:39 +0000551#endif
bellard3fb2ded2003-06-24 13:22:59 +0000552 }
bellard7d132992003-03-06 23:23:54 +0000553#endif
pbrookd5975362008-06-07 20:50:51 +0000554 spin_lock(&tb_lock);
bellard8a40a182005-11-20 10:35:40 +0000555 tb = tb_find_fast();
pbrookd5975362008-06-07 20:50:51 +0000556 /* Note: we do it here to avoid a gcc bug on Mac OS X when
557 doing it in tb_find_slow */
558 if (tb_invalidated_flag) {
559 /* as some TB could have been invalidated because
560 of memory exceptions while generating the code, we
561 must recompute the hash index here */
562 next_tb = 0;
pbrook2e70f6e2008-06-29 01:03:05 +0000563 tb_invalidated_flag = 0;
pbrookd5975362008-06-07 20:50:51 +0000564 }
bellard9d27abd2003-05-10 13:13:54 +0000565#ifdef DEBUG_EXEC
bellardc1135f62005-01-30 22:41:54 +0000566 if ((loglevel & CPU_LOG_EXEC)) {
bellardc27004e2005-01-03 23:35:10 +0000567 fprintf(logfile, "Trace 0x%08lx [" TARGET_FMT_lx "] %s\n",
568 (long)tb->tc_ptr, tb->pc,
569 lookup_symbol(tb->pc));
bellard3fb2ded2003-06-24 13:22:59 +0000570 }
bellard9d27abd2003-05-10 13:13:54 +0000571#endif
bellard8a40a182005-11-20 10:35:40 +0000572 /* see if we can patch the calling TB. When the TB
573 spans two pages, we cannot safely do a direct
574 jump. */
bellardc27004e2005-01-03 23:35:10 +0000575 {
blueswir1b5fc09a2008-05-04 06:38:18 +0000576 if (next_tb != 0 &&
blueswir14d7a0882008-05-10 10:14:22 +0000577#ifdef USE_KQEMU
bellardf32fc642006-02-08 22:43:39 +0000578 (env->kqemu_enabled != 2) &&
579#endif
bellardec6338b2007-11-08 14:25:03 +0000580 tb->page_addr[1] == -1) {
blueswir1b5fc09a2008-05-04 06:38:18 +0000581 tb_add_jump((TranslationBlock *)(next_tb & ~3), next_tb & 3, tb);
bellard3fb2ded2003-06-24 13:22:59 +0000582 }
bellardc27004e2005-01-03 23:35:10 +0000583 }
pbrookd5975362008-06-07 20:50:51 +0000584 spin_unlock(&tb_lock);
bellard83479e72003-06-25 16:12:37 +0000585 env->current_tb = tb;
malc55e8b852008-11-04 14:18:13 +0000586
587 /* cpu_interrupt might be called while translating the
588 TB, but before it is linked into a potentially
589 infinite loop and becomes env->current_tb. Avoid
590 starting execution if there is a pending interrupt. */
591 if (unlikely (env->interrupt_request & CPU_INTERRUPT_EXIT))
592 env->current_tb = NULL;
593
pbrook2e70f6e2008-06-29 01:03:05 +0000594 while (env->current_tb) {
595 tc_ptr = tb->tc_ptr;
bellard3fb2ded2003-06-24 13:22:59 +0000596 /* execute the generated code */
blueswir1572a9d42008-05-17 07:38:10 +0000597#if defined(__sparc__) && !defined(HOST_SOLARIS)
598#undef env
pbrook2e70f6e2008-06-29 01:03:05 +0000599 env = cpu_single_env;
blueswir1572a9d42008-05-17 07:38:10 +0000600#define env cpu_single_env
601#endif
pbrook2e70f6e2008-06-29 01:03:05 +0000602 next_tb = tcg_qemu_tb_exec(tc_ptr);
603 env->current_tb = NULL;
604 if ((next_tb & 3) == 2) {
thsbf20dc02008-06-30 17:22:19 +0000605 /* Instruction counter expired. */
pbrook2e70f6e2008-06-29 01:03:05 +0000606 int insns_left;
607 tb = (TranslationBlock *)(long)(next_tb & ~3);
608 /* Restore PC. */
aliguori622ed362008-11-18 19:36:03 +0000609 cpu_pc_from_tb(env, tb);
pbrook2e70f6e2008-06-29 01:03:05 +0000610 insns_left = env->icount_decr.u32;
611 if (env->icount_extra && insns_left >= 0) {
612 /* Refill decrementer and continue execution. */
613 env->icount_extra += insns_left;
614 if (env->icount_extra > 0xffff) {
615 insns_left = 0xffff;
616 } else {
617 insns_left = env->icount_extra;
618 }
619 env->icount_extra -= insns_left;
620 env->icount_decr.u16.low = insns_left;
621 } else {
622 if (insns_left > 0) {
623 /* Execute remaining instructions. */
624 cpu_exec_nocache(insns_left, tb);
625 }
626 env->exception_index = EXCP_INTERRUPT;
627 next_tb = 0;
628 cpu_loop_exit();
629 }
630 }
631 }
bellard4cbf74b2003-08-10 21:48:43 +0000632 /* reset soft MMU for next block (it can currently
633 only be set by a memory fault) */
bellardf32fc642006-02-08 22:43:39 +0000634#if defined(USE_KQEMU)
635#define MIN_CYCLE_BEFORE_SWITCH (100 * 1000)
636 if (kqemu_is_ok(env) &&
637 (cpu_get_time_fast() - env->last_io_time) >= MIN_CYCLE_BEFORE_SWITCH) {
638 cpu_loop_exit();
639 }
640#endif
ths50a518e2007-06-03 18:52:15 +0000641 } /* for(;;) */
bellard3fb2ded2003-06-24 13:22:59 +0000642 } else {
bellard0d1a29f2004-10-12 22:01:28 +0000643 env_to_regs();
bellard7d132992003-03-06 23:23:54 +0000644 }
bellard3fb2ded2003-06-24 13:22:59 +0000645 } /* for(;;) */
646
bellard7d132992003-03-06 23:23:54 +0000647
bellarde4533c72003-06-15 19:51:39 +0000648#if defined(TARGET_I386)
bellard9de5e442003-03-23 16:49:39 +0000649 /* restore flags in standard format */
pbrooka7812ae2008-11-17 14:43:54 +0000650 env->eflags = env->eflags | helper_cc_compute_all(CC_OP) | (DF & DF_MASK);
bellarde4533c72003-06-15 19:51:39 +0000651#elif defined(TARGET_ARM)
bellardb7bcbe92005-02-22 19:27:29 +0000652 /* XXX: Save/restore host fpu exception state?. */
bellard93ac68b2003-09-30 20:57:29 +0000653#elif defined(TARGET_SPARC)
bellard67867302003-11-23 17:05:30 +0000654#elif defined(TARGET_PPC)
pbrooke6e59062006-10-22 00:18:54 +0000655#elif defined(TARGET_M68K)
656 cpu_m68k_flush_flags(env, env->cc_op);
657 env->cc_op = CC_OP_FLAGS;
658 env->sr = (env->sr & 0xffe0)
659 | env->cc_dest | (env->cc_x << 4);
bellard6af0bf92005-07-02 14:58:51 +0000660#elif defined(TARGET_MIPS)
bellardfdf9b3e2006-04-27 21:07:38 +0000661#elif defined(TARGET_SH4)
j_mayereddf68a2007-04-05 07:22:49 +0000662#elif defined(TARGET_ALPHA)
thsf1ccf902007-10-08 13:16:14 +0000663#elif defined(TARGET_CRIS)
bellardfdf9b3e2006-04-27 21:07:38 +0000664 /* XXXXX */
bellarde4533c72003-06-15 19:51:39 +0000665#else
666#error unsupported target CPU
667#endif
pbrook1057eaa2007-02-04 13:37:44 +0000668
669 /* restore global registers */
pbrook1057eaa2007-02-04 13:37:44 +0000670#include "hostregs_helper.h"
671
bellard6a00d602005-11-21 23:25:50 +0000672 /* fail safe : never use cpu_single_env outside cpu_exec() */
ths5fafdf22007-09-16 21:08:06 +0000673 cpu_single_env = NULL;
bellard7d132992003-03-06 23:23:54 +0000674 return ret;
675}
bellard6dbad632003-03-16 18:05:05 +0000676
bellardfbf9eeb2004-04-25 21:21:33 +0000677/* must only be called from the generated code as an exception can be
678 generated */
679void tb_invalidate_page_range(target_ulong start, target_ulong end)
680{
bellarddc5d0b32004-06-22 18:43:30 +0000681 /* XXX: cannot enable it yet because it yields to MMU exception
682 where NIP != read address on PowerPC */
683#if 0
bellardfbf9eeb2004-04-25 21:21:33 +0000684 target_ulong phys_addr;
685 phys_addr = get_phys_addr_code(env, start);
686 tb_invalidate_phys_page_range(phys_addr, phys_addr + end - start, 0);
bellarddc5d0b32004-06-22 18:43:30 +0000687#endif
bellardfbf9eeb2004-04-25 21:21:33 +0000688}
689
bellard1a18c712003-10-30 01:07:51 +0000690#if defined(TARGET_I386) && defined(CONFIG_USER_ONLY)
bellarde4533c72003-06-15 19:51:39 +0000691
bellard6dbad632003-03-16 18:05:05 +0000692void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector)
693{
694 CPUX86State *saved_env;
695
696 saved_env = env;
697 env = s;
bellarda412ac52003-07-26 18:01:40 +0000698 if (!(env->cr[0] & CR0_PE_MASK) || (env->eflags & VM_MASK)) {
bellarda513fe12003-05-27 23:29:48 +0000699 selector &= 0xffff;
ths5fafdf22007-09-16 21:08:06 +0000700 cpu_x86_load_seg_cache(env, seg_reg, selector,
bellardc27004e2005-01-03 23:35:10 +0000701 (selector << 4), 0xffff, 0);
bellarda513fe12003-05-27 23:29:48 +0000702 } else {
bellard5d975592008-05-12 22:05:33 +0000703 helper_load_seg(seg_reg, selector);
bellarda513fe12003-05-27 23:29:48 +0000704 }
bellard6dbad632003-03-16 18:05:05 +0000705 env = saved_env;
706}
bellard9de5e442003-03-23 16:49:39 +0000707
bellard6f12a2a2007-11-11 22:16:56 +0000708void cpu_x86_fsave(CPUX86State *s, target_ulong ptr, int data32)
bellardd0a1ffc2003-05-29 20:04:28 +0000709{
710 CPUX86State *saved_env;
711
712 saved_env = env;
713 env = s;
ths3b46e622007-09-17 08:09:54 +0000714
bellard6f12a2a2007-11-11 22:16:56 +0000715 helper_fsave(ptr, data32);
bellardd0a1ffc2003-05-29 20:04:28 +0000716
717 env = saved_env;
718}
719
bellard6f12a2a2007-11-11 22:16:56 +0000720void cpu_x86_frstor(CPUX86State *s, target_ulong ptr, int data32)
bellardd0a1ffc2003-05-29 20:04:28 +0000721{
722 CPUX86State *saved_env;
723
724 saved_env = env;
725 env = s;
ths3b46e622007-09-17 08:09:54 +0000726
bellard6f12a2a2007-11-11 22:16:56 +0000727 helper_frstor(ptr, data32);
bellardd0a1ffc2003-05-29 20:04:28 +0000728
729 env = saved_env;
730}
731
bellarde4533c72003-06-15 19:51:39 +0000732#endif /* TARGET_I386 */
733
bellard67b915a2004-03-31 23:37:16 +0000734#if !defined(CONFIG_SOFTMMU)
735
bellard3fb2ded2003-06-24 13:22:59 +0000736#if defined(TARGET_I386)
737
bellardb56dad12003-05-08 15:38:04 +0000738/* 'pc' is the host PC at which the exception was raised. 'address' is
bellardfd6ce8f2003-05-14 19:00:11 +0000739 the effective address of the memory exception. 'is_write' is 1 if a
740 write caused the exception and otherwise 0'. 'old_set' is the
741 signal set which should be restored */
bellard2b413142003-05-14 23:01:10 +0000742static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
ths5fafdf22007-09-16 21:08:06 +0000743 int is_write, sigset_t *old_set,
bellardbf3e8bf2004-02-16 21:58:54 +0000744 void *puc)
bellard9de5e442003-03-23 16:49:39 +0000745{
bellarda513fe12003-05-27 23:29:48 +0000746 TranslationBlock *tb;
747 int ret;
bellard68a79312003-06-30 13:12:32 +0000748
bellard83479e72003-06-25 16:12:37 +0000749 if (cpu_single_env)
750 env = cpu_single_env; /* XXX: find a correct solution for multithread */
bellardfd6ce8f2003-05-14 19:00:11 +0000751#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000752 qemu_printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellardbf3e8bf2004-02-16 21:58:54 +0000753 pc, address, is_write, *(unsigned long *)old_set);
bellard9de5e442003-03-23 16:49:39 +0000754#endif
bellard25eb4482003-05-14 21:50:54 +0000755 /* XXX: locking issue */
pbrook53a59602006-03-25 19:31:22 +0000756 if (is_write && page_unprotect(h2g(address), pc, puc)) {
bellardfd6ce8f2003-05-14 19:00:11 +0000757 return 1;
758 }
bellardfbf9eeb2004-04-25 21:21:33 +0000759
bellard3fb2ded2003-06-24 13:22:59 +0000760 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +0000761 ret = cpu_x86_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellard3fb2ded2003-06-24 13:22:59 +0000762 if (ret < 0)
763 return 0; /* not an MMU fault */
764 if (ret == 0)
765 return 1; /* the MMU fault was handled without causing real CPU fault */
766 /* now we have a real cpu fault */
bellarda513fe12003-05-27 23:29:48 +0000767 tb = tb_find_pc(pc);
768 if (tb) {
bellard9de5e442003-03-23 16:49:39 +0000769 /* the PC is inside the translated code. It means that we have
770 a virtual CPU fault */
bellardbf3e8bf2004-02-16 21:58:54 +0000771 cpu_restore_state(tb, env, pc, puc);
bellard3fb2ded2003-06-24 13:22:59 +0000772 }
bellard4cbf74b2003-08-10 21:48:43 +0000773 if (ret == 1) {
bellard3fb2ded2003-06-24 13:22:59 +0000774#if 0
ths5fafdf22007-09-16 21:08:06 +0000775 printf("PF exception: EIP=0x%08x CR2=0x%08x error=0x%x\n",
bellard4cbf74b2003-08-10 21:48:43 +0000776 env->eip, env->cr[2], env->error_code);
bellard3fb2ded2003-06-24 13:22:59 +0000777#endif
bellard4cbf74b2003-08-10 21:48:43 +0000778 /* we restore the process signal mask as the sigreturn should
779 do it (XXX: use sigsetjmp) */
780 sigprocmask(SIG_SETMASK, old_set, NULL);
bellard54ca9092005-12-04 18:46:06 +0000781 raise_exception_err(env->exception_index, env->error_code);
bellard4cbf74b2003-08-10 21:48:43 +0000782 } else {
783 /* activate soft MMU for this block */
bellard3f337312003-08-20 23:02:09 +0000784 env->hflags |= HF_SOFTMMU_MASK;
bellardfbf9eeb2004-04-25 21:21:33 +0000785 cpu_resume_from_signal(env, puc);
bellard4cbf74b2003-08-10 21:48:43 +0000786 }
bellard3fb2ded2003-06-24 13:22:59 +0000787 /* never comes here */
788 return 1;
789}
790
bellarde4533c72003-06-15 19:51:39 +0000791#elif defined(TARGET_ARM)
bellard3fb2ded2003-06-24 13:22:59 +0000792static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
bellardbf3e8bf2004-02-16 21:58:54 +0000793 int is_write, sigset_t *old_set,
794 void *puc)
bellard3fb2ded2003-06-24 13:22:59 +0000795{
bellard68016c62005-02-07 23:12:27 +0000796 TranslationBlock *tb;
797 int ret;
798
799 if (cpu_single_env)
800 env = cpu_single_env; /* XXX: find a correct solution for multithread */
801#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000802 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellard68016c62005-02-07 23:12:27 +0000803 pc, address, is_write, *(unsigned long *)old_set);
804#endif
bellard9f0777e2005-02-02 20:42:01 +0000805 /* XXX: locking issue */
pbrook53a59602006-03-25 19:31:22 +0000806 if (is_write && page_unprotect(h2g(address), pc, puc)) {
bellard9f0777e2005-02-02 20:42:01 +0000807 return 1;
808 }
bellard68016c62005-02-07 23:12:27 +0000809 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +0000810 ret = cpu_arm_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellard68016c62005-02-07 23:12:27 +0000811 if (ret < 0)
812 return 0; /* not an MMU fault */
813 if (ret == 0)
814 return 1; /* the MMU fault was handled without causing real CPU fault */
815 /* now we have a real cpu fault */
816 tb = tb_find_pc(pc);
817 if (tb) {
818 /* the PC is inside the translated code. It means that we have
819 a virtual CPU fault */
820 cpu_restore_state(tb, env, pc, puc);
821 }
822 /* we restore the process signal mask as the sigreturn should
823 do it (XXX: use sigsetjmp) */
824 sigprocmask(SIG_SETMASK, old_set, NULL);
825 cpu_loop_exit();
aurel32968c74d2008-04-11 04:55:17 +0000826 /* never comes here */
827 return 1;
bellard3fb2ded2003-06-24 13:22:59 +0000828}
bellard93ac68b2003-09-30 20:57:29 +0000829#elif defined(TARGET_SPARC)
830static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
bellardbf3e8bf2004-02-16 21:58:54 +0000831 int is_write, sigset_t *old_set,
832 void *puc)
bellard93ac68b2003-09-30 20:57:29 +0000833{
bellard68016c62005-02-07 23:12:27 +0000834 TranslationBlock *tb;
835 int ret;
836
837 if (cpu_single_env)
838 env = cpu_single_env; /* XXX: find a correct solution for multithread */
839#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000840 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellard68016c62005-02-07 23:12:27 +0000841 pc, address, is_write, *(unsigned long *)old_set);
842#endif
bellardb453b702004-01-04 15:45:21 +0000843 /* XXX: locking issue */
pbrook53a59602006-03-25 19:31:22 +0000844 if (is_write && page_unprotect(h2g(address), pc, puc)) {
bellardb453b702004-01-04 15:45:21 +0000845 return 1;
846 }
bellard68016c62005-02-07 23:12:27 +0000847 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +0000848 ret = cpu_sparc_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellard68016c62005-02-07 23:12:27 +0000849 if (ret < 0)
850 return 0; /* not an MMU fault */
851 if (ret == 0)
852 return 1; /* the MMU fault was handled without causing real CPU fault */
853 /* now we have a real cpu fault */
854 tb = tb_find_pc(pc);
855 if (tb) {
856 /* the PC is inside the translated code. It means that we have
857 a virtual CPU fault */
858 cpu_restore_state(tb, env, pc, puc);
859 }
860 /* we restore the process signal mask as the sigreturn should
861 do it (XXX: use sigsetjmp) */
862 sigprocmask(SIG_SETMASK, old_set, NULL);
863 cpu_loop_exit();
aurel32968c74d2008-04-11 04:55:17 +0000864 /* never comes here */
865 return 1;
bellard93ac68b2003-09-30 20:57:29 +0000866}
bellard67867302003-11-23 17:05:30 +0000867#elif defined (TARGET_PPC)
868static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
bellardbf3e8bf2004-02-16 21:58:54 +0000869 int is_write, sigset_t *old_set,
870 void *puc)
bellard67867302003-11-23 17:05:30 +0000871{
872 TranslationBlock *tb;
bellardce097762004-01-04 23:53:18 +0000873 int ret;
ths3b46e622007-09-17 08:09:54 +0000874
bellard67867302003-11-23 17:05:30 +0000875 if (cpu_single_env)
876 env = cpu_single_env; /* XXX: find a correct solution for multithread */
bellard67867302003-11-23 17:05:30 +0000877#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000878 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellard67867302003-11-23 17:05:30 +0000879 pc, address, is_write, *(unsigned long *)old_set);
880#endif
881 /* XXX: locking issue */
pbrook53a59602006-03-25 19:31:22 +0000882 if (is_write && page_unprotect(h2g(address), pc, puc)) {
bellard67867302003-11-23 17:05:30 +0000883 return 1;
884 }
885
bellardce097762004-01-04 23:53:18 +0000886 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +0000887 ret = cpu_ppc_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellardce097762004-01-04 23:53:18 +0000888 if (ret < 0)
889 return 0; /* not an MMU fault */
890 if (ret == 0)
891 return 1; /* the MMU fault was handled without causing real CPU fault */
892
bellard67867302003-11-23 17:05:30 +0000893 /* now we have a real cpu fault */
894 tb = tb_find_pc(pc);
895 if (tb) {
896 /* the PC is inside the translated code. It means that we have
897 a virtual CPU fault */
bellardbf3e8bf2004-02-16 21:58:54 +0000898 cpu_restore_state(tb, env, pc, puc);
bellard67867302003-11-23 17:05:30 +0000899 }
bellardce097762004-01-04 23:53:18 +0000900 if (ret == 1) {
bellard67867302003-11-23 17:05:30 +0000901#if 0
ths5fafdf22007-09-16 21:08:06 +0000902 printf("PF exception: NIP=0x%08x error=0x%x %p\n",
bellardce097762004-01-04 23:53:18 +0000903 env->nip, env->error_code, tb);
bellard67867302003-11-23 17:05:30 +0000904#endif
905 /* we restore the process signal mask as the sigreturn should
906 do it (XXX: use sigsetjmp) */
bellardbf3e8bf2004-02-16 21:58:54 +0000907 sigprocmask(SIG_SETMASK, old_set, NULL);
bellard9fddaa02004-05-21 12:59:32 +0000908 do_raise_exception_err(env->exception_index, env->error_code);
bellardce097762004-01-04 23:53:18 +0000909 } else {
910 /* activate soft MMU for this block */
bellardfbf9eeb2004-04-25 21:21:33 +0000911 cpu_resume_from_signal(env, puc);
bellardce097762004-01-04 23:53:18 +0000912 }
bellard67867302003-11-23 17:05:30 +0000913 /* never comes here */
914 return 1;
915}
bellard6af0bf92005-07-02 14:58:51 +0000916
pbrooke6e59062006-10-22 00:18:54 +0000917#elif defined(TARGET_M68K)
918static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
919 int is_write, sigset_t *old_set,
920 void *puc)
921{
922 TranslationBlock *tb;
923 int ret;
924
925 if (cpu_single_env)
926 env = cpu_single_env; /* XXX: find a correct solution for multithread */
927#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000928 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
pbrooke6e59062006-10-22 00:18:54 +0000929 pc, address, is_write, *(unsigned long *)old_set);
930#endif
931 /* XXX: locking issue */
932 if (is_write && page_unprotect(address, pc, puc)) {
933 return 1;
934 }
935 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +0000936 ret = cpu_m68k_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
pbrooke6e59062006-10-22 00:18:54 +0000937 if (ret < 0)
938 return 0; /* not an MMU fault */
939 if (ret == 0)
940 return 1; /* the MMU fault was handled without causing real CPU fault */
941 /* now we have a real cpu fault */
942 tb = tb_find_pc(pc);
943 if (tb) {
944 /* the PC is inside the translated code. It means that we have
945 a virtual CPU fault */
946 cpu_restore_state(tb, env, pc, puc);
947 }
948 /* we restore the process signal mask as the sigreturn should
949 do it (XXX: use sigsetjmp) */
950 sigprocmask(SIG_SETMASK, old_set, NULL);
951 cpu_loop_exit();
952 /* never comes here */
953 return 1;
954}
955
bellard6af0bf92005-07-02 14:58:51 +0000956#elif defined (TARGET_MIPS)
957static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
958 int is_write, sigset_t *old_set,
959 void *puc)
960{
961 TranslationBlock *tb;
962 int ret;
ths3b46e622007-09-17 08:09:54 +0000963
bellard6af0bf92005-07-02 14:58:51 +0000964 if (cpu_single_env)
965 env = cpu_single_env; /* XXX: find a correct solution for multithread */
966#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000967 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellard6af0bf92005-07-02 14:58:51 +0000968 pc, address, is_write, *(unsigned long *)old_set);
969#endif
970 /* XXX: locking issue */
pbrook53a59602006-03-25 19:31:22 +0000971 if (is_write && page_unprotect(h2g(address), pc, puc)) {
bellard6af0bf92005-07-02 14:58:51 +0000972 return 1;
973 }
974
975 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +0000976 ret = cpu_mips_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellard6af0bf92005-07-02 14:58:51 +0000977 if (ret < 0)
978 return 0; /* not an MMU fault */
979 if (ret == 0)
980 return 1; /* the MMU fault was handled without causing real CPU fault */
981
982 /* now we have a real cpu fault */
983 tb = tb_find_pc(pc);
984 if (tb) {
985 /* the PC is inside the translated code. It means that we have
986 a virtual CPU fault */
987 cpu_restore_state(tb, env, pc, puc);
988 }
989 if (ret == 1) {
990#if 0
ths5fafdf22007-09-16 21:08:06 +0000991 printf("PF exception: PC=0x" TARGET_FMT_lx " error=0x%x %p\n",
ths1eb52072007-05-12 16:57:42 +0000992 env->PC, env->error_code, tb);
bellard6af0bf92005-07-02 14:58:51 +0000993#endif
994 /* we restore the process signal mask as the sigreturn should
995 do it (XXX: use sigsetjmp) */
996 sigprocmask(SIG_SETMASK, old_set, NULL);
997 do_raise_exception_err(env->exception_index, env->error_code);
998 } else {
999 /* activate soft MMU for this block */
1000 cpu_resume_from_signal(env, puc);
1001 }
1002 /* never comes here */
1003 return 1;
1004}
1005
bellardfdf9b3e2006-04-27 21:07:38 +00001006#elif defined (TARGET_SH4)
1007static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
1008 int is_write, sigset_t *old_set,
1009 void *puc)
1010{
1011 TranslationBlock *tb;
1012 int ret;
ths3b46e622007-09-17 08:09:54 +00001013
bellardfdf9b3e2006-04-27 21:07:38 +00001014 if (cpu_single_env)
1015 env = cpu_single_env; /* XXX: find a correct solution for multithread */
1016#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +00001017 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellardfdf9b3e2006-04-27 21:07:38 +00001018 pc, address, is_write, *(unsigned long *)old_set);
1019#endif
1020 /* XXX: locking issue */
1021 if (is_write && page_unprotect(h2g(address), pc, puc)) {
1022 return 1;
1023 }
1024
1025 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +00001026 ret = cpu_sh4_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellardfdf9b3e2006-04-27 21:07:38 +00001027 if (ret < 0)
1028 return 0; /* not an MMU fault */
1029 if (ret == 0)
1030 return 1; /* the MMU fault was handled without causing real CPU fault */
1031
1032 /* now we have a real cpu fault */
1033 tb = tb_find_pc(pc);
1034 if (tb) {
1035 /* the PC is inside the translated code. It means that we have
1036 a virtual CPU fault */
1037 cpu_restore_state(tb, env, pc, puc);
1038 }
bellardfdf9b3e2006-04-27 21:07:38 +00001039#if 0
ths5fafdf22007-09-16 21:08:06 +00001040 printf("PF exception: NIP=0x%08x error=0x%x %p\n",
bellardfdf9b3e2006-04-27 21:07:38 +00001041 env->nip, env->error_code, tb);
1042#endif
1043 /* we restore the process signal mask as the sigreturn should
1044 do it (XXX: use sigsetjmp) */
pbrook355fb232006-06-17 19:58:25 +00001045 sigprocmask(SIG_SETMASK, old_set, NULL);
1046 cpu_loop_exit();
bellardfdf9b3e2006-04-27 21:07:38 +00001047 /* never comes here */
1048 return 1;
1049}
j_mayereddf68a2007-04-05 07:22:49 +00001050
1051#elif defined (TARGET_ALPHA)
1052static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
1053 int is_write, sigset_t *old_set,
1054 void *puc)
1055{
1056 TranslationBlock *tb;
1057 int ret;
ths3b46e622007-09-17 08:09:54 +00001058
j_mayereddf68a2007-04-05 07:22:49 +00001059 if (cpu_single_env)
1060 env = cpu_single_env; /* XXX: find a correct solution for multithread */
1061#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +00001062 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
j_mayereddf68a2007-04-05 07:22:49 +00001063 pc, address, is_write, *(unsigned long *)old_set);
1064#endif
1065 /* XXX: locking issue */
1066 if (is_write && page_unprotect(h2g(address), pc, puc)) {
1067 return 1;
1068 }
1069
1070 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +00001071 ret = cpu_alpha_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
j_mayereddf68a2007-04-05 07:22:49 +00001072 if (ret < 0)
1073 return 0; /* not an MMU fault */
1074 if (ret == 0)
1075 return 1; /* the MMU fault was handled without causing real CPU fault */
1076
1077 /* now we have a real cpu fault */
1078 tb = tb_find_pc(pc);
1079 if (tb) {
1080 /* the PC is inside the translated code. It means that we have
1081 a virtual CPU fault */
1082 cpu_restore_state(tb, env, pc, puc);
1083 }
1084#if 0
ths5fafdf22007-09-16 21:08:06 +00001085 printf("PF exception: NIP=0x%08x error=0x%x %p\n",
j_mayereddf68a2007-04-05 07:22:49 +00001086 env->nip, env->error_code, tb);
1087#endif
1088 /* we restore the process signal mask as the sigreturn should
1089 do it (XXX: use sigsetjmp) */
1090 sigprocmask(SIG_SETMASK, old_set, NULL);
1091 cpu_loop_exit();
1092 /* never comes here */
1093 return 1;
1094}
thsf1ccf902007-10-08 13:16:14 +00001095#elif defined (TARGET_CRIS)
1096static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
1097 int is_write, sigset_t *old_set,
1098 void *puc)
1099{
1100 TranslationBlock *tb;
1101 int ret;
1102
1103 if (cpu_single_env)
1104 env = cpu_single_env; /* XXX: find a correct solution for multithread */
1105#if defined(DEBUG_SIGNAL)
1106 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
1107 pc, address, is_write, *(unsigned long *)old_set);
1108#endif
1109 /* XXX: locking issue */
1110 if (is_write && page_unprotect(h2g(address), pc, puc)) {
1111 return 1;
1112 }
1113
1114 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +00001115 ret = cpu_cris_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
thsf1ccf902007-10-08 13:16:14 +00001116 if (ret < 0)
1117 return 0; /* not an MMU fault */
1118 if (ret == 0)
1119 return 1; /* the MMU fault was handled without causing real CPU fault */
1120
1121 /* now we have a real cpu fault */
1122 tb = tb_find_pc(pc);
1123 if (tb) {
1124 /* the PC is inside the translated code. It means that we have
1125 a virtual CPU fault */
1126 cpu_restore_state(tb, env, pc, puc);
1127 }
thsf1ccf902007-10-08 13:16:14 +00001128 /* we restore the process signal mask as the sigreturn should
1129 do it (XXX: use sigsetjmp) */
1130 sigprocmask(SIG_SETMASK, old_set, NULL);
1131 cpu_loop_exit();
1132 /* never comes here */
1133 return 1;
1134}
1135
bellarde4533c72003-06-15 19:51:39 +00001136#else
1137#error unsupported target CPU
1138#endif
bellard9de5e442003-03-23 16:49:39 +00001139
bellard2b413142003-05-14 23:01:10 +00001140#if defined(__i386__)
1141
bellardd8ecc0b2007-02-05 21:41:46 +00001142#if defined(__APPLE__)
1143# include <sys/ucontext.h>
1144
1145# define EIP_sig(context) (*((unsigned long*)&(context)->uc_mcontext->ss.eip))
1146# define TRAP_sig(context) ((context)->uc_mcontext->es.trapno)
1147# define ERROR_sig(context) ((context)->uc_mcontext->es.err)
1148#else
1149# define EIP_sig(context) ((context)->uc_mcontext.gregs[REG_EIP])
1150# define TRAP_sig(context) ((context)->uc_mcontext.gregs[REG_TRAPNO])
1151# define ERROR_sig(context) ((context)->uc_mcontext.gregs[REG_ERR])
1152#endif
1153
ths5fafdf22007-09-16 21:08:06 +00001154int cpu_signal_handler(int host_signum, void *pinfo,
bellarde4533c72003-06-15 19:51:39 +00001155 void *puc)
bellard9de5e442003-03-23 16:49:39 +00001156{
ths5a7b5422007-01-31 12:16:51 +00001157 siginfo_t *info = pinfo;
bellard9de5e442003-03-23 16:49:39 +00001158 struct ucontext *uc = puc;
1159 unsigned long pc;
bellardbf3e8bf2004-02-16 21:58:54 +00001160 int trapno;
bellard97eb5b12004-02-25 23:19:55 +00001161
bellardd691f662003-03-24 21:58:34 +00001162#ifndef REG_EIP
1163/* for glibc 2.1 */
bellardfd6ce8f2003-05-14 19:00:11 +00001164#define REG_EIP EIP
1165#define REG_ERR ERR
1166#define REG_TRAPNO TRAPNO
bellardd691f662003-03-24 21:58:34 +00001167#endif
bellardd8ecc0b2007-02-05 21:41:46 +00001168 pc = EIP_sig(uc);
1169 trapno = TRAP_sig(uc);
bellardec6338b2007-11-08 14:25:03 +00001170 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1171 trapno == 0xe ?
1172 (ERROR_sig(uc) >> 1) & 1 : 0,
1173 &uc->uc_sigmask, puc);
bellard2b413142003-05-14 23:01:10 +00001174}
1175
bellardbc51c5c2004-03-17 23:46:04 +00001176#elif defined(__x86_64__)
1177
ths5a7b5422007-01-31 12:16:51 +00001178int cpu_signal_handler(int host_signum, void *pinfo,
bellardbc51c5c2004-03-17 23:46:04 +00001179 void *puc)
1180{
ths5a7b5422007-01-31 12:16:51 +00001181 siginfo_t *info = pinfo;
bellardbc51c5c2004-03-17 23:46:04 +00001182 struct ucontext *uc = puc;
1183 unsigned long pc;
1184
1185 pc = uc->uc_mcontext.gregs[REG_RIP];
ths5fafdf22007-09-16 21:08:06 +00001186 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1187 uc->uc_mcontext.gregs[REG_TRAPNO] == 0xe ?
bellardbc51c5c2004-03-17 23:46:04 +00001188 (uc->uc_mcontext.gregs[REG_ERR] >> 1) & 1 : 0,
1189 &uc->uc_sigmask, puc);
1190}
1191
bellard83fb7ad2004-07-05 21:25:26 +00001192#elif defined(__powerpc__)
bellard2b413142003-05-14 23:01:10 +00001193
bellard83fb7ad2004-07-05 21:25:26 +00001194/***********************************************************************
1195 * signal context platform-specific definitions
1196 * From Wine
1197 */
1198#ifdef linux
1199/* All Registers access - only for local access */
1200# define REG_sig(reg_name, context) ((context)->uc_mcontext.regs->reg_name)
1201/* Gpr Registers access */
1202# define GPR_sig(reg_num, context) REG_sig(gpr[reg_num], context)
1203# define IAR_sig(context) REG_sig(nip, context) /* Program counter */
1204# define MSR_sig(context) REG_sig(msr, context) /* Machine State Register (Supervisor) */
1205# define CTR_sig(context) REG_sig(ctr, context) /* Count register */
1206# define XER_sig(context) REG_sig(xer, context) /* User's integer exception register */
1207# define LR_sig(context) REG_sig(link, context) /* Link register */
1208# define CR_sig(context) REG_sig(ccr, context) /* Condition register */
1209/* Float Registers access */
1210# define FLOAT_sig(reg_num, context) (((double*)((char*)((context)->uc_mcontext.regs+48*4)))[reg_num])
1211# define FPSCR_sig(context) (*(int*)((char*)((context)->uc_mcontext.regs+(48+32*2)*4)))
1212/* Exception Registers access */
1213# define DAR_sig(context) REG_sig(dar, context)
1214# define DSISR_sig(context) REG_sig(dsisr, context)
1215# define TRAP_sig(context) REG_sig(trap, context)
1216#endif /* linux */
1217
1218#ifdef __APPLE__
1219# include <sys/ucontext.h>
1220typedef struct ucontext SIGCONTEXT;
1221/* All Registers access - only for local access */
1222# define REG_sig(reg_name, context) ((context)->uc_mcontext->ss.reg_name)
1223# define FLOATREG_sig(reg_name, context) ((context)->uc_mcontext->fs.reg_name)
1224# define EXCEPREG_sig(reg_name, context) ((context)->uc_mcontext->es.reg_name)
1225# define VECREG_sig(reg_name, context) ((context)->uc_mcontext->vs.reg_name)
1226/* Gpr Registers access */
1227# define GPR_sig(reg_num, context) REG_sig(r##reg_num, context)
1228# define IAR_sig(context) REG_sig(srr0, context) /* Program counter */
1229# define MSR_sig(context) REG_sig(srr1, context) /* Machine State Register (Supervisor) */
1230# define CTR_sig(context) REG_sig(ctr, context)
1231# define XER_sig(context) REG_sig(xer, context) /* Link register */
1232# define LR_sig(context) REG_sig(lr, context) /* User's integer exception register */
1233# define CR_sig(context) REG_sig(cr, context) /* Condition register */
1234/* Float Registers access */
1235# define FLOAT_sig(reg_num, context) FLOATREG_sig(fpregs[reg_num], context)
1236# define FPSCR_sig(context) ((double)FLOATREG_sig(fpscr, context))
1237/* Exception Registers access */
1238# define DAR_sig(context) EXCEPREG_sig(dar, context) /* Fault registers for coredump */
1239# define DSISR_sig(context) EXCEPREG_sig(dsisr, context)
1240# define TRAP_sig(context) EXCEPREG_sig(exception, context) /* number of powerpc exception taken */
1241#endif /* __APPLE__ */
1242
ths5fafdf22007-09-16 21:08:06 +00001243int cpu_signal_handler(int host_signum, void *pinfo,
bellarde4533c72003-06-15 19:51:39 +00001244 void *puc)
bellard2b413142003-05-14 23:01:10 +00001245{
ths5a7b5422007-01-31 12:16:51 +00001246 siginfo_t *info = pinfo;
bellard25eb4482003-05-14 21:50:54 +00001247 struct ucontext *uc = puc;
bellard25eb4482003-05-14 21:50:54 +00001248 unsigned long pc;
bellard25eb4482003-05-14 21:50:54 +00001249 int is_write;
1250
bellard83fb7ad2004-07-05 21:25:26 +00001251 pc = IAR_sig(uc);
bellard25eb4482003-05-14 21:50:54 +00001252 is_write = 0;
1253#if 0
1254 /* ppc 4xx case */
bellard83fb7ad2004-07-05 21:25:26 +00001255 if (DSISR_sig(uc) & 0x00800000)
bellard25eb4482003-05-14 21:50:54 +00001256 is_write = 1;
bellard9de5e442003-03-23 16:49:39 +00001257#else
bellard83fb7ad2004-07-05 21:25:26 +00001258 if (TRAP_sig(uc) != 0x400 && (DSISR_sig(uc) & 0x02000000))
bellard25eb4482003-05-14 21:50:54 +00001259 is_write = 1;
1260#endif
ths5fafdf22007-09-16 21:08:06 +00001261 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellardbf3e8bf2004-02-16 21:58:54 +00001262 is_write, &uc->uc_sigmask, puc);
bellard9de5e442003-03-23 16:49:39 +00001263}
bellard2b413142003-05-14 23:01:10 +00001264
bellard2f87c602003-06-02 20:38:09 +00001265#elif defined(__alpha__)
1266
ths5fafdf22007-09-16 21:08:06 +00001267int cpu_signal_handler(int host_signum, void *pinfo,
bellard2f87c602003-06-02 20:38:09 +00001268 void *puc)
1269{
ths5a7b5422007-01-31 12:16:51 +00001270 siginfo_t *info = pinfo;
bellard2f87c602003-06-02 20:38:09 +00001271 struct ucontext *uc = puc;
1272 uint32_t *pc = uc->uc_mcontext.sc_pc;
1273 uint32_t insn = *pc;
1274 int is_write = 0;
1275
bellard8c6939c2003-06-09 15:28:00 +00001276 /* XXX: need kernel patch to get write flag faster */
bellard2f87c602003-06-02 20:38:09 +00001277 switch (insn >> 26) {
1278 case 0x0d: // stw
1279 case 0x0e: // stb
1280 case 0x0f: // stq_u
1281 case 0x24: // stf
1282 case 0x25: // stg
1283 case 0x26: // sts
1284 case 0x27: // stt
1285 case 0x2c: // stl
1286 case 0x2d: // stq
1287 case 0x2e: // stl_c
1288 case 0x2f: // stq_c
1289 is_write = 1;
1290 }
1291
ths5fafdf22007-09-16 21:08:06 +00001292 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellardbf3e8bf2004-02-16 21:58:54 +00001293 is_write, &uc->uc_sigmask, puc);
bellard2f87c602003-06-02 20:38:09 +00001294}
bellard8c6939c2003-06-09 15:28:00 +00001295#elif defined(__sparc__)
1296
ths5fafdf22007-09-16 21:08:06 +00001297int cpu_signal_handler(int host_signum, void *pinfo,
bellarde4533c72003-06-15 19:51:39 +00001298 void *puc)
bellard8c6939c2003-06-09 15:28:00 +00001299{
ths5a7b5422007-01-31 12:16:51 +00001300 siginfo_t *info = pinfo;
bellard8c6939c2003-06-09 15:28:00 +00001301 int is_write;
1302 uint32_t insn;
blueswir16b4c11c2008-05-19 17:20:01 +00001303#if !defined(__arch64__) || defined(HOST_SOLARIS)
blueswir1c9e1e2b2008-05-18 06:40:16 +00001304 uint32_t *regs = (uint32_t *)(info + 1);
1305 void *sigmask = (regs + 20);
bellard8c6939c2003-06-09 15:28:00 +00001306 /* XXX: is there a standard glibc define ? */
blueswir1c9e1e2b2008-05-18 06:40:16 +00001307 unsigned long pc = regs[1];
1308#else
blueswir184778502008-10-26 20:33:16 +00001309#ifdef __linux__
blueswir1c9e1e2b2008-05-18 06:40:16 +00001310 struct sigcontext *sc = puc;
1311 unsigned long pc = sc->sigc_regs.tpc;
1312 void *sigmask = (void *)sc->sigc_mask;
blueswir184778502008-10-26 20:33:16 +00001313#elif defined(__OpenBSD__)
1314 struct sigcontext *uc = puc;
1315 unsigned long pc = uc->sc_pc;
1316 void *sigmask = (void *)(long)uc->sc_mask;
1317#endif
blueswir1c9e1e2b2008-05-18 06:40:16 +00001318#endif
1319
bellard8c6939c2003-06-09 15:28:00 +00001320 /* XXX: need kernel patch to get write flag faster */
1321 is_write = 0;
1322 insn = *(uint32_t *)pc;
1323 if ((insn >> 30) == 3) {
1324 switch((insn >> 19) & 0x3f) {
1325 case 0x05: // stb
1326 case 0x06: // sth
1327 case 0x04: // st
1328 case 0x07: // std
1329 case 0x24: // stf
1330 case 0x27: // stdf
1331 case 0x25: // stfsr
1332 is_write = 1;
1333 break;
1334 }
1335 }
ths5fafdf22007-09-16 21:08:06 +00001336 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellardbf3e8bf2004-02-16 21:58:54 +00001337 is_write, sigmask, NULL);
bellard8c6939c2003-06-09 15:28:00 +00001338}
1339
1340#elif defined(__arm__)
1341
ths5fafdf22007-09-16 21:08:06 +00001342int cpu_signal_handler(int host_signum, void *pinfo,
bellarde4533c72003-06-15 19:51:39 +00001343 void *puc)
bellard8c6939c2003-06-09 15:28:00 +00001344{
ths5a7b5422007-01-31 12:16:51 +00001345 siginfo_t *info = pinfo;
bellard8c6939c2003-06-09 15:28:00 +00001346 struct ucontext *uc = puc;
1347 unsigned long pc;
1348 int is_write;
ths3b46e622007-09-17 08:09:54 +00001349
blueswir148bbf112008-07-08 18:35:02 +00001350#if (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ <= 3))
balrog5c49b362008-06-02 01:01:18 +00001351 pc = uc->uc_mcontext.gregs[R15];
1352#else
balrog4eee57f2008-05-06 14:47:19 +00001353 pc = uc->uc_mcontext.arm_pc;
balrog5c49b362008-06-02 01:01:18 +00001354#endif
bellard8c6939c2003-06-09 15:28:00 +00001355 /* XXX: compute is_write */
1356 is_write = 0;
ths5fafdf22007-09-16 21:08:06 +00001357 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellard8c6939c2003-06-09 15:28:00 +00001358 is_write,
pbrookf3a96762006-07-29 19:09:31 +00001359 &uc->uc_sigmask, puc);
bellard8c6939c2003-06-09 15:28:00 +00001360}
1361
bellard38e584a2003-08-10 22:14:22 +00001362#elif defined(__mc68000)
1363
ths5fafdf22007-09-16 21:08:06 +00001364int cpu_signal_handler(int host_signum, void *pinfo,
bellard38e584a2003-08-10 22:14:22 +00001365 void *puc)
1366{
ths5a7b5422007-01-31 12:16:51 +00001367 siginfo_t *info = pinfo;
bellard38e584a2003-08-10 22:14:22 +00001368 struct ucontext *uc = puc;
1369 unsigned long pc;
1370 int is_write;
ths3b46e622007-09-17 08:09:54 +00001371
bellard38e584a2003-08-10 22:14:22 +00001372 pc = uc->uc_mcontext.gregs[16];
1373 /* XXX: compute is_write */
1374 is_write = 0;
ths5fafdf22007-09-16 21:08:06 +00001375 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellard38e584a2003-08-10 22:14:22 +00001376 is_write,
bellardbf3e8bf2004-02-16 21:58:54 +00001377 &uc->uc_sigmask, puc);
bellard38e584a2003-08-10 22:14:22 +00001378}
1379
bellardb8076a72005-04-07 22:20:31 +00001380#elif defined(__ia64)
1381
1382#ifndef __ISR_VALID
1383 /* This ought to be in <bits/siginfo.h>... */
1384# define __ISR_VALID 1
bellardb8076a72005-04-07 22:20:31 +00001385#endif
1386
ths5a7b5422007-01-31 12:16:51 +00001387int cpu_signal_handler(int host_signum, void *pinfo, void *puc)
bellardb8076a72005-04-07 22:20:31 +00001388{
ths5a7b5422007-01-31 12:16:51 +00001389 siginfo_t *info = pinfo;
bellardb8076a72005-04-07 22:20:31 +00001390 struct ucontext *uc = puc;
1391 unsigned long ip;
1392 int is_write = 0;
1393
1394 ip = uc->uc_mcontext.sc_ip;
1395 switch (host_signum) {
1396 case SIGILL:
1397 case SIGFPE:
1398 case SIGSEGV:
1399 case SIGBUS:
1400 case SIGTRAP:
bellardfd4a43e2006-04-24 20:32:17 +00001401 if (info->si_code && (info->si_segvflags & __ISR_VALID))
bellardb8076a72005-04-07 22:20:31 +00001402 /* ISR.W (write-access) is bit 33: */
1403 is_write = (info->si_isr >> 33) & 1;
1404 break;
1405
1406 default:
1407 break;
1408 }
1409 return handle_cpu_signal(ip, (unsigned long)info->si_addr,
1410 is_write,
1411 &uc->uc_sigmask, puc);
1412}
1413
bellard90cb9492005-07-24 15:11:38 +00001414#elif defined(__s390__)
1415
ths5fafdf22007-09-16 21:08:06 +00001416int cpu_signal_handler(int host_signum, void *pinfo,
bellard90cb9492005-07-24 15:11:38 +00001417 void *puc)
1418{
ths5a7b5422007-01-31 12:16:51 +00001419 siginfo_t *info = pinfo;
bellard90cb9492005-07-24 15:11:38 +00001420 struct ucontext *uc = puc;
1421 unsigned long pc;
1422 int is_write;
ths3b46e622007-09-17 08:09:54 +00001423
bellard90cb9492005-07-24 15:11:38 +00001424 pc = uc->uc_mcontext.psw.addr;
1425 /* XXX: compute is_write */
1426 is_write = 0;
ths5fafdf22007-09-16 21:08:06 +00001427 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
thsc4b89d12007-05-05 19:23:11 +00001428 is_write, &uc->uc_sigmask, puc);
1429}
1430
1431#elif defined(__mips__)
1432
ths5fafdf22007-09-16 21:08:06 +00001433int cpu_signal_handler(int host_signum, void *pinfo,
thsc4b89d12007-05-05 19:23:11 +00001434 void *puc)
1435{
ths9617efe2007-05-08 21:05:55 +00001436 siginfo_t *info = pinfo;
thsc4b89d12007-05-05 19:23:11 +00001437 struct ucontext *uc = puc;
1438 greg_t pc = uc->uc_mcontext.pc;
1439 int is_write;
ths3b46e622007-09-17 08:09:54 +00001440
thsc4b89d12007-05-05 19:23:11 +00001441 /* XXX: compute is_write */
1442 is_write = 0;
ths5fafdf22007-09-16 21:08:06 +00001443 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
thsc4b89d12007-05-05 19:23:11 +00001444 is_write, &uc->uc_sigmask, puc);
bellard90cb9492005-07-24 15:11:38 +00001445}
1446
aurel32f54b3f92008-04-12 20:14:54 +00001447#elif defined(__hppa__)
1448
1449int cpu_signal_handler(int host_signum, void *pinfo,
1450 void *puc)
1451{
1452 struct siginfo *info = pinfo;
1453 struct ucontext *uc = puc;
1454 unsigned long pc;
1455 int is_write;
1456
1457 pc = uc->uc_mcontext.sc_iaoq[0];
1458 /* FIXME: compute is_write */
1459 is_write = 0;
1460 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1461 is_write,
1462 &uc->uc_sigmask, puc);
1463}
1464
bellard2b413142003-05-14 23:01:10 +00001465#else
1466
bellard3fb2ded2003-06-24 13:22:59 +00001467#error host CPU specific signal handler needed
bellard2b413142003-05-14 23:01:10 +00001468
1469#endif
bellard67b915a2004-03-31 23:37:16 +00001470
1471#endif /* !defined(CONFIG_SOFTMMU) */