blob: 1955d24418dc2b93ee650f0eeb5bb2687ef1c55b [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
bellard7d132992003-03-06 23:23:54 +0000186/* main execution loop */
187
bellarde4533c72003-06-15 19:51:39 +0000188int cpu_exec(CPUState *env1)
bellard7d132992003-03-06 23:23:54 +0000189{
pbrook1057eaa2007-02-04 13:37:44 +0000190#define DECLARE_HOST_REGS 1
191#include "hostregs_helper.h"
bellard8a40a182005-11-20 10:35:40 +0000192 int ret, interrupt_request;
bellard8a40a182005-11-20 10:35:40 +0000193 TranslationBlock *tb;
bellardc27004e2005-01-03 23:35:10 +0000194 uint8_t *tc_ptr;
pbrookd5975362008-06-07 20:50:51 +0000195 unsigned long next_tb;
bellard8c6939c2003-06-09 15:28:00 +0000196
thsbfed01f2007-06-03 17:44:37 +0000197 if (cpu_halted(env1) == EXCP_HALTED)
198 return EXCP_HALTED;
bellard5a1e3cf2005-11-23 21:02:53 +0000199
ths5fafdf22007-09-16 21:08:06 +0000200 cpu_single_env = env1;
bellard6a00d602005-11-21 23:25:50 +0000201
bellard7d132992003-03-06 23:23:54 +0000202 /* first we save global registers */
pbrook1057eaa2007-02-04 13:37:44 +0000203#define SAVE_HOST_REGS 1
204#include "hostregs_helper.h"
bellardc27004e2005-01-03 23:35:10 +0000205 env = env1;
bellarde4533c72003-06-15 19:51:39 +0000206
bellard0d1a29f2004-10-12 22:01:28 +0000207 env_to_regs();
thsecb644f2007-06-03 18:45:53 +0000208#if defined(TARGET_I386)
bellard9de5e442003-03-23 16:49:39 +0000209 /* put eflags in CPU temporary format */
bellardfc2b4c42003-03-29 16:52:44 +0000210 CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
211 DF = 1 - (2 * ((env->eflags >> 10) & 1));
bellard9de5e442003-03-23 16:49:39 +0000212 CC_OP = CC_OP_EFLAGS;
bellardfc2b4c42003-03-29 16:52:44 +0000213 env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
bellard93ac68b2003-09-30 20:57:29 +0000214#elif defined(TARGET_SPARC)
pbrooke6e59062006-10-22 00:18:54 +0000215#elif defined(TARGET_M68K)
216 env->cc_op = CC_OP_FLAGS;
217 env->cc_dest = env->sr & 0xf;
218 env->cc_x = (env->sr >> 4) & 1;
thsecb644f2007-06-03 18:45:53 +0000219#elif defined(TARGET_ALPHA)
220#elif defined(TARGET_ARM)
221#elif defined(TARGET_PPC)
bellard6af0bf92005-07-02 14:58:51 +0000222#elif defined(TARGET_MIPS)
bellardfdf9b3e2006-04-27 21:07:38 +0000223#elif defined(TARGET_SH4)
thsf1ccf902007-10-08 13:16:14 +0000224#elif defined(TARGET_CRIS)
bellardfdf9b3e2006-04-27 21:07:38 +0000225 /* XXXXX */
bellarde4533c72003-06-15 19:51:39 +0000226#else
227#error unsupported target CPU
228#endif
bellard3fb2ded2003-06-24 13:22:59 +0000229 env->exception_index = -1;
bellard9d27abd2003-05-10 13:13:54 +0000230
bellard7d132992003-03-06 23:23:54 +0000231 /* prepare setjmp context for exception handling */
bellard3fb2ded2003-06-24 13:22:59 +0000232 for(;;) {
233 if (setjmp(env->jmp_env) == 0) {
bellardee8b7022004-02-03 23:35:10 +0000234 env->current_tb = NULL;
bellard3fb2ded2003-06-24 13:22:59 +0000235 /* if an exception is pending, we execute it here */
236 if (env->exception_index >= 0) {
237 if (env->exception_index >= EXCP_INTERRUPT) {
238 /* exit request from the cpu execution loop */
239 ret = env->exception_index;
240 break;
241 } else if (env->user_mode_only) {
242 /* if user mode only, we simulate a fake exception
ths9f083492006-12-07 18:28:42 +0000243 which will be handled outside the cpu execution
bellard3fb2ded2003-06-24 13:22:59 +0000244 loop */
bellard83479e72003-06-25 16:12:37 +0000245#if defined(TARGET_I386)
ths5fafdf22007-09-16 21:08:06 +0000246 do_interrupt_user(env->exception_index,
247 env->exception_is_int,
248 env->error_code,
bellard3fb2ded2003-06-24 13:22:59 +0000249 env->exception_next_eip);
bellardeba01622008-05-12 12:04:40 +0000250 /* successfully delivered */
251 env->old_exception = -1;
bellard83479e72003-06-25 16:12:37 +0000252#endif
bellard3fb2ded2003-06-24 13:22:59 +0000253 ret = env->exception_index;
254 break;
255 } else {
bellard83479e72003-06-25 16:12:37 +0000256#if defined(TARGET_I386)
bellard3fb2ded2003-06-24 13:22:59 +0000257 /* simulate a real cpu exception. On i386, it can
258 trigger new exceptions, but we do not handle
259 double or triple faults yet. */
ths5fafdf22007-09-16 21:08:06 +0000260 do_interrupt(env->exception_index,
261 env->exception_is_int,
262 env->error_code,
bellardd05e66d2003-08-20 21:34:35 +0000263 env->exception_next_eip, 0);
ths678dde12007-03-31 20:28:52 +0000264 /* successfully delivered */
265 env->old_exception = -1;
bellardce097762004-01-04 23:53:18 +0000266#elif defined(TARGET_PPC)
267 do_interrupt(env);
bellard6af0bf92005-07-02 14:58:51 +0000268#elif defined(TARGET_MIPS)
269 do_interrupt(env);
bellarde95c8d52004-09-30 22:22:08 +0000270#elif defined(TARGET_SPARC)
blueswir1f2bc7e72008-05-27 17:35:30 +0000271 do_interrupt(env);
bellardb5ff1b32005-11-26 10:38:39 +0000272#elif defined(TARGET_ARM)
273 do_interrupt(env);
bellardfdf9b3e2006-04-27 21:07:38 +0000274#elif defined(TARGET_SH4)
275 do_interrupt(env);
j_mayereddf68a2007-04-05 07:22:49 +0000276#elif defined(TARGET_ALPHA)
277 do_interrupt(env);
thsf1ccf902007-10-08 13:16:14 +0000278#elif defined(TARGET_CRIS)
279 do_interrupt(env);
pbrook06338792007-05-23 19:58:11 +0000280#elif defined(TARGET_M68K)
281 do_interrupt(0);
bellard83479e72003-06-25 16:12:37 +0000282#endif
bellard3fb2ded2003-06-24 13:22:59 +0000283 }
284 env->exception_index = -1;
ths5fafdf22007-09-16 21:08:06 +0000285 }
bellard9df217a2005-02-10 22:05:51 +0000286#ifdef USE_KQEMU
287 if (kqemu_is_ok(env) && env->interrupt_request == 0) {
288 int ret;
pbrooka7812ae2008-11-17 14:43:54 +0000289 env->eflags = env->eflags | helper_cc_compute_all(CC_OP) | (DF & DF_MASK);
bellard9df217a2005-02-10 22:05:51 +0000290 ret = kqemu_cpu_exec(env);
291 /* put eflags in CPU temporary format */
292 CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
293 DF = 1 - (2 * ((env->eflags >> 10) & 1));
294 CC_OP = CC_OP_EFLAGS;
295 env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
296 if (ret == 1) {
297 /* exception */
298 longjmp(env->jmp_env, 1);
299 } else if (ret == 2) {
300 /* softmmu execution needed */
301 } else {
302 if (env->interrupt_request != 0) {
303 /* hardware interrupt will be executed just after */
304 } else {
305 /* otherwise, we restart */
306 longjmp(env->jmp_env, 1);
307 }
308 }
bellard9de5e442003-03-23 16:49:39 +0000309 }
bellard9df217a2005-02-10 22:05:51 +0000310#endif
311
aliguori7ba1e612008-11-05 16:04:33 +0000312 if (kvm_enabled()) {
aliguoribecfc392008-11-10 15:55:14 +0000313 kvm_cpu_exec(env);
314 longjmp(env->jmp_env, 1);
aliguori7ba1e612008-11-05 16:04:33 +0000315 }
316
blueswir1b5fc09a2008-05-04 06:38:18 +0000317 next_tb = 0; /* force lookup of first TB */
bellard3fb2ded2003-06-24 13:22:59 +0000318 for(;;) {
bellard68a79312003-06-30 13:12:32 +0000319 interrupt_request = env->interrupt_request;
malce1638bd2008-11-06 18:54:46 +0000320 if (unlikely(interrupt_request)) {
321 if (unlikely(env->singlestep_enabled & SSTEP_NOIRQ)) {
322 /* Mask out external interrupts for this step. */
323 interrupt_request &= ~(CPU_INTERRUPT_HARD |
324 CPU_INTERRUPT_FIQ |
325 CPU_INTERRUPT_SMI |
326 CPU_INTERRUPT_NMI);
327 }
pbrook6658ffb2007-03-16 23:58:11 +0000328 if (interrupt_request & CPU_INTERRUPT_DEBUG) {
329 env->interrupt_request &= ~CPU_INTERRUPT_DEBUG;
330 env->exception_index = EXCP_DEBUG;
331 cpu_loop_exit();
332 }
balroga90b7312007-05-01 01:28:01 +0000333#if defined(TARGET_ARM) || defined(TARGET_SPARC) || defined(TARGET_MIPS) || \
thsf1ccf902007-10-08 13:16:14 +0000334 defined(TARGET_PPC) || defined(TARGET_ALPHA) || defined(TARGET_CRIS)
balroga90b7312007-05-01 01:28:01 +0000335 if (interrupt_request & CPU_INTERRUPT_HALT) {
336 env->interrupt_request &= ~CPU_INTERRUPT_HALT;
337 env->halted = 1;
338 env->exception_index = EXCP_HLT;
339 cpu_loop_exit();
340 }
341#endif
bellard68a79312003-06-30 13:12:32 +0000342#if defined(TARGET_I386)
bellarddb620f42008-06-04 17:02:19 +0000343 if (env->hflags2 & HF2_GIF_MASK) {
344 if ((interrupt_request & CPU_INTERRUPT_SMI) &&
345 !(env->hflags & HF_SMM_MASK)) {
346 svm_check_intercept(SVM_EXIT_SMI);
347 env->interrupt_request &= ~CPU_INTERRUPT_SMI;
348 do_smm_enter();
349 next_tb = 0;
350 } else if ((interrupt_request & CPU_INTERRUPT_NMI) &&
351 !(env->hflags2 & HF2_NMI_MASK)) {
352 env->interrupt_request &= ~CPU_INTERRUPT_NMI;
353 env->hflags2 |= HF2_NMI_MASK;
354 do_interrupt(EXCP02_NMI, 0, 0, 0, 1);
355 next_tb = 0;
356 } else if ((interrupt_request & CPU_INTERRUPT_HARD) &&
357 (((env->hflags2 & HF2_VINTR_MASK) &&
358 (env->hflags2 & HF2_HIF_MASK)) ||
359 (!(env->hflags2 & HF2_VINTR_MASK) &&
360 (env->eflags & IF_MASK &&
361 !(env->hflags & HF_INHIBIT_IRQ_MASK))))) {
362 int intno;
363 svm_check_intercept(SVM_EXIT_INTR);
364 env->interrupt_request &= ~(CPU_INTERRUPT_HARD | CPU_INTERRUPT_VIRQ);
365 intno = cpu_get_pic_interrupt(env);
366 if (loglevel & CPU_LOG_TB_IN_ASM) {
367 fprintf(logfile, "Servicing hardware INT=0x%02x\n", intno);
368 }
369 do_interrupt(intno, 0, 0, 0, 1);
370 /* ensure that no TB jump will be modified as
371 the program flow was changed */
372 next_tb = 0;
ths0573fbf2007-09-23 15:28:04 +0000373#if !defined(CONFIG_USER_ONLY)
bellarddb620f42008-06-04 17:02:19 +0000374 } else if ((interrupt_request & CPU_INTERRUPT_VIRQ) &&
375 (env->eflags & IF_MASK) &&
376 !(env->hflags & HF_INHIBIT_IRQ_MASK)) {
377 int intno;
378 /* FIXME: this should respect TPR */
379 svm_check_intercept(SVM_EXIT_VINTR);
380 env->interrupt_request &= ~CPU_INTERRUPT_VIRQ;
381 intno = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_vector));
382 if (loglevel & CPU_LOG_TB_IN_ASM)
383 fprintf(logfile, "Servicing virtual hardware INT=0x%02x\n", intno);
384 do_interrupt(intno, 0, 0, 0, 1);
385 next_tb = 0;
ths0573fbf2007-09-23 15:28:04 +0000386#endif
bellarddb620f42008-06-04 17:02:19 +0000387 }
bellard68a79312003-06-30 13:12:32 +0000388 }
bellardce097762004-01-04 23:53:18 +0000389#elif defined(TARGET_PPC)
bellard9fddaa02004-05-21 12:59:32 +0000390#if 0
391 if ((interrupt_request & CPU_INTERRUPT_RESET)) {
392 cpu_ppc_reset(env);
393 }
394#endif
j_mayer47103572007-03-30 09:38:04 +0000395 if (interrupt_request & CPU_INTERRUPT_HARD) {
j_mayere9df0142007-04-09 22:45:36 +0000396 ppc_hw_interrupt(env);
397 if (env->pending_interrupts == 0)
398 env->interrupt_request &= ~CPU_INTERRUPT_HARD;
blueswir1b5fc09a2008-05-04 06:38:18 +0000399 next_tb = 0;
bellardce097762004-01-04 23:53:18 +0000400 }
bellard6af0bf92005-07-02 14:58:51 +0000401#elif defined(TARGET_MIPS)
402 if ((interrupt_request & CPU_INTERRUPT_HARD) &&
ths24c7b0e2007-03-30 16:44:54 +0000403 (env->CP0_Status & env->CP0_Cause & CP0Ca_IP_mask) &&
bellard6af0bf92005-07-02 14:58:51 +0000404 (env->CP0_Status & (1 << CP0St_IE)) &&
ths24c7b0e2007-03-30 16:44:54 +0000405 !(env->CP0_Status & (1 << CP0St_EXL)) &&
406 !(env->CP0_Status & (1 << CP0St_ERL)) &&
bellard6af0bf92005-07-02 14:58:51 +0000407 !(env->hflags & MIPS_HFLAG_DM)) {
408 /* Raise it */
409 env->exception_index = EXCP_EXT_INTERRUPT;
410 env->error_code = 0;
411 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000412 next_tb = 0;
bellard6af0bf92005-07-02 14:58:51 +0000413 }
bellarde95c8d52004-09-30 22:22:08 +0000414#elif defined(TARGET_SPARC)
bellard66321a12005-04-06 20:47:48 +0000415 if ((interrupt_request & CPU_INTERRUPT_HARD) &&
416 (env->psret != 0)) {
417 int pil = env->interrupt_index & 15;
418 int type = env->interrupt_index & 0xf0;
419
420 if (((type == TT_EXTINT) &&
421 (pil == 15 || pil > env->psrpil)) ||
422 type != TT_EXTINT) {
423 env->interrupt_request &= ~CPU_INTERRUPT_HARD;
blueswir1f2bc7e72008-05-27 17:35:30 +0000424 env->exception_index = env->interrupt_index;
425 do_interrupt(env);
bellard66321a12005-04-06 20:47:48 +0000426 env->interrupt_index = 0;
blueswir1327ac2e2007-08-04 10:50:30 +0000427#if !defined(TARGET_SPARC64) && !defined(CONFIG_USER_ONLY)
428 cpu_check_irqs(env);
429#endif
blueswir1b5fc09a2008-05-04 06:38:18 +0000430 next_tb = 0;
bellard66321a12005-04-06 20:47:48 +0000431 }
bellarde95c8d52004-09-30 22:22:08 +0000432 } else if (interrupt_request & CPU_INTERRUPT_TIMER) {
433 //do_interrupt(0, 0, 0, 0, 0);
434 env->interrupt_request &= ~CPU_INTERRUPT_TIMER;
balroga90b7312007-05-01 01:28:01 +0000435 }
bellardb5ff1b32005-11-26 10:38:39 +0000436#elif defined(TARGET_ARM)
437 if (interrupt_request & CPU_INTERRUPT_FIQ
438 && !(env->uncached_cpsr & CPSR_F)) {
439 env->exception_index = EXCP_FIQ;
440 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000441 next_tb = 0;
bellardb5ff1b32005-11-26 10:38:39 +0000442 }
pbrook9ee6e8b2007-11-11 00:04:49 +0000443 /* ARMv7-M interrupt return works by loading a magic value
444 into the PC. On real hardware the load causes the
445 return to occur. The qemu implementation performs the
446 jump normally, then does the exception return when the
447 CPU tries to execute code at the magic address.
448 This will cause the magic PC value to be pushed to
449 the stack if an interrupt occured at the wrong time.
450 We avoid this by disabling interrupts when
451 pc contains a magic address. */
bellardb5ff1b32005-11-26 10:38:39 +0000452 if (interrupt_request & CPU_INTERRUPT_HARD
pbrook9ee6e8b2007-11-11 00:04:49 +0000453 && ((IS_M(env) && env->regs[15] < 0xfffffff0)
454 || !(env->uncached_cpsr & CPSR_I))) {
bellardb5ff1b32005-11-26 10:38:39 +0000455 env->exception_index = EXCP_IRQ;
456 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000457 next_tb = 0;
bellardb5ff1b32005-11-26 10:38:39 +0000458 }
bellardfdf9b3e2006-04-27 21:07:38 +0000459#elif defined(TARGET_SH4)
thse96e2042007-12-02 06:18:24 +0000460 if (interrupt_request & CPU_INTERRUPT_HARD) {
461 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000462 next_tb = 0;
thse96e2042007-12-02 06:18:24 +0000463 }
j_mayereddf68a2007-04-05 07:22:49 +0000464#elif defined(TARGET_ALPHA)
465 if (interrupt_request & CPU_INTERRUPT_HARD) {
466 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000467 next_tb = 0;
j_mayereddf68a2007-04-05 07:22:49 +0000468 }
thsf1ccf902007-10-08 13:16:14 +0000469#elif defined(TARGET_CRIS)
edgar_igl1b1a38b2008-06-09 23:18:06 +0000470 if (interrupt_request & CPU_INTERRUPT_HARD
471 && (env->pregs[PR_CCS] & I_FLAG)) {
472 env->exception_index = EXCP_IRQ;
473 do_interrupt(env);
474 next_tb = 0;
475 }
476 if (interrupt_request & CPU_INTERRUPT_NMI
477 && (env->pregs[PR_CCS] & M_FLAG)) {
478 env->exception_index = EXCP_NMI;
thsf1ccf902007-10-08 13:16:14 +0000479 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000480 next_tb = 0;
thsf1ccf902007-10-08 13:16:14 +0000481 }
pbrook06338792007-05-23 19:58:11 +0000482#elif defined(TARGET_M68K)
483 if (interrupt_request & CPU_INTERRUPT_HARD
484 && ((env->sr & SR_I) >> SR_I_SHIFT)
485 < env->pending_level) {
486 /* Real hardware gets the interrupt vector via an
487 IACK cycle at this point. Current emulated
488 hardware doesn't rely on this, so we
489 provide/save the vector when the interrupt is
490 first signalled. */
491 env->exception_index = env->pending_vector;
492 do_interrupt(1);
blueswir1b5fc09a2008-05-04 06:38:18 +0000493 next_tb = 0;
pbrook06338792007-05-23 19:58:11 +0000494 }
bellard68a79312003-06-30 13:12:32 +0000495#endif
bellard9d050952006-05-22 22:03:52 +0000496 /* Don't use the cached interupt_request value,
497 do_interrupt may have updated the EXITTB flag. */
bellardb5ff1b32005-11-26 10:38:39 +0000498 if (env->interrupt_request & CPU_INTERRUPT_EXITTB) {
bellardbf3e8bf2004-02-16 21:58:54 +0000499 env->interrupt_request &= ~CPU_INTERRUPT_EXITTB;
500 /* ensure that no TB jump will be modified as
501 the program flow was changed */
blueswir1b5fc09a2008-05-04 06:38:18 +0000502 next_tb = 0;
bellardbf3e8bf2004-02-16 21:58:54 +0000503 }
bellard68a79312003-06-30 13:12:32 +0000504 if (interrupt_request & CPU_INTERRUPT_EXIT) {
505 env->interrupt_request &= ~CPU_INTERRUPT_EXIT;
506 env->exception_index = EXCP_INTERRUPT;
507 cpu_loop_exit();
508 }
bellard3fb2ded2003-06-24 13:22:59 +0000509 }
510#ifdef DEBUG_EXEC
bellardb5ff1b32005-11-26 10:38:39 +0000511 if ((loglevel & CPU_LOG_TB_CPU)) {
bellard3fb2ded2003-06-24 13:22:59 +0000512 /* restore flags in standard format */
thsecb644f2007-06-03 18:45:53 +0000513 regs_to_env();
514#if defined(TARGET_I386)
pbrooka7812ae2008-11-17 14:43:54 +0000515 env->eflags = env->eflags | helper_cc_compute_all(CC_OP) | (DF & DF_MASK);
bellard7fe48482004-10-09 18:08:01 +0000516 cpu_dump_state(env, logfile, fprintf, X86_DUMP_CCOP);
bellard3fb2ded2003-06-24 13:22:59 +0000517 env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
bellarde4533c72003-06-15 19:51:39 +0000518#elif defined(TARGET_ARM)
bellard7fe48482004-10-09 18:08:01 +0000519 cpu_dump_state(env, logfile, fprintf, 0);
bellard93ac68b2003-09-30 20:57:29 +0000520#elif defined(TARGET_SPARC)
bellard34751872005-07-02 14:31:34 +0000521 cpu_dump_state(env, logfile, fprintf, 0);
bellard67867302003-11-23 17:05:30 +0000522#elif defined(TARGET_PPC)
bellard7fe48482004-10-09 18:08:01 +0000523 cpu_dump_state(env, logfile, fprintf, 0);
pbrooke6e59062006-10-22 00:18:54 +0000524#elif defined(TARGET_M68K)
525 cpu_m68k_flush_flags(env, env->cc_op);
526 env->cc_op = CC_OP_FLAGS;
527 env->sr = (env->sr & 0xffe0)
528 | env->cc_dest | (env->cc_x << 4);
529 cpu_dump_state(env, logfile, fprintf, 0);
bellard6af0bf92005-07-02 14:58:51 +0000530#elif defined(TARGET_MIPS)
531 cpu_dump_state(env, logfile, fprintf, 0);
bellardfdf9b3e2006-04-27 21:07:38 +0000532#elif defined(TARGET_SH4)
533 cpu_dump_state(env, logfile, fprintf, 0);
j_mayereddf68a2007-04-05 07:22:49 +0000534#elif defined(TARGET_ALPHA)
535 cpu_dump_state(env, logfile, fprintf, 0);
thsf1ccf902007-10-08 13:16:14 +0000536#elif defined(TARGET_CRIS)
537 cpu_dump_state(env, logfile, fprintf, 0);
bellarde4533c72003-06-15 19:51:39 +0000538#else
ths5fafdf22007-09-16 21:08:06 +0000539#error unsupported target CPU
bellarde4533c72003-06-15 19:51:39 +0000540#endif
bellard3fb2ded2003-06-24 13:22:59 +0000541 }
bellard7d132992003-03-06 23:23:54 +0000542#endif
pbrookd5975362008-06-07 20:50:51 +0000543 spin_lock(&tb_lock);
bellard8a40a182005-11-20 10:35:40 +0000544 tb = tb_find_fast();
pbrookd5975362008-06-07 20:50:51 +0000545 /* Note: we do it here to avoid a gcc bug on Mac OS X when
546 doing it in tb_find_slow */
547 if (tb_invalidated_flag) {
548 /* as some TB could have been invalidated because
549 of memory exceptions while generating the code, we
550 must recompute the hash index here */
551 next_tb = 0;
pbrook2e70f6e2008-06-29 01:03:05 +0000552 tb_invalidated_flag = 0;
pbrookd5975362008-06-07 20:50:51 +0000553 }
bellard9d27abd2003-05-10 13:13:54 +0000554#ifdef DEBUG_EXEC
bellardc1135f62005-01-30 22:41:54 +0000555 if ((loglevel & CPU_LOG_EXEC)) {
bellardc27004e2005-01-03 23:35:10 +0000556 fprintf(logfile, "Trace 0x%08lx [" TARGET_FMT_lx "] %s\n",
557 (long)tb->tc_ptr, tb->pc,
558 lookup_symbol(tb->pc));
bellard3fb2ded2003-06-24 13:22:59 +0000559 }
bellard9d27abd2003-05-10 13:13:54 +0000560#endif
bellard8a40a182005-11-20 10:35:40 +0000561 /* see if we can patch the calling TB. When the TB
562 spans two pages, we cannot safely do a direct
563 jump. */
bellardc27004e2005-01-03 23:35:10 +0000564 {
blueswir1b5fc09a2008-05-04 06:38:18 +0000565 if (next_tb != 0 &&
blueswir14d7a0882008-05-10 10:14:22 +0000566#ifdef USE_KQEMU
bellardf32fc642006-02-08 22:43:39 +0000567 (env->kqemu_enabled != 2) &&
568#endif
bellardec6338b2007-11-08 14:25:03 +0000569 tb->page_addr[1] == -1) {
blueswir1b5fc09a2008-05-04 06:38:18 +0000570 tb_add_jump((TranslationBlock *)(next_tb & ~3), next_tb & 3, tb);
bellard3fb2ded2003-06-24 13:22:59 +0000571 }
bellardc27004e2005-01-03 23:35:10 +0000572 }
pbrookd5975362008-06-07 20:50:51 +0000573 spin_unlock(&tb_lock);
bellard83479e72003-06-25 16:12:37 +0000574 env->current_tb = tb;
malc55e8b852008-11-04 14:18:13 +0000575
576 /* cpu_interrupt might be called while translating the
577 TB, but before it is linked into a potentially
578 infinite loop and becomes env->current_tb. Avoid
579 starting execution if there is a pending interrupt. */
580 if (unlikely (env->interrupt_request & CPU_INTERRUPT_EXIT))
581 env->current_tb = NULL;
582
pbrook2e70f6e2008-06-29 01:03:05 +0000583 while (env->current_tb) {
584 tc_ptr = tb->tc_ptr;
bellard3fb2ded2003-06-24 13:22:59 +0000585 /* execute the generated code */
blueswir1572a9d42008-05-17 07:38:10 +0000586#if defined(__sparc__) && !defined(HOST_SOLARIS)
587#undef env
pbrook2e70f6e2008-06-29 01:03:05 +0000588 env = cpu_single_env;
blueswir1572a9d42008-05-17 07:38:10 +0000589#define env cpu_single_env
590#endif
pbrook2e70f6e2008-06-29 01:03:05 +0000591 next_tb = tcg_qemu_tb_exec(tc_ptr);
592 env->current_tb = NULL;
593 if ((next_tb & 3) == 2) {
thsbf20dc02008-06-30 17:22:19 +0000594 /* Instruction counter expired. */
pbrook2e70f6e2008-06-29 01:03:05 +0000595 int insns_left;
596 tb = (TranslationBlock *)(long)(next_tb & ~3);
597 /* Restore PC. */
aliguori622ed362008-11-18 19:36:03 +0000598 cpu_pc_from_tb(env, tb);
pbrook2e70f6e2008-06-29 01:03:05 +0000599 insns_left = env->icount_decr.u32;
600 if (env->icount_extra && insns_left >= 0) {
601 /* Refill decrementer and continue execution. */
602 env->icount_extra += insns_left;
603 if (env->icount_extra > 0xffff) {
604 insns_left = 0xffff;
605 } else {
606 insns_left = env->icount_extra;
607 }
608 env->icount_extra -= insns_left;
609 env->icount_decr.u16.low = insns_left;
610 } else {
611 if (insns_left > 0) {
612 /* Execute remaining instructions. */
613 cpu_exec_nocache(insns_left, tb);
614 }
615 env->exception_index = EXCP_INTERRUPT;
616 next_tb = 0;
617 cpu_loop_exit();
618 }
619 }
620 }
bellard4cbf74b2003-08-10 21:48:43 +0000621 /* reset soft MMU for next block (it can currently
622 only be set by a memory fault) */
bellardf32fc642006-02-08 22:43:39 +0000623#if defined(USE_KQEMU)
624#define MIN_CYCLE_BEFORE_SWITCH (100 * 1000)
625 if (kqemu_is_ok(env) &&
626 (cpu_get_time_fast() - env->last_io_time) >= MIN_CYCLE_BEFORE_SWITCH) {
627 cpu_loop_exit();
628 }
629#endif
ths50a518e2007-06-03 18:52:15 +0000630 } /* for(;;) */
bellard3fb2ded2003-06-24 13:22:59 +0000631 } else {
bellard0d1a29f2004-10-12 22:01:28 +0000632 env_to_regs();
bellard7d132992003-03-06 23:23:54 +0000633 }
bellard3fb2ded2003-06-24 13:22:59 +0000634 } /* for(;;) */
635
bellard7d132992003-03-06 23:23:54 +0000636
bellarde4533c72003-06-15 19:51:39 +0000637#if defined(TARGET_I386)
bellard9de5e442003-03-23 16:49:39 +0000638 /* restore flags in standard format */
pbrooka7812ae2008-11-17 14:43:54 +0000639 env->eflags = env->eflags | helper_cc_compute_all(CC_OP) | (DF & DF_MASK);
bellarde4533c72003-06-15 19:51:39 +0000640#elif defined(TARGET_ARM)
bellardb7bcbe92005-02-22 19:27:29 +0000641 /* XXX: Save/restore host fpu exception state?. */
bellard93ac68b2003-09-30 20:57:29 +0000642#elif defined(TARGET_SPARC)
bellard67867302003-11-23 17:05:30 +0000643#elif defined(TARGET_PPC)
pbrooke6e59062006-10-22 00:18:54 +0000644#elif defined(TARGET_M68K)
645 cpu_m68k_flush_flags(env, env->cc_op);
646 env->cc_op = CC_OP_FLAGS;
647 env->sr = (env->sr & 0xffe0)
648 | env->cc_dest | (env->cc_x << 4);
bellard6af0bf92005-07-02 14:58:51 +0000649#elif defined(TARGET_MIPS)
bellardfdf9b3e2006-04-27 21:07:38 +0000650#elif defined(TARGET_SH4)
j_mayereddf68a2007-04-05 07:22:49 +0000651#elif defined(TARGET_ALPHA)
thsf1ccf902007-10-08 13:16:14 +0000652#elif defined(TARGET_CRIS)
bellardfdf9b3e2006-04-27 21:07:38 +0000653 /* XXXXX */
bellarde4533c72003-06-15 19:51:39 +0000654#else
655#error unsupported target CPU
656#endif
pbrook1057eaa2007-02-04 13:37:44 +0000657
658 /* restore global registers */
pbrook1057eaa2007-02-04 13:37:44 +0000659#include "hostregs_helper.h"
660
bellard6a00d602005-11-21 23:25:50 +0000661 /* fail safe : never use cpu_single_env outside cpu_exec() */
ths5fafdf22007-09-16 21:08:06 +0000662 cpu_single_env = NULL;
bellard7d132992003-03-06 23:23:54 +0000663 return ret;
664}
bellard6dbad632003-03-16 18:05:05 +0000665
bellardfbf9eeb2004-04-25 21:21:33 +0000666/* must only be called from the generated code as an exception can be
667 generated */
668void tb_invalidate_page_range(target_ulong start, target_ulong end)
669{
bellarddc5d0b32004-06-22 18:43:30 +0000670 /* XXX: cannot enable it yet because it yields to MMU exception
671 where NIP != read address on PowerPC */
672#if 0
bellardfbf9eeb2004-04-25 21:21:33 +0000673 target_ulong phys_addr;
674 phys_addr = get_phys_addr_code(env, start);
675 tb_invalidate_phys_page_range(phys_addr, phys_addr + end - start, 0);
bellarddc5d0b32004-06-22 18:43:30 +0000676#endif
bellardfbf9eeb2004-04-25 21:21:33 +0000677}
678
bellard1a18c712003-10-30 01:07:51 +0000679#if defined(TARGET_I386) && defined(CONFIG_USER_ONLY)
bellarde4533c72003-06-15 19:51:39 +0000680
bellard6dbad632003-03-16 18:05:05 +0000681void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector)
682{
683 CPUX86State *saved_env;
684
685 saved_env = env;
686 env = s;
bellarda412ac52003-07-26 18:01:40 +0000687 if (!(env->cr[0] & CR0_PE_MASK) || (env->eflags & VM_MASK)) {
bellarda513fe12003-05-27 23:29:48 +0000688 selector &= 0xffff;
ths5fafdf22007-09-16 21:08:06 +0000689 cpu_x86_load_seg_cache(env, seg_reg, selector,
bellardc27004e2005-01-03 23:35:10 +0000690 (selector << 4), 0xffff, 0);
bellarda513fe12003-05-27 23:29:48 +0000691 } else {
bellard5d975592008-05-12 22:05:33 +0000692 helper_load_seg(seg_reg, selector);
bellarda513fe12003-05-27 23:29:48 +0000693 }
bellard6dbad632003-03-16 18:05:05 +0000694 env = saved_env;
695}
bellard9de5e442003-03-23 16:49:39 +0000696
bellard6f12a2a2007-11-11 22:16:56 +0000697void cpu_x86_fsave(CPUX86State *s, target_ulong ptr, int data32)
bellardd0a1ffc2003-05-29 20:04:28 +0000698{
699 CPUX86State *saved_env;
700
701 saved_env = env;
702 env = s;
ths3b46e622007-09-17 08:09:54 +0000703
bellard6f12a2a2007-11-11 22:16:56 +0000704 helper_fsave(ptr, data32);
bellardd0a1ffc2003-05-29 20:04:28 +0000705
706 env = saved_env;
707}
708
bellard6f12a2a2007-11-11 22:16:56 +0000709void cpu_x86_frstor(CPUX86State *s, target_ulong ptr, int data32)
bellardd0a1ffc2003-05-29 20:04:28 +0000710{
711 CPUX86State *saved_env;
712
713 saved_env = env;
714 env = s;
ths3b46e622007-09-17 08:09:54 +0000715
bellard6f12a2a2007-11-11 22:16:56 +0000716 helper_frstor(ptr, data32);
bellardd0a1ffc2003-05-29 20:04:28 +0000717
718 env = saved_env;
719}
720
bellarde4533c72003-06-15 19:51:39 +0000721#endif /* TARGET_I386 */
722
bellard67b915a2004-03-31 23:37:16 +0000723#if !defined(CONFIG_SOFTMMU)
724
bellard3fb2ded2003-06-24 13:22:59 +0000725#if defined(TARGET_I386)
726
bellardb56dad12003-05-08 15:38:04 +0000727/* 'pc' is the host PC at which the exception was raised. 'address' is
bellardfd6ce8f2003-05-14 19:00:11 +0000728 the effective address of the memory exception. 'is_write' is 1 if a
729 write caused the exception and otherwise 0'. 'old_set' is the
730 signal set which should be restored */
bellard2b413142003-05-14 23:01:10 +0000731static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
ths5fafdf22007-09-16 21:08:06 +0000732 int is_write, sigset_t *old_set,
bellardbf3e8bf2004-02-16 21:58:54 +0000733 void *puc)
bellard9de5e442003-03-23 16:49:39 +0000734{
bellarda513fe12003-05-27 23:29:48 +0000735 TranslationBlock *tb;
736 int ret;
bellard68a79312003-06-30 13:12:32 +0000737
bellard83479e72003-06-25 16:12:37 +0000738 if (cpu_single_env)
739 env = cpu_single_env; /* XXX: find a correct solution for multithread */
bellardfd6ce8f2003-05-14 19:00:11 +0000740#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000741 qemu_printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellardbf3e8bf2004-02-16 21:58:54 +0000742 pc, address, is_write, *(unsigned long *)old_set);
bellard9de5e442003-03-23 16:49:39 +0000743#endif
bellard25eb4482003-05-14 21:50:54 +0000744 /* XXX: locking issue */
pbrook53a59602006-03-25 19:31:22 +0000745 if (is_write && page_unprotect(h2g(address), pc, puc)) {
bellardfd6ce8f2003-05-14 19:00:11 +0000746 return 1;
747 }
bellardfbf9eeb2004-04-25 21:21:33 +0000748
bellard3fb2ded2003-06-24 13:22:59 +0000749 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +0000750 ret = cpu_x86_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellard3fb2ded2003-06-24 13:22:59 +0000751 if (ret < 0)
752 return 0; /* not an MMU fault */
753 if (ret == 0)
754 return 1; /* the MMU fault was handled without causing real CPU fault */
755 /* now we have a real cpu fault */
bellarda513fe12003-05-27 23:29:48 +0000756 tb = tb_find_pc(pc);
757 if (tb) {
bellard9de5e442003-03-23 16:49:39 +0000758 /* the PC is inside the translated code. It means that we have
759 a virtual CPU fault */
bellardbf3e8bf2004-02-16 21:58:54 +0000760 cpu_restore_state(tb, env, pc, puc);
bellard3fb2ded2003-06-24 13:22:59 +0000761 }
bellard4cbf74b2003-08-10 21:48:43 +0000762 if (ret == 1) {
bellard3fb2ded2003-06-24 13:22:59 +0000763#if 0
ths5fafdf22007-09-16 21:08:06 +0000764 printf("PF exception: EIP=0x%08x CR2=0x%08x error=0x%x\n",
bellard4cbf74b2003-08-10 21:48:43 +0000765 env->eip, env->cr[2], env->error_code);
bellard3fb2ded2003-06-24 13:22:59 +0000766#endif
bellard4cbf74b2003-08-10 21:48:43 +0000767 /* we restore the process signal mask as the sigreturn should
768 do it (XXX: use sigsetjmp) */
769 sigprocmask(SIG_SETMASK, old_set, NULL);
bellard54ca9092005-12-04 18:46:06 +0000770 raise_exception_err(env->exception_index, env->error_code);
bellard4cbf74b2003-08-10 21:48:43 +0000771 } else {
772 /* activate soft MMU for this block */
bellard3f337312003-08-20 23:02:09 +0000773 env->hflags |= HF_SOFTMMU_MASK;
bellardfbf9eeb2004-04-25 21:21:33 +0000774 cpu_resume_from_signal(env, puc);
bellard4cbf74b2003-08-10 21:48:43 +0000775 }
bellard3fb2ded2003-06-24 13:22:59 +0000776 /* never comes here */
777 return 1;
778}
779
bellarde4533c72003-06-15 19:51:39 +0000780#elif defined(TARGET_ARM)
bellard3fb2ded2003-06-24 13:22:59 +0000781static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
bellardbf3e8bf2004-02-16 21:58:54 +0000782 int is_write, sigset_t *old_set,
783 void *puc)
bellard3fb2ded2003-06-24 13:22:59 +0000784{
bellard68016c62005-02-07 23:12:27 +0000785 TranslationBlock *tb;
786 int ret;
787
788 if (cpu_single_env)
789 env = cpu_single_env; /* XXX: find a correct solution for multithread */
790#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000791 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellard68016c62005-02-07 23:12:27 +0000792 pc, address, is_write, *(unsigned long *)old_set);
793#endif
bellard9f0777e2005-02-02 20:42:01 +0000794 /* XXX: locking issue */
pbrook53a59602006-03-25 19:31:22 +0000795 if (is_write && page_unprotect(h2g(address), pc, puc)) {
bellard9f0777e2005-02-02 20:42:01 +0000796 return 1;
797 }
bellard68016c62005-02-07 23:12:27 +0000798 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +0000799 ret = cpu_arm_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellard68016c62005-02-07 23:12:27 +0000800 if (ret < 0)
801 return 0; /* not an MMU fault */
802 if (ret == 0)
803 return 1; /* the MMU fault was handled without causing real CPU fault */
804 /* now we have a real cpu fault */
805 tb = tb_find_pc(pc);
806 if (tb) {
807 /* the PC is inside the translated code. It means that we have
808 a virtual CPU fault */
809 cpu_restore_state(tb, env, pc, puc);
810 }
811 /* we restore the process signal mask as the sigreturn should
812 do it (XXX: use sigsetjmp) */
813 sigprocmask(SIG_SETMASK, old_set, NULL);
814 cpu_loop_exit();
aurel32968c74d2008-04-11 04:55:17 +0000815 /* never comes here */
816 return 1;
bellard3fb2ded2003-06-24 13:22:59 +0000817}
bellard93ac68b2003-09-30 20:57:29 +0000818#elif defined(TARGET_SPARC)
819static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
bellardbf3e8bf2004-02-16 21:58:54 +0000820 int is_write, sigset_t *old_set,
821 void *puc)
bellard93ac68b2003-09-30 20:57:29 +0000822{
bellard68016c62005-02-07 23:12:27 +0000823 TranslationBlock *tb;
824 int ret;
825
826 if (cpu_single_env)
827 env = cpu_single_env; /* XXX: find a correct solution for multithread */
828#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000829 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellard68016c62005-02-07 23:12:27 +0000830 pc, address, is_write, *(unsigned long *)old_set);
831#endif
bellardb453b702004-01-04 15:45:21 +0000832 /* XXX: locking issue */
pbrook53a59602006-03-25 19:31:22 +0000833 if (is_write && page_unprotect(h2g(address), pc, puc)) {
bellardb453b702004-01-04 15:45:21 +0000834 return 1;
835 }
bellard68016c62005-02-07 23:12:27 +0000836 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +0000837 ret = cpu_sparc_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellard68016c62005-02-07 23:12:27 +0000838 if (ret < 0)
839 return 0; /* not an MMU fault */
840 if (ret == 0)
841 return 1; /* the MMU fault was handled without causing real CPU fault */
842 /* now we have a real cpu fault */
843 tb = tb_find_pc(pc);
844 if (tb) {
845 /* the PC is inside the translated code. It means that we have
846 a virtual CPU fault */
847 cpu_restore_state(tb, env, pc, puc);
848 }
849 /* we restore the process signal mask as the sigreturn should
850 do it (XXX: use sigsetjmp) */
851 sigprocmask(SIG_SETMASK, old_set, NULL);
852 cpu_loop_exit();
aurel32968c74d2008-04-11 04:55:17 +0000853 /* never comes here */
854 return 1;
bellard93ac68b2003-09-30 20:57:29 +0000855}
bellard67867302003-11-23 17:05:30 +0000856#elif defined (TARGET_PPC)
857static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
bellardbf3e8bf2004-02-16 21:58:54 +0000858 int is_write, sigset_t *old_set,
859 void *puc)
bellard67867302003-11-23 17:05:30 +0000860{
861 TranslationBlock *tb;
bellardce097762004-01-04 23:53:18 +0000862 int ret;
ths3b46e622007-09-17 08:09:54 +0000863
bellard67867302003-11-23 17:05:30 +0000864 if (cpu_single_env)
865 env = cpu_single_env; /* XXX: find a correct solution for multithread */
bellard67867302003-11-23 17:05:30 +0000866#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000867 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellard67867302003-11-23 17:05:30 +0000868 pc, address, is_write, *(unsigned long *)old_set);
869#endif
870 /* XXX: locking issue */
pbrook53a59602006-03-25 19:31:22 +0000871 if (is_write && page_unprotect(h2g(address), pc, puc)) {
bellard67867302003-11-23 17:05:30 +0000872 return 1;
873 }
874
bellardce097762004-01-04 23:53:18 +0000875 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +0000876 ret = cpu_ppc_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellardce097762004-01-04 23:53:18 +0000877 if (ret < 0)
878 return 0; /* not an MMU fault */
879 if (ret == 0)
880 return 1; /* the MMU fault was handled without causing real CPU fault */
881
bellard67867302003-11-23 17:05:30 +0000882 /* now we have a real cpu fault */
883 tb = tb_find_pc(pc);
884 if (tb) {
885 /* the PC is inside the translated code. It means that we have
886 a virtual CPU fault */
bellardbf3e8bf2004-02-16 21:58:54 +0000887 cpu_restore_state(tb, env, pc, puc);
bellard67867302003-11-23 17:05:30 +0000888 }
bellardce097762004-01-04 23:53:18 +0000889 if (ret == 1) {
bellard67867302003-11-23 17:05:30 +0000890#if 0
ths5fafdf22007-09-16 21:08:06 +0000891 printf("PF exception: NIP=0x%08x error=0x%x %p\n",
bellardce097762004-01-04 23:53:18 +0000892 env->nip, env->error_code, tb);
bellard67867302003-11-23 17:05:30 +0000893#endif
894 /* we restore the process signal mask as the sigreturn should
895 do it (XXX: use sigsetjmp) */
bellardbf3e8bf2004-02-16 21:58:54 +0000896 sigprocmask(SIG_SETMASK, old_set, NULL);
bellard9fddaa02004-05-21 12:59:32 +0000897 do_raise_exception_err(env->exception_index, env->error_code);
bellardce097762004-01-04 23:53:18 +0000898 } else {
899 /* activate soft MMU for this block */
bellardfbf9eeb2004-04-25 21:21:33 +0000900 cpu_resume_from_signal(env, puc);
bellardce097762004-01-04 23:53:18 +0000901 }
bellard67867302003-11-23 17:05:30 +0000902 /* never comes here */
903 return 1;
904}
bellard6af0bf92005-07-02 14:58:51 +0000905
pbrooke6e59062006-10-22 00:18:54 +0000906#elif defined(TARGET_M68K)
907static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
908 int is_write, sigset_t *old_set,
909 void *puc)
910{
911 TranslationBlock *tb;
912 int ret;
913
914 if (cpu_single_env)
915 env = cpu_single_env; /* XXX: find a correct solution for multithread */
916#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000917 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
pbrooke6e59062006-10-22 00:18:54 +0000918 pc, address, is_write, *(unsigned long *)old_set);
919#endif
920 /* XXX: locking issue */
921 if (is_write && page_unprotect(address, pc, puc)) {
922 return 1;
923 }
924 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +0000925 ret = cpu_m68k_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
pbrooke6e59062006-10-22 00:18:54 +0000926 if (ret < 0)
927 return 0; /* not an MMU fault */
928 if (ret == 0)
929 return 1; /* the MMU fault was handled without causing real CPU fault */
930 /* now we have a real cpu fault */
931 tb = tb_find_pc(pc);
932 if (tb) {
933 /* the PC is inside the translated code. It means that we have
934 a virtual CPU fault */
935 cpu_restore_state(tb, env, pc, puc);
936 }
937 /* we restore the process signal mask as the sigreturn should
938 do it (XXX: use sigsetjmp) */
939 sigprocmask(SIG_SETMASK, old_set, NULL);
940 cpu_loop_exit();
941 /* never comes here */
942 return 1;
943}
944
bellard6af0bf92005-07-02 14:58:51 +0000945#elif defined (TARGET_MIPS)
946static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
947 int is_write, sigset_t *old_set,
948 void *puc)
949{
950 TranslationBlock *tb;
951 int ret;
ths3b46e622007-09-17 08:09:54 +0000952
bellard6af0bf92005-07-02 14:58:51 +0000953 if (cpu_single_env)
954 env = cpu_single_env; /* XXX: find a correct solution for multithread */
955#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000956 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellard6af0bf92005-07-02 14:58:51 +0000957 pc, address, is_write, *(unsigned long *)old_set);
958#endif
959 /* XXX: locking issue */
pbrook53a59602006-03-25 19:31:22 +0000960 if (is_write && page_unprotect(h2g(address), pc, puc)) {
bellard6af0bf92005-07-02 14:58:51 +0000961 return 1;
962 }
963
964 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +0000965 ret = cpu_mips_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellard6af0bf92005-07-02 14:58:51 +0000966 if (ret < 0)
967 return 0; /* not an MMU fault */
968 if (ret == 0)
969 return 1; /* the MMU fault was handled without causing real CPU fault */
970
971 /* now we have a real cpu fault */
972 tb = tb_find_pc(pc);
973 if (tb) {
974 /* the PC is inside the translated code. It means that we have
975 a virtual CPU fault */
976 cpu_restore_state(tb, env, pc, puc);
977 }
978 if (ret == 1) {
979#if 0
ths5fafdf22007-09-16 21:08:06 +0000980 printf("PF exception: PC=0x" TARGET_FMT_lx " error=0x%x %p\n",
ths1eb52072007-05-12 16:57:42 +0000981 env->PC, env->error_code, tb);
bellard6af0bf92005-07-02 14:58:51 +0000982#endif
983 /* we restore the process signal mask as the sigreturn should
984 do it (XXX: use sigsetjmp) */
985 sigprocmask(SIG_SETMASK, old_set, NULL);
986 do_raise_exception_err(env->exception_index, env->error_code);
987 } else {
988 /* activate soft MMU for this block */
989 cpu_resume_from_signal(env, puc);
990 }
991 /* never comes here */
992 return 1;
993}
994
bellardfdf9b3e2006-04-27 21:07:38 +0000995#elif defined (TARGET_SH4)
996static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
997 int is_write, sigset_t *old_set,
998 void *puc)
999{
1000 TranslationBlock *tb;
1001 int ret;
ths3b46e622007-09-17 08:09:54 +00001002
bellardfdf9b3e2006-04-27 21:07:38 +00001003 if (cpu_single_env)
1004 env = cpu_single_env; /* XXX: find a correct solution for multithread */
1005#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +00001006 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellardfdf9b3e2006-04-27 21:07:38 +00001007 pc, address, is_write, *(unsigned long *)old_set);
1008#endif
1009 /* XXX: locking issue */
1010 if (is_write && page_unprotect(h2g(address), pc, puc)) {
1011 return 1;
1012 }
1013
1014 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +00001015 ret = cpu_sh4_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellardfdf9b3e2006-04-27 21:07:38 +00001016 if (ret < 0)
1017 return 0; /* not an MMU fault */
1018 if (ret == 0)
1019 return 1; /* the MMU fault was handled without causing real CPU fault */
1020
1021 /* now we have a real cpu fault */
1022 tb = tb_find_pc(pc);
1023 if (tb) {
1024 /* the PC is inside the translated code. It means that we have
1025 a virtual CPU fault */
1026 cpu_restore_state(tb, env, pc, puc);
1027 }
bellardfdf9b3e2006-04-27 21:07:38 +00001028#if 0
ths5fafdf22007-09-16 21:08:06 +00001029 printf("PF exception: NIP=0x%08x error=0x%x %p\n",
bellardfdf9b3e2006-04-27 21:07:38 +00001030 env->nip, env->error_code, tb);
1031#endif
1032 /* we restore the process signal mask as the sigreturn should
1033 do it (XXX: use sigsetjmp) */
pbrook355fb232006-06-17 19:58:25 +00001034 sigprocmask(SIG_SETMASK, old_set, NULL);
1035 cpu_loop_exit();
bellardfdf9b3e2006-04-27 21:07:38 +00001036 /* never comes here */
1037 return 1;
1038}
j_mayereddf68a2007-04-05 07:22:49 +00001039
1040#elif defined (TARGET_ALPHA)
1041static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
1042 int is_write, sigset_t *old_set,
1043 void *puc)
1044{
1045 TranslationBlock *tb;
1046 int ret;
ths3b46e622007-09-17 08:09:54 +00001047
j_mayereddf68a2007-04-05 07:22:49 +00001048 if (cpu_single_env)
1049 env = cpu_single_env; /* XXX: find a correct solution for multithread */
1050#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +00001051 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
j_mayereddf68a2007-04-05 07:22:49 +00001052 pc, address, is_write, *(unsigned long *)old_set);
1053#endif
1054 /* XXX: locking issue */
1055 if (is_write && page_unprotect(h2g(address), pc, puc)) {
1056 return 1;
1057 }
1058
1059 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +00001060 ret = cpu_alpha_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
j_mayereddf68a2007-04-05 07:22:49 +00001061 if (ret < 0)
1062 return 0; /* not an MMU fault */
1063 if (ret == 0)
1064 return 1; /* the MMU fault was handled without causing real CPU fault */
1065
1066 /* now we have a real cpu fault */
1067 tb = tb_find_pc(pc);
1068 if (tb) {
1069 /* the PC is inside the translated code. It means that we have
1070 a virtual CPU fault */
1071 cpu_restore_state(tb, env, pc, puc);
1072 }
1073#if 0
ths5fafdf22007-09-16 21:08:06 +00001074 printf("PF exception: NIP=0x%08x error=0x%x %p\n",
j_mayereddf68a2007-04-05 07:22:49 +00001075 env->nip, env->error_code, tb);
1076#endif
1077 /* we restore the process signal mask as the sigreturn should
1078 do it (XXX: use sigsetjmp) */
1079 sigprocmask(SIG_SETMASK, old_set, NULL);
1080 cpu_loop_exit();
1081 /* never comes here */
1082 return 1;
1083}
thsf1ccf902007-10-08 13:16:14 +00001084#elif defined (TARGET_CRIS)
1085static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
1086 int is_write, sigset_t *old_set,
1087 void *puc)
1088{
1089 TranslationBlock *tb;
1090 int ret;
1091
1092 if (cpu_single_env)
1093 env = cpu_single_env; /* XXX: find a correct solution for multithread */
1094#if defined(DEBUG_SIGNAL)
1095 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
1096 pc, address, is_write, *(unsigned long *)old_set);
1097#endif
1098 /* XXX: locking issue */
1099 if (is_write && page_unprotect(h2g(address), pc, puc)) {
1100 return 1;
1101 }
1102
1103 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +00001104 ret = cpu_cris_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
thsf1ccf902007-10-08 13:16:14 +00001105 if (ret < 0)
1106 return 0; /* not an MMU fault */
1107 if (ret == 0)
1108 return 1; /* the MMU fault was handled without causing real CPU fault */
1109
1110 /* now we have a real cpu fault */
1111 tb = tb_find_pc(pc);
1112 if (tb) {
1113 /* the PC is inside the translated code. It means that we have
1114 a virtual CPU fault */
1115 cpu_restore_state(tb, env, pc, puc);
1116 }
thsf1ccf902007-10-08 13:16:14 +00001117 /* we restore the process signal mask as the sigreturn should
1118 do it (XXX: use sigsetjmp) */
1119 sigprocmask(SIG_SETMASK, old_set, NULL);
1120 cpu_loop_exit();
1121 /* never comes here */
1122 return 1;
1123}
1124
bellarde4533c72003-06-15 19:51:39 +00001125#else
1126#error unsupported target CPU
1127#endif
bellard9de5e442003-03-23 16:49:39 +00001128
bellard2b413142003-05-14 23:01:10 +00001129#if defined(__i386__)
1130
bellardd8ecc0b2007-02-05 21:41:46 +00001131#if defined(__APPLE__)
1132# include <sys/ucontext.h>
1133
1134# define EIP_sig(context) (*((unsigned long*)&(context)->uc_mcontext->ss.eip))
1135# define TRAP_sig(context) ((context)->uc_mcontext->es.trapno)
1136# define ERROR_sig(context) ((context)->uc_mcontext->es.err)
1137#else
1138# define EIP_sig(context) ((context)->uc_mcontext.gregs[REG_EIP])
1139# define TRAP_sig(context) ((context)->uc_mcontext.gregs[REG_TRAPNO])
1140# define ERROR_sig(context) ((context)->uc_mcontext.gregs[REG_ERR])
1141#endif
1142
ths5fafdf22007-09-16 21:08:06 +00001143int cpu_signal_handler(int host_signum, void *pinfo,
bellarde4533c72003-06-15 19:51:39 +00001144 void *puc)
bellard9de5e442003-03-23 16:49:39 +00001145{
ths5a7b5422007-01-31 12:16:51 +00001146 siginfo_t *info = pinfo;
bellard9de5e442003-03-23 16:49:39 +00001147 struct ucontext *uc = puc;
1148 unsigned long pc;
bellardbf3e8bf2004-02-16 21:58:54 +00001149 int trapno;
bellard97eb5b12004-02-25 23:19:55 +00001150
bellardd691f662003-03-24 21:58:34 +00001151#ifndef REG_EIP
1152/* for glibc 2.1 */
bellardfd6ce8f2003-05-14 19:00:11 +00001153#define REG_EIP EIP
1154#define REG_ERR ERR
1155#define REG_TRAPNO TRAPNO
bellardd691f662003-03-24 21:58:34 +00001156#endif
bellardd8ecc0b2007-02-05 21:41:46 +00001157 pc = EIP_sig(uc);
1158 trapno = TRAP_sig(uc);
bellardec6338b2007-11-08 14:25:03 +00001159 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1160 trapno == 0xe ?
1161 (ERROR_sig(uc) >> 1) & 1 : 0,
1162 &uc->uc_sigmask, puc);
bellard2b413142003-05-14 23:01:10 +00001163}
1164
bellardbc51c5c2004-03-17 23:46:04 +00001165#elif defined(__x86_64__)
1166
ths5a7b5422007-01-31 12:16:51 +00001167int cpu_signal_handler(int host_signum, void *pinfo,
bellardbc51c5c2004-03-17 23:46:04 +00001168 void *puc)
1169{
ths5a7b5422007-01-31 12:16:51 +00001170 siginfo_t *info = pinfo;
bellardbc51c5c2004-03-17 23:46:04 +00001171 struct ucontext *uc = puc;
1172 unsigned long pc;
1173
1174 pc = uc->uc_mcontext.gregs[REG_RIP];
ths5fafdf22007-09-16 21:08:06 +00001175 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1176 uc->uc_mcontext.gregs[REG_TRAPNO] == 0xe ?
bellardbc51c5c2004-03-17 23:46:04 +00001177 (uc->uc_mcontext.gregs[REG_ERR] >> 1) & 1 : 0,
1178 &uc->uc_sigmask, puc);
1179}
1180
bellard83fb7ad2004-07-05 21:25:26 +00001181#elif defined(__powerpc__)
bellard2b413142003-05-14 23:01:10 +00001182
bellard83fb7ad2004-07-05 21:25:26 +00001183/***********************************************************************
1184 * signal context platform-specific definitions
1185 * From Wine
1186 */
1187#ifdef linux
1188/* All Registers access - only for local access */
1189# define REG_sig(reg_name, context) ((context)->uc_mcontext.regs->reg_name)
1190/* Gpr Registers access */
1191# define GPR_sig(reg_num, context) REG_sig(gpr[reg_num], context)
1192# define IAR_sig(context) REG_sig(nip, context) /* Program counter */
1193# define MSR_sig(context) REG_sig(msr, context) /* Machine State Register (Supervisor) */
1194# define CTR_sig(context) REG_sig(ctr, context) /* Count register */
1195# define XER_sig(context) REG_sig(xer, context) /* User's integer exception register */
1196# define LR_sig(context) REG_sig(link, context) /* Link register */
1197# define CR_sig(context) REG_sig(ccr, context) /* Condition register */
1198/* Float Registers access */
1199# define FLOAT_sig(reg_num, context) (((double*)((char*)((context)->uc_mcontext.regs+48*4)))[reg_num])
1200# define FPSCR_sig(context) (*(int*)((char*)((context)->uc_mcontext.regs+(48+32*2)*4)))
1201/* Exception Registers access */
1202# define DAR_sig(context) REG_sig(dar, context)
1203# define DSISR_sig(context) REG_sig(dsisr, context)
1204# define TRAP_sig(context) REG_sig(trap, context)
1205#endif /* linux */
1206
1207#ifdef __APPLE__
1208# include <sys/ucontext.h>
1209typedef struct ucontext SIGCONTEXT;
1210/* All Registers access - only for local access */
1211# define REG_sig(reg_name, context) ((context)->uc_mcontext->ss.reg_name)
1212# define FLOATREG_sig(reg_name, context) ((context)->uc_mcontext->fs.reg_name)
1213# define EXCEPREG_sig(reg_name, context) ((context)->uc_mcontext->es.reg_name)
1214# define VECREG_sig(reg_name, context) ((context)->uc_mcontext->vs.reg_name)
1215/* Gpr Registers access */
1216# define GPR_sig(reg_num, context) REG_sig(r##reg_num, context)
1217# define IAR_sig(context) REG_sig(srr0, context) /* Program counter */
1218# define MSR_sig(context) REG_sig(srr1, context) /* Machine State Register (Supervisor) */
1219# define CTR_sig(context) REG_sig(ctr, context)
1220# define XER_sig(context) REG_sig(xer, context) /* Link register */
1221# define LR_sig(context) REG_sig(lr, context) /* User's integer exception register */
1222# define CR_sig(context) REG_sig(cr, context) /* Condition register */
1223/* Float Registers access */
1224# define FLOAT_sig(reg_num, context) FLOATREG_sig(fpregs[reg_num], context)
1225# define FPSCR_sig(context) ((double)FLOATREG_sig(fpscr, context))
1226/* Exception Registers access */
1227# define DAR_sig(context) EXCEPREG_sig(dar, context) /* Fault registers for coredump */
1228# define DSISR_sig(context) EXCEPREG_sig(dsisr, context)
1229# define TRAP_sig(context) EXCEPREG_sig(exception, context) /* number of powerpc exception taken */
1230#endif /* __APPLE__ */
1231
ths5fafdf22007-09-16 21:08:06 +00001232int cpu_signal_handler(int host_signum, void *pinfo,
bellarde4533c72003-06-15 19:51:39 +00001233 void *puc)
bellard2b413142003-05-14 23:01:10 +00001234{
ths5a7b5422007-01-31 12:16:51 +00001235 siginfo_t *info = pinfo;
bellard25eb4482003-05-14 21:50:54 +00001236 struct ucontext *uc = puc;
bellard25eb4482003-05-14 21:50:54 +00001237 unsigned long pc;
bellard25eb4482003-05-14 21:50:54 +00001238 int is_write;
1239
bellard83fb7ad2004-07-05 21:25:26 +00001240 pc = IAR_sig(uc);
bellard25eb4482003-05-14 21:50:54 +00001241 is_write = 0;
1242#if 0
1243 /* ppc 4xx case */
bellard83fb7ad2004-07-05 21:25:26 +00001244 if (DSISR_sig(uc) & 0x00800000)
bellard25eb4482003-05-14 21:50:54 +00001245 is_write = 1;
bellard9de5e442003-03-23 16:49:39 +00001246#else
bellard83fb7ad2004-07-05 21:25:26 +00001247 if (TRAP_sig(uc) != 0x400 && (DSISR_sig(uc) & 0x02000000))
bellard25eb4482003-05-14 21:50:54 +00001248 is_write = 1;
1249#endif
ths5fafdf22007-09-16 21:08:06 +00001250 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellardbf3e8bf2004-02-16 21:58:54 +00001251 is_write, &uc->uc_sigmask, puc);
bellard9de5e442003-03-23 16:49:39 +00001252}
bellard2b413142003-05-14 23:01:10 +00001253
bellard2f87c602003-06-02 20:38:09 +00001254#elif defined(__alpha__)
1255
ths5fafdf22007-09-16 21:08:06 +00001256int cpu_signal_handler(int host_signum, void *pinfo,
bellard2f87c602003-06-02 20:38:09 +00001257 void *puc)
1258{
ths5a7b5422007-01-31 12:16:51 +00001259 siginfo_t *info = pinfo;
bellard2f87c602003-06-02 20:38:09 +00001260 struct ucontext *uc = puc;
1261 uint32_t *pc = uc->uc_mcontext.sc_pc;
1262 uint32_t insn = *pc;
1263 int is_write = 0;
1264
bellard8c6939c2003-06-09 15:28:00 +00001265 /* XXX: need kernel patch to get write flag faster */
bellard2f87c602003-06-02 20:38:09 +00001266 switch (insn >> 26) {
1267 case 0x0d: // stw
1268 case 0x0e: // stb
1269 case 0x0f: // stq_u
1270 case 0x24: // stf
1271 case 0x25: // stg
1272 case 0x26: // sts
1273 case 0x27: // stt
1274 case 0x2c: // stl
1275 case 0x2d: // stq
1276 case 0x2e: // stl_c
1277 case 0x2f: // stq_c
1278 is_write = 1;
1279 }
1280
ths5fafdf22007-09-16 21:08:06 +00001281 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellardbf3e8bf2004-02-16 21:58:54 +00001282 is_write, &uc->uc_sigmask, puc);
bellard2f87c602003-06-02 20:38:09 +00001283}
bellard8c6939c2003-06-09 15:28:00 +00001284#elif defined(__sparc__)
1285
ths5fafdf22007-09-16 21:08:06 +00001286int cpu_signal_handler(int host_signum, void *pinfo,
bellarde4533c72003-06-15 19:51:39 +00001287 void *puc)
bellard8c6939c2003-06-09 15:28:00 +00001288{
ths5a7b5422007-01-31 12:16:51 +00001289 siginfo_t *info = pinfo;
bellard8c6939c2003-06-09 15:28:00 +00001290 int is_write;
1291 uint32_t insn;
blueswir16b4c11c2008-05-19 17:20:01 +00001292#if !defined(__arch64__) || defined(HOST_SOLARIS)
blueswir1c9e1e2b2008-05-18 06:40:16 +00001293 uint32_t *regs = (uint32_t *)(info + 1);
1294 void *sigmask = (regs + 20);
bellard8c6939c2003-06-09 15:28:00 +00001295 /* XXX: is there a standard glibc define ? */
blueswir1c9e1e2b2008-05-18 06:40:16 +00001296 unsigned long pc = regs[1];
1297#else
blueswir184778502008-10-26 20:33:16 +00001298#ifdef __linux__
blueswir1c9e1e2b2008-05-18 06:40:16 +00001299 struct sigcontext *sc = puc;
1300 unsigned long pc = sc->sigc_regs.tpc;
1301 void *sigmask = (void *)sc->sigc_mask;
blueswir184778502008-10-26 20:33:16 +00001302#elif defined(__OpenBSD__)
1303 struct sigcontext *uc = puc;
1304 unsigned long pc = uc->sc_pc;
1305 void *sigmask = (void *)(long)uc->sc_mask;
1306#endif
blueswir1c9e1e2b2008-05-18 06:40:16 +00001307#endif
1308
bellard8c6939c2003-06-09 15:28:00 +00001309 /* XXX: need kernel patch to get write flag faster */
1310 is_write = 0;
1311 insn = *(uint32_t *)pc;
1312 if ((insn >> 30) == 3) {
1313 switch((insn >> 19) & 0x3f) {
1314 case 0x05: // stb
1315 case 0x06: // sth
1316 case 0x04: // st
1317 case 0x07: // std
1318 case 0x24: // stf
1319 case 0x27: // stdf
1320 case 0x25: // stfsr
1321 is_write = 1;
1322 break;
1323 }
1324 }
ths5fafdf22007-09-16 21:08:06 +00001325 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellardbf3e8bf2004-02-16 21:58:54 +00001326 is_write, sigmask, NULL);
bellard8c6939c2003-06-09 15:28:00 +00001327}
1328
1329#elif defined(__arm__)
1330
ths5fafdf22007-09-16 21:08:06 +00001331int cpu_signal_handler(int host_signum, void *pinfo,
bellarde4533c72003-06-15 19:51:39 +00001332 void *puc)
bellard8c6939c2003-06-09 15:28:00 +00001333{
ths5a7b5422007-01-31 12:16:51 +00001334 siginfo_t *info = pinfo;
bellard8c6939c2003-06-09 15:28:00 +00001335 struct ucontext *uc = puc;
1336 unsigned long pc;
1337 int is_write;
ths3b46e622007-09-17 08:09:54 +00001338
blueswir148bbf112008-07-08 18:35:02 +00001339#if (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ <= 3))
balrog5c49b362008-06-02 01:01:18 +00001340 pc = uc->uc_mcontext.gregs[R15];
1341#else
balrog4eee57f2008-05-06 14:47:19 +00001342 pc = uc->uc_mcontext.arm_pc;
balrog5c49b362008-06-02 01:01:18 +00001343#endif
bellard8c6939c2003-06-09 15:28:00 +00001344 /* XXX: compute is_write */
1345 is_write = 0;
ths5fafdf22007-09-16 21:08:06 +00001346 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellard8c6939c2003-06-09 15:28:00 +00001347 is_write,
pbrookf3a96762006-07-29 19:09:31 +00001348 &uc->uc_sigmask, puc);
bellard8c6939c2003-06-09 15:28:00 +00001349}
1350
bellard38e584a2003-08-10 22:14:22 +00001351#elif defined(__mc68000)
1352
ths5fafdf22007-09-16 21:08:06 +00001353int cpu_signal_handler(int host_signum, void *pinfo,
bellard38e584a2003-08-10 22:14:22 +00001354 void *puc)
1355{
ths5a7b5422007-01-31 12:16:51 +00001356 siginfo_t *info = pinfo;
bellard38e584a2003-08-10 22:14:22 +00001357 struct ucontext *uc = puc;
1358 unsigned long pc;
1359 int is_write;
ths3b46e622007-09-17 08:09:54 +00001360
bellard38e584a2003-08-10 22:14:22 +00001361 pc = uc->uc_mcontext.gregs[16];
1362 /* XXX: compute is_write */
1363 is_write = 0;
ths5fafdf22007-09-16 21:08:06 +00001364 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellard38e584a2003-08-10 22:14:22 +00001365 is_write,
bellardbf3e8bf2004-02-16 21:58:54 +00001366 &uc->uc_sigmask, puc);
bellard38e584a2003-08-10 22:14:22 +00001367}
1368
bellardb8076a72005-04-07 22:20:31 +00001369#elif defined(__ia64)
1370
1371#ifndef __ISR_VALID
1372 /* This ought to be in <bits/siginfo.h>... */
1373# define __ISR_VALID 1
bellardb8076a72005-04-07 22:20:31 +00001374#endif
1375
ths5a7b5422007-01-31 12:16:51 +00001376int cpu_signal_handler(int host_signum, void *pinfo, void *puc)
bellardb8076a72005-04-07 22:20:31 +00001377{
ths5a7b5422007-01-31 12:16:51 +00001378 siginfo_t *info = pinfo;
bellardb8076a72005-04-07 22:20:31 +00001379 struct ucontext *uc = puc;
1380 unsigned long ip;
1381 int is_write = 0;
1382
1383 ip = uc->uc_mcontext.sc_ip;
1384 switch (host_signum) {
1385 case SIGILL:
1386 case SIGFPE:
1387 case SIGSEGV:
1388 case SIGBUS:
1389 case SIGTRAP:
bellardfd4a43e2006-04-24 20:32:17 +00001390 if (info->si_code && (info->si_segvflags & __ISR_VALID))
bellardb8076a72005-04-07 22:20:31 +00001391 /* ISR.W (write-access) is bit 33: */
1392 is_write = (info->si_isr >> 33) & 1;
1393 break;
1394
1395 default:
1396 break;
1397 }
1398 return handle_cpu_signal(ip, (unsigned long)info->si_addr,
1399 is_write,
1400 &uc->uc_sigmask, puc);
1401}
1402
bellard90cb9492005-07-24 15:11:38 +00001403#elif defined(__s390__)
1404
ths5fafdf22007-09-16 21:08:06 +00001405int cpu_signal_handler(int host_signum, void *pinfo,
bellard90cb9492005-07-24 15:11:38 +00001406 void *puc)
1407{
ths5a7b5422007-01-31 12:16:51 +00001408 siginfo_t *info = pinfo;
bellard90cb9492005-07-24 15:11:38 +00001409 struct ucontext *uc = puc;
1410 unsigned long pc;
1411 int is_write;
ths3b46e622007-09-17 08:09:54 +00001412
bellard90cb9492005-07-24 15:11:38 +00001413 pc = uc->uc_mcontext.psw.addr;
1414 /* XXX: compute is_write */
1415 is_write = 0;
ths5fafdf22007-09-16 21:08:06 +00001416 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
thsc4b89d12007-05-05 19:23:11 +00001417 is_write, &uc->uc_sigmask, puc);
1418}
1419
1420#elif defined(__mips__)
1421
ths5fafdf22007-09-16 21:08:06 +00001422int cpu_signal_handler(int host_signum, void *pinfo,
thsc4b89d12007-05-05 19:23:11 +00001423 void *puc)
1424{
ths9617efe2007-05-08 21:05:55 +00001425 siginfo_t *info = pinfo;
thsc4b89d12007-05-05 19:23:11 +00001426 struct ucontext *uc = puc;
1427 greg_t pc = uc->uc_mcontext.pc;
1428 int is_write;
ths3b46e622007-09-17 08:09:54 +00001429
thsc4b89d12007-05-05 19:23:11 +00001430 /* XXX: compute is_write */
1431 is_write = 0;
ths5fafdf22007-09-16 21:08:06 +00001432 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
thsc4b89d12007-05-05 19:23:11 +00001433 is_write, &uc->uc_sigmask, puc);
bellard90cb9492005-07-24 15:11:38 +00001434}
1435
aurel32f54b3f92008-04-12 20:14:54 +00001436#elif defined(__hppa__)
1437
1438int cpu_signal_handler(int host_signum, void *pinfo,
1439 void *puc)
1440{
1441 struct siginfo *info = pinfo;
1442 struct ucontext *uc = puc;
1443 unsigned long pc;
1444 int is_write;
1445
1446 pc = uc->uc_mcontext.sc_iaoq[0];
1447 /* FIXME: compute is_write */
1448 is_write = 0;
1449 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1450 is_write,
1451 &uc->uc_sigmask, puc);
1452}
1453
bellard2b413142003-05-14 23:01:10 +00001454#else
1455
bellard3fb2ded2003-06-24 13:22:59 +00001456#error host CPU specific signal handler needed
bellard2b413142003-05-14 23:01:10 +00001457
1458#endif
bellard67b915a2004-03-31 23:37:16 +00001459
1460#endif /* !defined(CONFIG_SOFTMMU) */