blob: 05deafbdd2c53843a76f7139a047e2986067a2f0 [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
aliguoridde23672008-11-18 20:50:36 +0000186static CPUDebugExcpHandler *debug_excp_handler;
187
188CPUDebugExcpHandler *cpu_set_debug_excp_handler(CPUDebugExcpHandler *handler)
189{
190 CPUDebugExcpHandler *old_handler = debug_excp_handler;
191
192 debug_excp_handler = handler;
193 return old_handler;
194}
195
aliguori6e140f22008-11-18 20:37:55 +0000196static void cpu_handle_debug_exception(CPUState *env)
197{
198 CPUWatchpoint *wp;
199
200 if (!env->watchpoint_hit)
201 for (wp = env->watchpoints; wp != NULL; wp = wp->next)
202 wp->flags &= ~BP_WATCHPOINT_HIT;
aliguoridde23672008-11-18 20:50:36 +0000203
204 if (debug_excp_handler)
205 debug_excp_handler(env);
aliguori6e140f22008-11-18 20:37:55 +0000206}
207
bellard7d132992003-03-06 23:23:54 +0000208/* main execution loop */
209
bellarde4533c72003-06-15 19:51:39 +0000210int cpu_exec(CPUState *env1)
bellard7d132992003-03-06 23:23:54 +0000211{
pbrook1057eaa2007-02-04 13:37:44 +0000212#define DECLARE_HOST_REGS 1
213#include "hostregs_helper.h"
bellard8a40a182005-11-20 10:35:40 +0000214 int ret, interrupt_request;
bellard8a40a182005-11-20 10:35:40 +0000215 TranslationBlock *tb;
bellardc27004e2005-01-03 23:35:10 +0000216 uint8_t *tc_ptr;
pbrookd5975362008-06-07 20:50:51 +0000217 unsigned long next_tb;
bellard8c6939c2003-06-09 15:28:00 +0000218
thsbfed01f2007-06-03 17:44:37 +0000219 if (cpu_halted(env1) == EXCP_HALTED)
220 return EXCP_HALTED;
bellard5a1e3cf2005-11-23 21:02:53 +0000221
ths5fafdf22007-09-16 21:08:06 +0000222 cpu_single_env = env1;
bellard6a00d602005-11-21 23:25:50 +0000223
bellard7d132992003-03-06 23:23:54 +0000224 /* first we save global registers */
pbrook1057eaa2007-02-04 13:37:44 +0000225#define SAVE_HOST_REGS 1
226#include "hostregs_helper.h"
bellardc27004e2005-01-03 23:35:10 +0000227 env = env1;
bellarde4533c72003-06-15 19:51:39 +0000228
bellard0d1a29f2004-10-12 22:01:28 +0000229 env_to_regs();
thsecb644f2007-06-03 18:45:53 +0000230#if defined(TARGET_I386)
bellard9de5e442003-03-23 16:49:39 +0000231 /* put eflags in CPU temporary format */
bellardfc2b4c42003-03-29 16:52:44 +0000232 CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
233 DF = 1 - (2 * ((env->eflags >> 10) & 1));
bellard9de5e442003-03-23 16:49:39 +0000234 CC_OP = CC_OP_EFLAGS;
bellardfc2b4c42003-03-29 16:52:44 +0000235 env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
bellard93ac68b2003-09-30 20:57:29 +0000236#elif defined(TARGET_SPARC)
pbrooke6e59062006-10-22 00:18:54 +0000237#elif defined(TARGET_M68K)
238 env->cc_op = CC_OP_FLAGS;
239 env->cc_dest = env->sr & 0xf;
240 env->cc_x = (env->sr >> 4) & 1;
thsecb644f2007-06-03 18:45:53 +0000241#elif defined(TARGET_ALPHA)
242#elif defined(TARGET_ARM)
243#elif defined(TARGET_PPC)
bellard6af0bf92005-07-02 14:58:51 +0000244#elif defined(TARGET_MIPS)
bellardfdf9b3e2006-04-27 21:07:38 +0000245#elif defined(TARGET_SH4)
thsf1ccf902007-10-08 13:16:14 +0000246#elif defined(TARGET_CRIS)
bellardfdf9b3e2006-04-27 21:07:38 +0000247 /* XXXXX */
bellarde4533c72003-06-15 19:51:39 +0000248#else
249#error unsupported target CPU
250#endif
bellard3fb2ded2003-06-24 13:22:59 +0000251 env->exception_index = -1;
bellard9d27abd2003-05-10 13:13:54 +0000252
bellard7d132992003-03-06 23:23:54 +0000253 /* prepare setjmp context for exception handling */
bellard3fb2ded2003-06-24 13:22:59 +0000254 for(;;) {
255 if (setjmp(env->jmp_env) == 0) {
bellardee8b7022004-02-03 23:35:10 +0000256 env->current_tb = NULL;
bellard3fb2ded2003-06-24 13:22:59 +0000257 /* if an exception is pending, we execute it here */
258 if (env->exception_index >= 0) {
259 if (env->exception_index >= EXCP_INTERRUPT) {
260 /* exit request from the cpu execution loop */
261 ret = env->exception_index;
aliguori6e140f22008-11-18 20:37:55 +0000262 if (ret == EXCP_DEBUG)
263 cpu_handle_debug_exception(env);
bellard3fb2ded2003-06-24 13:22:59 +0000264 break;
265 } else if (env->user_mode_only) {
266 /* if user mode only, we simulate a fake exception
ths9f083492006-12-07 18:28:42 +0000267 which will be handled outside the cpu execution
bellard3fb2ded2003-06-24 13:22:59 +0000268 loop */
bellard83479e72003-06-25 16:12:37 +0000269#if defined(TARGET_I386)
ths5fafdf22007-09-16 21:08:06 +0000270 do_interrupt_user(env->exception_index,
271 env->exception_is_int,
272 env->error_code,
bellard3fb2ded2003-06-24 13:22:59 +0000273 env->exception_next_eip);
bellardeba01622008-05-12 12:04:40 +0000274 /* successfully delivered */
275 env->old_exception = -1;
bellard83479e72003-06-25 16:12:37 +0000276#endif
bellard3fb2ded2003-06-24 13:22:59 +0000277 ret = env->exception_index;
278 break;
279 } else {
bellard83479e72003-06-25 16:12:37 +0000280#if defined(TARGET_I386)
bellard3fb2ded2003-06-24 13:22:59 +0000281 /* simulate a real cpu exception. On i386, it can
282 trigger new exceptions, but we do not handle
283 double or triple faults yet. */
ths5fafdf22007-09-16 21:08:06 +0000284 do_interrupt(env->exception_index,
285 env->exception_is_int,
286 env->error_code,
bellardd05e66d2003-08-20 21:34:35 +0000287 env->exception_next_eip, 0);
ths678dde12007-03-31 20:28:52 +0000288 /* successfully delivered */
289 env->old_exception = -1;
bellardce097762004-01-04 23:53:18 +0000290#elif defined(TARGET_PPC)
291 do_interrupt(env);
bellard6af0bf92005-07-02 14:58:51 +0000292#elif defined(TARGET_MIPS)
293 do_interrupt(env);
bellarde95c8d52004-09-30 22:22:08 +0000294#elif defined(TARGET_SPARC)
blueswir1f2bc7e72008-05-27 17:35:30 +0000295 do_interrupt(env);
bellardb5ff1b32005-11-26 10:38:39 +0000296#elif defined(TARGET_ARM)
297 do_interrupt(env);
bellardfdf9b3e2006-04-27 21:07:38 +0000298#elif defined(TARGET_SH4)
299 do_interrupt(env);
j_mayereddf68a2007-04-05 07:22:49 +0000300#elif defined(TARGET_ALPHA)
301 do_interrupt(env);
thsf1ccf902007-10-08 13:16:14 +0000302#elif defined(TARGET_CRIS)
303 do_interrupt(env);
pbrook06338792007-05-23 19:58:11 +0000304#elif defined(TARGET_M68K)
305 do_interrupt(0);
bellard83479e72003-06-25 16:12:37 +0000306#endif
bellard3fb2ded2003-06-24 13:22:59 +0000307 }
308 env->exception_index = -1;
ths5fafdf22007-09-16 21:08:06 +0000309 }
bellard9df217a2005-02-10 22:05:51 +0000310#ifdef USE_KQEMU
311 if (kqemu_is_ok(env) && env->interrupt_request == 0) {
312 int ret;
pbrooka7812ae2008-11-17 14:43:54 +0000313 env->eflags = env->eflags | helper_cc_compute_all(CC_OP) | (DF & DF_MASK);
bellard9df217a2005-02-10 22:05:51 +0000314 ret = kqemu_cpu_exec(env);
315 /* put eflags in CPU temporary format */
316 CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
317 DF = 1 - (2 * ((env->eflags >> 10) & 1));
318 CC_OP = CC_OP_EFLAGS;
319 env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
320 if (ret == 1) {
321 /* exception */
322 longjmp(env->jmp_env, 1);
323 } else if (ret == 2) {
324 /* softmmu execution needed */
325 } else {
326 if (env->interrupt_request != 0) {
327 /* hardware interrupt will be executed just after */
328 } else {
329 /* otherwise, we restart */
330 longjmp(env->jmp_env, 1);
331 }
332 }
bellard9de5e442003-03-23 16:49:39 +0000333 }
bellard9df217a2005-02-10 22:05:51 +0000334#endif
335
aliguori7ba1e612008-11-05 16:04:33 +0000336 if (kvm_enabled()) {
aliguoribecfc392008-11-10 15:55:14 +0000337 kvm_cpu_exec(env);
338 longjmp(env->jmp_env, 1);
aliguori7ba1e612008-11-05 16:04:33 +0000339 }
340
blueswir1b5fc09a2008-05-04 06:38:18 +0000341 next_tb = 0; /* force lookup of first TB */
bellard3fb2ded2003-06-24 13:22:59 +0000342 for(;;) {
bellard68a79312003-06-30 13:12:32 +0000343 interrupt_request = env->interrupt_request;
malce1638bd2008-11-06 18:54:46 +0000344 if (unlikely(interrupt_request)) {
345 if (unlikely(env->singlestep_enabled & SSTEP_NOIRQ)) {
346 /* Mask out external interrupts for this step. */
347 interrupt_request &= ~(CPU_INTERRUPT_HARD |
348 CPU_INTERRUPT_FIQ |
349 CPU_INTERRUPT_SMI |
350 CPU_INTERRUPT_NMI);
351 }
pbrook6658ffb2007-03-16 23:58:11 +0000352 if (interrupt_request & CPU_INTERRUPT_DEBUG) {
353 env->interrupt_request &= ~CPU_INTERRUPT_DEBUG;
354 env->exception_index = EXCP_DEBUG;
355 cpu_loop_exit();
356 }
balroga90b7312007-05-01 01:28:01 +0000357#if defined(TARGET_ARM) || defined(TARGET_SPARC) || defined(TARGET_MIPS) || \
thsf1ccf902007-10-08 13:16:14 +0000358 defined(TARGET_PPC) || defined(TARGET_ALPHA) || defined(TARGET_CRIS)
balroga90b7312007-05-01 01:28:01 +0000359 if (interrupt_request & CPU_INTERRUPT_HALT) {
360 env->interrupt_request &= ~CPU_INTERRUPT_HALT;
361 env->halted = 1;
362 env->exception_index = EXCP_HLT;
363 cpu_loop_exit();
364 }
365#endif
bellard68a79312003-06-30 13:12:32 +0000366#if defined(TARGET_I386)
bellarddb620f42008-06-04 17:02:19 +0000367 if (env->hflags2 & HF2_GIF_MASK) {
368 if ((interrupt_request & CPU_INTERRUPT_SMI) &&
369 !(env->hflags & HF_SMM_MASK)) {
370 svm_check_intercept(SVM_EXIT_SMI);
371 env->interrupt_request &= ~CPU_INTERRUPT_SMI;
372 do_smm_enter();
373 next_tb = 0;
374 } else if ((interrupt_request & CPU_INTERRUPT_NMI) &&
375 !(env->hflags2 & HF2_NMI_MASK)) {
376 env->interrupt_request &= ~CPU_INTERRUPT_NMI;
377 env->hflags2 |= HF2_NMI_MASK;
378 do_interrupt(EXCP02_NMI, 0, 0, 0, 1);
379 next_tb = 0;
380 } else if ((interrupt_request & CPU_INTERRUPT_HARD) &&
381 (((env->hflags2 & HF2_VINTR_MASK) &&
382 (env->hflags2 & HF2_HIF_MASK)) ||
383 (!(env->hflags2 & HF2_VINTR_MASK) &&
384 (env->eflags & IF_MASK &&
385 !(env->hflags & HF_INHIBIT_IRQ_MASK))))) {
386 int intno;
387 svm_check_intercept(SVM_EXIT_INTR);
388 env->interrupt_request &= ~(CPU_INTERRUPT_HARD | CPU_INTERRUPT_VIRQ);
389 intno = cpu_get_pic_interrupt(env);
390 if (loglevel & CPU_LOG_TB_IN_ASM) {
391 fprintf(logfile, "Servicing hardware INT=0x%02x\n", intno);
392 }
393 do_interrupt(intno, 0, 0, 0, 1);
394 /* ensure that no TB jump will be modified as
395 the program flow was changed */
396 next_tb = 0;
ths0573fbf2007-09-23 15:28:04 +0000397#if !defined(CONFIG_USER_ONLY)
bellarddb620f42008-06-04 17:02:19 +0000398 } else if ((interrupt_request & CPU_INTERRUPT_VIRQ) &&
399 (env->eflags & IF_MASK) &&
400 !(env->hflags & HF_INHIBIT_IRQ_MASK)) {
401 int intno;
402 /* FIXME: this should respect TPR */
403 svm_check_intercept(SVM_EXIT_VINTR);
404 env->interrupt_request &= ~CPU_INTERRUPT_VIRQ;
405 intno = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_vector));
406 if (loglevel & CPU_LOG_TB_IN_ASM)
407 fprintf(logfile, "Servicing virtual hardware INT=0x%02x\n", intno);
408 do_interrupt(intno, 0, 0, 0, 1);
409 next_tb = 0;
ths0573fbf2007-09-23 15:28:04 +0000410#endif
bellarddb620f42008-06-04 17:02:19 +0000411 }
bellard68a79312003-06-30 13:12:32 +0000412 }
bellardce097762004-01-04 23:53:18 +0000413#elif defined(TARGET_PPC)
bellard9fddaa02004-05-21 12:59:32 +0000414#if 0
415 if ((interrupt_request & CPU_INTERRUPT_RESET)) {
416 cpu_ppc_reset(env);
417 }
418#endif
j_mayer47103572007-03-30 09:38:04 +0000419 if (interrupt_request & CPU_INTERRUPT_HARD) {
j_mayere9df0142007-04-09 22:45:36 +0000420 ppc_hw_interrupt(env);
421 if (env->pending_interrupts == 0)
422 env->interrupt_request &= ~CPU_INTERRUPT_HARD;
blueswir1b5fc09a2008-05-04 06:38:18 +0000423 next_tb = 0;
bellardce097762004-01-04 23:53:18 +0000424 }
bellard6af0bf92005-07-02 14:58:51 +0000425#elif defined(TARGET_MIPS)
426 if ((interrupt_request & CPU_INTERRUPT_HARD) &&
ths24c7b0e2007-03-30 16:44:54 +0000427 (env->CP0_Status & env->CP0_Cause & CP0Ca_IP_mask) &&
bellard6af0bf92005-07-02 14:58:51 +0000428 (env->CP0_Status & (1 << CP0St_IE)) &&
ths24c7b0e2007-03-30 16:44:54 +0000429 !(env->CP0_Status & (1 << CP0St_EXL)) &&
430 !(env->CP0_Status & (1 << CP0St_ERL)) &&
bellard6af0bf92005-07-02 14:58:51 +0000431 !(env->hflags & MIPS_HFLAG_DM)) {
432 /* Raise it */
433 env->exception_index = EXCP_EXT_INTERRUPT;
434 env->error_code = 0;
435 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000436 next_tb = 0;
bellard6af0bf92005-07-02 14:58:51 +0000437 }
bellarde95c8d52004-09-30 22:22:08 +0000438#elif defined(TARGET_SPARC)
bellard66321a12005-04-06 20:47:48 +0000439 if ((interrupt_request & CPU_INTERRUPT_HARD) &&
440 (env->psret != 0)) {
441 int pil = env->interrupt_index & 15;
442 int type = env->interrupt_index & 0xf0;
443
444 if (((type == TT_EXTINT) &&
445 (pil == 15 || pil > env->psrpil)) ||
446 type != TT_EXTINT) {
447 env->interrupt_request &= ~CPU_INTERRUPT_HARD;
blueswir1f2bc7e72008-05-27 17:35:30 +0000448 env->exception_index = env->interrupt_index;
449 do_interrupt(env);
bellard66321a12005-04-06 20:47:48 +0000450 env->interrupt_index = 0;
blueswir1327ac2e2007-08-04 10:50:30 +0000451#if !defined(TARGET_SPARC64) && !defined(CONFIG_USER_ONLY)
452 cpu_check_irqs(env);
453#endif
blueswir1b5fc09a2008-05-04 06:38:18 +0000454 next_tb = 0;
bellard66321a12005-04-06 20:47:48 +0000455 }
bellarde95c8d52004-09-30 22:22:08 +0000456 } else if (interrupt_request & CPU_INTERRUPT_TIMER) {
457 //do_interrupt(0, 0, 0, 0, 0);
458 env->interrupt_request &= ~CPU_INTERRUPT_TIMER;
balroga90b7312007-05-01 01:28:01 +0000459 }
bellardb5ff1b32005-11-26 10:38:39 +0000460#elif defined(TARGET_ARM)
461 if (interrupt_request & CPU_INTERRUPT_FIQ
462 && !(env->uncached_cpsr & CPSR_F)) {
463 env->exception_index = EXCP_FIQ;
464 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000465 next_tb = 0;
bellardb5ff1b32005-11-26 10:38:39 +0000466 }
pbrook9ee6e8b2007-11-11 00:04:49 +0000467 /* ARMv7-M interrupt return works by loading a magic value
468 into the PC. On real hardware the load causes the
469 return to occur. The qemu implementation performs the
470 jump normally, then does the exception return when the
471 CPU tries to execute code at the magic address.
472 This will cause the magic PC value to be pushed to
473 the stack if an interrupt occured at the wrong time.
474 We avoid this by disabling interrupts when
475 pc contains a magic address. */
bellardb5ff1b32005-11-26 10:38:39 +0000476 if (interrupt_request & CPU_INTERRUPT_HARD
pbrook9ee6e8b2007-11-11 00:04:49 +0000477 && ((IS_M(env) && env->regs[15] < 0xfffffff0)
478 || !(env->uncached_cpsr & CPSR_I))) {
bellardb5ff1b32005-11-26 10:38:39 +0000479 env->exception_index = EXCP_IRQ;
480 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000481 next_tb = 0;
bellardb5ff1b32005-11-26 10:38:39 +0000482 }
bellardfdf9b3e2006-04-27 21:07:38 +0000483#elif defined(TARGET_SH4)
thse96e2042007-12-02 06:18:24 +0000484 if (interrupt_request & CPU_INTERRUPT_HARD) {
485 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000486 next_tb = 0;
thse96e2042007-12-02 06:18:24 +0000487 }
j_mayereddf68a2007-04-05 07:22:49 +0000488#elif defined(TARGET_ALPHA)
489 if (interrupt_request & CPU_INTERRUPT_HARD) {
490 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000491 next_tb = 0;
j_mayereddf68a2007-04-05 07:22:49 +0000492 }
thsf1ccf902007-10-08 13:16:14 +0000493#elif defined(TARGET_CRIS)
edgar_igl1b1a38b2008-06-09 23:18:06 +0000494 if (interrupt_request & CPU_INTERRUPT_HARD
495 && (env->pregs[PR_CCS] & I_FLAG)) {
496 env->exception_index = EXCP_IRQ;
497 do_interrupt(env);
498 next_tb = 0;
499 }
500 if (interrupt_request & CPU_INTERRUPT_NMI
501 && (env->pregs[PR_CCS] & M_FLAG)) {
502 env->exception_index = EXCP_NMI;
thsf1ccf902007-10-08 13:16:14 +0000503 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000504 next_tb = 0;
thsf1ccf902007-10-08 13:16:14 +0000505 }
pbrook06338792007-05-23 19:58:11 +0000506#elif defined(TARGET_M68K)
507 if (interrupt_request & CPU_INTERRUPT_HARD
508 && ((env->sr & SR_I) >> SR_I_SHIFT)
509 < env->pending_level) {
510 /* Real hardware gets the interrupt vector via an
511 IACK cycle at this point. Current emulated
512 hardware doesn't rely on this, so we
513 provide/save the vector when the interrupt is
514 first signalled. */
515 env->exception_index = env->pending_vector;
516 do_interrupt(1);
blueswir1b5fc09a2008-05-04 06:38:18 +0000517 next_tb = 0;
pbrook06338792007-05-23 19:58:11 +0000518 }
bellard68a79312003-06-30 13:12:32 +0000519#endif
bellard9d050952006-05-22 22:03:52 +0000520 /* Don't use the cached interupt_request value,
521 do_interrupt may have updated the EXITTB flag. */
bellardb5ff1b32005-11-26 10:38:39 +0000522 if (env->interrupt_request & CPU_INTERRUPT_EXITTB) {
bellardbf3e8bf2004-02-16 21:58:54 +0000523 env->interrupt_request &= ~CPU_INTERRUPT_EXITTB;
524 /* ensure that no TB jump will be modified as
525 the program flow was changed */
blueswir1b5fc09a2008-05-04 06:38:18 +0000526 next_tb = 0;
bellardbf3e8bf2004-02-16 21:58:54 +0000527 }
bellard68a79312003-06-30 13:12:32 +0000528 if (interrupt_request & CPU_INTERRUPT_EXIT) {
529 env->interrupt_request &= ~CPU_INTERRUPT_EXIT;
530 env->exception_index = EXCP_INTERRUPT;
531 cpu_loop_exit();
532 }
bellard3fb2ded2003-06-24 13:22:59 +0000533 }
534#ifdef DEBUG_EXEC
bellardb5ff1b32005-11-26 10:38:39 +0000535 if ((loglevel & CPU_LOG_TB_CPU)) {
bellard3fb2ded2003-06-24 13:22:59 +0000536 /* restore flags in standard format */
thsecb644f2007-06-03 18:45:53 +0000537 regs_to_env();
538#if defined(TARGET_I386)
pbrooka7812ae2008-11-17 14:43:54 +0000539 env->eflags = env->eflags | helper_cc_compute_all(CC_OP) | (DF & DF_MASK);
bellard7fe48482004-10-09 18:08:01 +0000540 cpu_dump_state(env, logfile, fprintf, X86_DUMP_CCOP);
bellard3fb2ded2003-06-24 13:22:59 +0000541 env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
bellarde4533c72003-06-15 19:51:39 +0000542#elif defined(TARGET_ARM)
bellard7fe48482004-10-09 18:08:01 +0000543 cpu_dump_state(env, logfile, fprintf, 0);
bellard93ac68b2003-09-30 20:57:29 +0000544#elif defined(TARGET_SPARC)
bellard34751872005-07-02 14:31:34 +0000545 cpu_dump_state(env, logfile, fprintf, 0);
bellard67867302003-11-23 17:05:30 +0000546#elif defined(TARGET_PPC)
bellard7fe48482004-10-09 18:08:01 +0000547 cpu_dump_state(env, logfile, fprintf, 0);
pbrooke6e59062006-10-22 00:18:54 +0000548#elif defined(TARGET_M68K)
549 cpu_m68k_flush_flags(env, env->cc_op);
550 env->cc_op = CC_OP_FLAGS;
551 env->sr = (env->sr & 0xffe0)
552 | env->cc_dest | (env->cc_x << 4);
553 cpu_dump_state(env, logfile, fprintf, 0);
bellard6af0bf92005-07-02 14:58:51 +0000554#elif defined(TARGET_MIPS)
555 cpu_dump_state(env, logfile, fprintf, 0);
bellardfdf9b3e2006-04-27 21:07:38 +0000556#elif defined(TARGET_SH4)
557 cpu_dump_state(env, logfile, fprintf, 0);
j_mayereddf68a2007-04-05 07:22:49 +0000558#elif defined(TARGET_ALPHA)
559 cpu_dump_state(env, logfile, fprintf, 0);
thsf1ccf902007-10-08 13:16:14 +0000560#elif defined(TARGET_CRIS)
561 cpu_dump_state(env, logfile, fprintf, 0);
bellarde4533c72003-06-15 19:51:39 +0000562#else
ths5fafdf22007-09-16 21:08:06 +0000563#error unsupported target CPU
bellarde4533c72003-06-15 19:51:39 +0000564#endif
bellard3fb2ded2003-06-24 13:22:59 +0000565 }
bellard7d132992003-03-06 23:23:54 +0000566#endif
pbrookd5975362008-06-07 20:50:51 +0000567 spin_lock(&tb_lock);
bellard8a40a182005-11-20 10:35:40 +0000568 tb = tb_find_fast();
pbrookd5975362008-06-07 20:50:51 +0000569 /* Note: we do it here to avoid a gcc bug on Mac OS X when
570 doing it in tb_find_slow */
571 if (tb_invalidated_flag) {
572 /* as some TB could have been invalidated because
573 of memory exceptions while generating the code, we
574 must recompute the hash index here */
575 next_tb = 0;
pbrook2e70f6e2008-06-29 01:03:05 +0000576 tb_invalidated_flag = 0;
pbrookd5975362008-06-07 20:50:51 +0000577 }
bellard9d27abd2003-05-10 13:13:54 +0000578#ifdef DEBUG_EXEC
bellardc1135f62005-01-30 22:41:54 +0000579 if ((loglevel & CPU_LOG_EXEC)) {
bellardc27004e2005-01-03 23:35:10 +0000580 fprintf(logfile, "Trace 0x%08lx [" TARGET_FMT_lx "] %s\n",
581 (long)tb->tc_ptr, tb->pc,
582 lookup_symbol(tb->pc));
bellard3fb2ded2003-06-24 13:22:59 +0000583 }
bellard9d27abd2003-05-10 13:13:54 +0000584#endif
bellard8a40a182005-11-20 10:35:40 +0000585 /* see if we can patch the calling TB. When the TB
586 spans two pages, we cannot safely do a direct
587 jump. */
bellardc27004e2005-01-03 23:35:10 +0000588 {
blueswir1b5fc09a2008-05-04 06:38:18 +0000589 if (next_tb != 0 &&
blueswir14d7a0882008-05-10 10:14:22 +0000590#ifdef USE_KQEMU
bellardf32fc642006-02-08 22:43:39 +0000591 (env->kqemu_enabled != 2) &&
592#endif
bellardec6338b2007-11-08 14:25:03 +0000593 tb->page_addr[1] == -1) {
blueswir1b5fc09a2008-05-04 06:38:18 +0000594 tb_add_jump((TranslationBlock *)(next_tb & ~3), next_tb & 3, tb);
bellard3fb2ded2003-06-24 13:22:59 +0000595 }
bellardc27004e2005-01-03 23:35:10 +0000596 }
pbrookd5975362008-06-07 20:50:51 +0000597 spin_unlock(&tb_lock);
bellard83479e72003-06-25 16:12:37 +0000598 env->current_tb = tb;
malc55e8b852008-11-04 14:18:13 +0000599
600 /* cpu_interrupt might be called while translating the
601 TB, but before it is linked into a potentially
602 infinite loop and becomes env->current_tb. Avoid
603 starting execution if there is a pending interrupt. */
604 if (unlikely (env->interrupt_request & CPU_INTERRUPT_EXIT))
605 env->current_tb = NULL;
606
pbrook2e70f6e2008-06-29 01:03:05 +0000607 while (env->current_tb) {
608 tc_ptr = tb->tc_ptr;
bellard3fb2ded2003-06-24 13:22:59 +0000609 /* execute the generated code */
blueswir1572a9d42008-05-17 07:38:10 +0000610#if defined(__sparc__) && !defined(HOST_SOLARIS)
611#undef env
pbrook2e70f6e2008-06-29 01:03:05 +0000612 env = cpu_single_env;
blueswir1572a9d42008-05-17 07:38:10 +0000613#define env cpu_single_env
614#endif
pbrook2e70f6e2008-06-29 01:03:05 +0000615 next_tb = tcg_qemu_tb_exec(tc_ptr);
616 env->current_tb = NULL;
617 if ((next_tb & 3) == 2) {
thsbf20dc02008-06-30 17:22:19 +0000618 /* Instruction counter expired. */
pbrook2e70f6e2008-06-29 01:03:05 +0000619 int insns_left;
620 tb = (TranslationBlock *)(long)(next_tb & ~3);
621 /* Restore PC. */
aliguori622ed362008-11-18 19:36:03 +0000622 cpu_pc_from_tb(env, tb);
pbrook2e70f6e2008-06-29 01:03:05 +0000623 insns_left = env->icount_decr.u32;
624 if (env->icount_extra && insns_left >= 0) {
625 /* Refill decrementer and continue execution. */
626 env->icount_extra += insns_left;
627 if (env->icount_extra > 0xffff) {
628 insns_left = 0xffff;
629 } else {
630 insns_left = env->icount_extra;
631 }
632 env->icount_extra -= insns_left;
633 env->icount_decr.u16.low = insns_left;
634 } else {
635 if (insns_left > 0) {
636 /* Execute remaining instructions. */
637 cpu_exec_nocache(insns_left, tb);
638 }
639 env->exception_index = EXCP_INTERRUPT;
640 next_tb = 0;
641 cpu_loop_exit();
642 }
643 }
644 }
bellard4cbf74b2003-08-10 21:48:43 +0000645 /* reset soft MMU for next block (it can currently
646 only be set by a memory fault) */
bellardf32fc642006-02-08 22:43:39 +0000647#if defined(USE_KQEMU)
648#define MIN_CYCLE_BEFORE_SWITCH (100 * 1000)
649 if (kqemu_is_ok(env) &&
650 (cpu_get_time_fast() - env->last_io_time) >= MIN_CYCLE_BEFORE_SWITCH) {
651 cpu_loop_exit();
652 }
653#endif
ths50a518e2007-06-03 18:52:15 +0000654 } /* for(;;) */
bellard3fb2ded2003-06-24 13:22:59 +0000655 } else {
bellard0d1a29f2004-10-12 22:01:28 +0000656 env_to_regs();
bellard7d132992003-03-06 23:23:54 +0000657 }
bellard3fb2ded2003-06-24 13:22:59 +0000658 } /* for(;;) */
659
bellard7d132992003-03-06 23:23:54 +0000660
bellarde4533c72003-06-15 19:51:39 +0000661#if defined(TARGET_I386)
bellard9de5e442003-03-23 16:49:39 +0000662 /* restore flags in standard format */
pbrooka7812ae2008-11-17 14:43:54 +0000663 env->eflags = env->eflags | helper_cc_compute_all(CC_OP) | (DF & DF_MASK);
bellarde4533c72003-06-15 19:51:39 +0000664#elif defined(TARGET_ARM)
bellardb7bcbe92005-02-22 19:27:29 +0000665 /* XXX: Save/restore host fpu exception state?. */
bellard93ac68b2003-09-30 20:57:29 +0000666#elif defined(TARGET_SPARC)
bellard67867302003-11-23 17:05:30 +0000667#elif defined(TARGET_PPC)
pbrooke6e59062006-10-22 00:18:54 +0000668#elif defined(TARGET_M68K)
669 cpu_m68k_flush_flags(env, env->cc_op);
670 env->cc_op = CC_OP_FLAGS;
671 env->sr = (env->sr & 0xffe0)
672 | env->cc_dest | (env->cc_x << 4);
bellard6af0bf92005-07-02 14:58:51 +0000673#elif defined(TARGET_MIPS)
bellardfdf9b3e2006-04-27 21:07:38 +0000674#elif defined(TARGET_SH4)
j_mayereddf68a2007-04-05 07:22:49 +0000675#elif defined(TARGET_ALPHA)
thsf1ccf902007-10-08 13:16:14 +0000676#elif defined(TARGET_CRIS)
bellardfdf9b3e2006-04-27 21:07:38 +0000677 /* XXXXX */
bellarde4533c72003-06-15 19:51:39 +0000678#else
679#error unsupported target CPU
680#endif
pbrook1057eaa2007-02-04 13:37:44 +0000681
682 /* restore global registers */
pbrook1057eaa2007-02-04 13:37:44 +0000683#include "hostregs_helper.h"
684
bellard6a00d602005-11-21 23:25:50 +0000685 /* fail safe : never use cpu_single_env outside cpu_exec() */
ths5fafdf22007-09-16 21:08:06 +0000686 cpu_single_env = NULL;
bellard7d132992003-03-06 23:23:54 +0000687 return ret;
688}
bellard6dbad632003-03-16 18:05:05 +0000689
bellardfbf9eeb2004-04-25 21:21:33 +0000690/* must only be called from the generated code as an exception can be
691 generated */
692void tb_invalidate_page_range(target_ulong start, target_ulong end)
693{
bellarddc5d0b32004-06-22 18:43:30 +0000694 /* XXX: cannot enable it yet because it yields to MMU exception
695 where NIP != read address on PowerPC */
696#if 0
bellardfbf9eeb2004-04-25 21:21:33 +0000697 target_ulong phys_addr;
698 phys_addr = get_phys_addr_code(env, start);
699 tb_invalidate_phys_page_range(phys_addr, phys_addr + end - start, 0);
bellarddc5d0b32004-06-22 18:43:30 +0000700#endif
bellardfbf9eeb2004-04-25 21:21:33 +0000701}
702
bellard1a18c712003-10-30 01:07:51 +0000703#if defined(TARGET_I386) && defined(CONFIG_USER_ONLY)
bellarde4533c72003-06-15 19:51:39 +0000704
bellard6dbad632003-03-16 18:05:05 +0000705void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector)
706{
707 CPUX86State *saved_env;
708
709 saved_env = env;
710 env = s;
bellarda412ac52003-07-26 18:01:40 +0000711 if (!(env->cr[0] & CR0_PE_MASK) || (env->eflags & VM_MASK)) {
bellarda513fe12003-05-27 23:29:48 +0000712 selector &= 0xffff;
ths5fafdf22007-09-16 21:08:06 +0000713 cpu_x86_load_seg_cache(env, seg_reg, selector,
bellardc27004e2005-01-03 23:35:10 +0000714 (selector << 4), 0xffff, 0);
bellarda513fe12003-05-27 23:29:48 +0000715 } else {
bellard5d975592008-05-12 22:05:33 +0000716 helper_load_seg(seg_reg, selector);
bellarda513fe12003-05-27 23:29:48 +0000717 }
bellard6dbad632003-03-16 18:05:05 +0000718 env = saved_env;
719}
bellard9de5e442003-03-23 16:49:39 +0000720
bellard6f12a2a2007-11-11 22:16:56 +0000721void cpu_x86_fsave(CPUX86State *s, target_ulong ptr, int data32)
bellardd0a1ffc2003-05-29 20:04:28 +0000722{
723 CPUX86State *saved_env;
724
725 saved_env = env;
726 env = s;
ths3b46e622007-09-17 08:09:54 +0000727
bellard6f12a2a2007-11-11 22:16:56 +0000728 helper_fsave(ptr, data32);
bellardd0a1ffc2003-05-29 20:04:28 +0000729
730 env = saved_env;
731}
732
bellard6f12a2a2007-11-11 22:16:56 +0000733void cpu_x86_frstor(CPUX86State *s, target_ulong ptr, int data32)
bellardd0a1ffc2003-05-29 20:04:28 +0000734{
735 CPUX86State *saved_env;
736
737 saved_env = env;
738 env = s;
ths3b46e622007-09-17 08:09:54 +0000739
bellard6f12a2a2007-11-11 22:16:56 +0000740 helper_frstor(ptr, data32);
bellardd0a1ffc2003-05-29 20:04:28 +0000741
742 env = saved_env;
743}
744
bellarde4533c72003-06-15 19:51:39 +0000745#endif /* TARGET_I386 */
746
bellard67b915a2004-03-31 23:37:16 +0000747#if !defined(CONFIG_SOFTMMU)
748
bellard3fb2ded2003-06-24 13:22:59 +0000749#if defined(TARGET_I386)
750
bellardb56dad12003-05-08 15:38:04 +0000751/* 'pc' is the host PC at which the exception was raised. 'address' is
bellardfd6ce8f2003-05-14 19:00:11 +0000752 the effective address of the memory exception. 'is_write' is 1 if a
753 write caused the exception and otherwise 0'. 'old_set' is the
754 signal set which should be restored */
bellard2b413142003-05-14 23:01:10 +0000755static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
ths5fafdf22007-09-16 21:08:06 +0000756 int is_write, sigset_t *old_set,
bellardbf3e8bf2004-02-16 21:58:54 +0000757 void *puc)
bellard9de5e442003-03-23 16:49:39 +0000758{
bellarda513fe12003-05-27 23:29:48 +0000759 TranslationBlock *tb;
760 int ret;
bellard68a79312003-06-30 13:12:32 +0000761
bellard83479e72003-06-25 16:12:37 +0000762 if (cpu_single_env)
763 env = cpu_single_env; /* XXX: find a correct solution for multithread */
bellardfd6ce8f2003-05-14 19:00:11 +0000764#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000765 qemu_printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellardbf3e8bf2004-02-16 21:58:54 +0000766 pc, address, is_write, *(unsigned long *)old_set);
bellard9de5e442003-03-23 16:49:39 +0000767#endif
bellard25eb4482003-05-14 21:50:54 +0000768 /* XXX: locking issue */
pbrook53a59602006-03-25 19:31:22 +0000769 if (is_write && page_unprotect(h2g(address), pc, puc)) {
bellardfd6ce8f2003-05-14 19:00:11 +0000770 return 1;
771 }
bellardfbf9eeb2004-04-25 21:21:33 +0000772
bellard3fb2ded2003-06-24 13:22:59 +0000773 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +0000774 ret = cpu_x86_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellard3fb2ded2003-06-24 13:22:59 +0000775 if (ret < 0)
776 return 0; /* not an MMU fault */
777 if (ret == 0)
778 return 1; /* the MMU fault was handled without causing real CPU fault */
779 /* now we have a real cpu fault */
bellarda513fe12003-05-27 23:29:48 +0000780 tb = tb_find_pc(pc);
781 if (tb) {
bellard9de5e442003-03-23 16:49:39 +0000782 /* the PC is inside the translated code. It means that we have
783 a virtual CPU fault */
bellardbf3e8bf2004-02-16 21:58:54 +0000784 cpu_restore_state(tb, env, pc, puc);
bellard3fb2ded2003-06-24 13:22:59 +0000785 }
bellard4cbf74b2003-08-10 21:48:43 +0000786 if (ret == 1) {
bellard3fb2ded2003-06-24 13:22:59 +0000787#if 0
ths5fafdf22007-09-16 21:08:06 +0000788 printf("PF exception: EIP=0x%08x CR2=0x%08x error=0x%x\n",
bellard4cbf74b2003-08-10 21:48:43 +0000789 env->eip, env->cr[2], env->error_code);
bellard3fb2ded2003-06-24 13:22:59 +0000790#endif
bellard4cbf74b2003-08-10 21:48:43 +0000791 /* we restore the process signal mask as the sigreturn should
792 do it (XXX: use sigsetjmp) */
793 sigprocmask(SIG_SETMASK, old_set, NULL);
bellard54ca9092005-12-04 18:46:06 +0000794 raise_exception_err(env->exception_index, env->error_code);
bellard4cbf74b2003-08-10 21:48:43 +0000795 } else {
796 /* activate soft MMU for this block */
bellard3f337312003-08-20 23:02:09 +0000797 env->hflags |= HF_SOFTMMU_MASK;
bellardfbf9eeb2004-04-25 21:21:33 +0000798 cpu_resume_from_signal(env, puc);
bellard4cbf74b2003-08-10 21:48:43 +0000799 }
bellard3fb2ded2003-06-24 13:22:59 +0000800 /* never comes here */
801 return 1;
802}
803
bellarde4533c72003-06-15 19:51:39 +0000804#elif defined(TARGET_ARM)
bellard3fb2ded2003-06-24 13:22:59 +0000805static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
bellardbf3e8bf2004-02-16 21:58:54 +0000806 int is_write, sigset_t *old_set,
807 void *puc)
bellard3fb2ded2003-06-24 13:22:59 +0000808{
bellard68016c62005-02-07 23:12:27 +0000809 TranslationBlock *tb;
810 int ret;
811
812 if (cpu_single_env)
813 env = cpu_single_env; /* XXX: find a correct solution for multithread */
814#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000815 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellard68016c62005-02-07 23:12:27 +0000816 pc, address, is_write, *(unsigned long *)old_set);
817#endif
bellard9f0777e2005-02-02 20:42:01 +0000818 /* XXX: locking issue */
pbrook53a59602006-03-25 19:31:22 +0000819 if (is_write && page_unprotect(h2g(address), pc, puc)) {
bellard9f0777e2005-02-02 20:42:01 +0000820 return 1;
821 }
bellard68016c62005-02-07 23:12:27 +0000822 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +0000823 ret = cpu_arm_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellard68016c62005-02-07 23:12:27 +0000824 if (ret < 0)
825 return 0; /* not an MMU fault */
826 if (ret == 0)
827 return 1; /* the MMU fault was handled without causing real CPU fault */
828 /* now we have a real cpu fault */
829 tb = tb_find_pc(pc);
830 if (tb) {
831 /* the PC is inside the translated code. It means that we have
832 a virtual CPU fault */
833 cpu_restore_state(tb, env, pc, puc);
834 }
835 /* we restore the process signal mask as the sigreturn should
836 do it (XXX: use sigsetjmp) */
837 sigprocmask(SIG_SETMASK, old_set, NULL);
838 cpu_loop_exit();
aurel32968c74d2008-04-11 04:55:17 +0000839 /* never comes here */
840 return 1;
bellard3fb2ded2003-06-24 13:22:59 +0000841}
bellard93ac68b2003-09-30 20:57:29 +0000842#elif defined(TARGET_SPARC)
843static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
bellardbf3e8bf2004-02-16 21:58:54 +0000844 int is_write, sigset_t *old_set,
845 void *puc)
bellard93ac68b2003-09-30 20:57:29 +0000846{
bellard68016c62005-02-07 23:12:27 +0000847 TranslationBlock *tb;
848 int ret;
849
850 if (cpu_single_env)
851 env = cpu_single_env; /* XXX: find a correct solution for multithread */
852#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000853 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellard68016c62005-02-07 23:12:27 +0000854 pc, address, is_write, *(unsigned long *)old_set);
855#endif
bellardb453b702004-01-04 15:45:21 +0000856 /* XXX: locking issue */
pbrook53a59602006-03-25 19:31:22 +0000857 if (is_write && page_unprotect(h2g(address), pc, puc)) {
bellardb453b702004-01-04 15:45:21 +0000858 return 1;
859 }
bellard68016c62005-02-07 23:12:27 +0000860 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +0000861 ret = cpu_sparc_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellard68016c62005-02-07 23:12:27 +0000862 if (ret < 0)
863 return 0; /* not an MMU fault */
864 if (ret == 0)
865 return 1; /* the MMU fault was handled without causing real CPU fault */
866 /* now we have a real cpu fault */
867 tb = tb_find_pc(pc);
868 if (tb) {
869 /* the PC is inside the translated code. It means that we have
870 a virtual CPU fault */
871 cpu_restore_state(tb, env, pc, puc);
872 }
873 /* we restore the process signal mask as the sigreturn should
874 do it (XXX: use sigsetjmp) */
875 sigprocmask(SIG_SETMASK, old_set, NULL);
876 cpu_loop_exit();
aurel32968c74d2008-04-11 04:55:17 +0000877 /* never comes here */
878 return 1;
bellard93ac68b2003-09-30 20:57:29 +0000879}
bellard67867302003-11-23 17:05:30 +0000880#elif defined (TARGET_PPC)
881static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
bellardbf3e8bf2004-02-16 21:58:54 +0000882 int is_write, sigset_t *old_set,
883 void *puc)
bellard67867302003-11-23 17:05:30 +0000884{
885 TranslationBlock *tb;
bellardce097762004-01-04 23:53:18 +0000886 int ret;
ths3b46e622007-09-17 08:09:54 +0000887
bellard67867302003-11-23 17:05:30 +0000888 if (cpu_single_env)
889 env = cpu_single_env; /* XXX: find a correct solution for multithread */
bellard67867302003-11-23 17:05:30 +0000890#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000891 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellard67867302003-11-23 17:05:30 +0000892 pc, address, is_write, *(unsigned long *)old_set);
893#endif
894 /* XXX: locking issue */
pbrook53a59602006-03-25 19:31:22 +0000895 if (is_write && page_unprotect(h2g(address), pc, puc)) {
bellard67867302003-11-23 17:05:30 +0000896 return 1;
897 }
898
bellardce097762004-01-04 23:53:18 +0000899 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +0000900 ret = cpu_ppc_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellardce097762004-01-04 23:53:18 +0000901 if (ret < 0)
902 return 0; /* not an MMU fault */
903 if (ret == 0)
904 return 1; /* the MMU fault was handled without causing real CPU fault */
905
bellard67867302003-11-23 17:05:30 +0000906 /* now we have a real cpu fault */
907 tb = tb_find_pc(pc);
908 if (tb) {
909 /* the PC is inside the translated code. It means that we have
910 a virtual CPU fault */
bellardbf3e8bf2004-02-16 21:58:54 +0000911 cpu_restore_state(tb, env, pc, puc);
bellard67867302003-11-23 17:05:30 +0000912 }
bellardce097762004-01-04 23:53:18 +0000913 if (ret == 1) {
bellard67867302003-11-23 17:05:30 +0000914#if 0
ths5fafdf22007-09-16 21:08:06 +0000915 printf("PF exception: NIP=0x%08x error=0x%x %p\n",
bellardce097762004-01-04 23:53:18 +0000916 env->nip, env->error_code, tb);
bellard67867302003-11-23 17:05:30 +0000917#endif
918 /* we restore the process signal mask as the sigreturn should
919 do it (XXX: use sigsetjmp) */
bellardbf3e8bf2004-02-16 21:58:54 +0000920 sigprocmask(SIG_SETMASK, old_set, NULL);
aurel3264adab32008-11-22 10:09:17 +0000921 raise_exception_err(env, env->exception_index, env->error_code);
bellardce097762004-01-04 23:53:18 +0000922 } else {
923 /* activate soft MMU for this block */
bellardfbf9eeb2004-04-25 21:21:33 +0000924 cpu_resume_from_signal(env, puc);
bellardce097762004-01-04 23:53:18 +0000925 }
bellard67867302003-11-23 17:05:30 +0000926 /* never comes here */
927 return 1;
928}
bellard6af0bf92005-07-02 14:58:51 +0000929
pbrooke6e59062006-10-22 00:18:54 +0000930#elif defined(TARGET_M68K)
931static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
932 int is_write, sigset_t *old_set,
933 void *puc)
934{
935 TranslationBlock *tb;
936 int ret;
937
938 if (cpu_single_env)
939 env = cpu_single_env; /* XXX: find a correct solution for multithread */
940#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000941 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
pbrooke6e59062006-10-22 00:18:54 +0000942 pc, address, is_write, *(unsigned long *)old_set);
943#endif
944 /* XXX: locking issue */
945 if (is_write && page_unprotect(address, pc, puc)) {
946 return 1;
947 }
948 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +0000949 ret = cpu_m68k_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
pbrooke6e59062006-10-22 00:18:54 +0000950 if (ret < 0)
951 return 0; /* not an MMU fault */
952 if (ret == 0)
953 return 1; /* the MMU fault was handled without causing real CPU fault */
954 /* now we have a real cpu fault */
955 tb = tb_find_pc(pc);
956 if (tb) {
957 /* the PC is inside the translated code. It means that we have
958 a virtual CPU fault */
959 cpu_restore_state(tb, env, pc, puc);
960 }
961 /* we restore the process signal mask as the sigreturn should
962 do it (XXX: use sigsetjmp) */
963 sigprocmask(SIG_SETMASK, old_set, NULL);
964 cpu_loop_exit();
965 /* never comes here */
966 return 1;
967}
968
bellard6af0bf92005-07-02 14:58:51 +0000969#elif defined (TARGET_MIPS)
970static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
971 int is_write, sigset_t *old_set,
972 void *puc)
973{
974 TranslationBlock *tb;
975 int ret;
ths3b46e622007-09-17 08:09:54 +0000976
bellard6af0bf92005-07-02 14:58:51 +0000977 if (cpu_single_env)
978 env = cpu_single_env; /* XXX: find a correct solution for multithread */
979#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000980 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellard6af0bf92005-07-02 14:58:51 +0000981 pc, address, is_write, *(unsigned long *)old_set);
982#endif
983 /* XXX: locking issue */
pbrook53a59602006-03-25 19:31:22 +0000984 if (is_write && page_unprotect(h2g(address), pc, puc)) {
bellard6af0bf92005-07-02 14:58:51 +0000985 return 1;
986 }
987
988 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +0000989 ret = cpu_mips_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellard6af0bf92005-07-02 14:58:51 +0000990 if (ret < 0)
991 return 0; /* not an MMU fault */
992 if (ret == 0)
993 return 1; /* the MMU fault was handled without causing real CPU fault */
994
995 /* now we have a real cpu fault */
996 tb = tb_find_pc(pc);
997 if (tb) {
998 /* the PC is inside the translated code. It means that we have
999 a virtual CPU fault */
1000 cpu_restore_state(tb, env, pc, puc);
1001 }
1002 if (ret == 1) {
1003#if 0
ths5fafdf22007-09-16 21:08:06 +00001004 printf("PF exception: PC=0x" TARGET_FMT_lx " error=0x%x %p\n",
ths1eb52072007-05-12 16:57:42 +00001005 env->PC, env->error_code, tb);
bellard6af0bf92005-07-02 14:58:51 +00001006#endif
1007 /* we restore the process signal mask as the sigreturn should
1008 do it (XXX: use sigsetjmp) */
1009 sigprocmask(SIG_SETMASK, old_set, NULL);
1010 do_raise_exception_err(env->exception_index, env->error_code);
1011 } else {
1012 /* activate soft MMU for this block */
1013 cpu_resume_from_signal(env, puc);
1014 }
1015 /* never comes here */
1016 return 1;
1017}
1018
bellardfdf9b3e2006-04-27 21:07:38 +00001019#elif defined (TARGET_SH4)
1020static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
1021 int is_write, sigset_t *old_set,
1022 void *puc)
1023{
1024 TranslationBlock *tb;
1025 int ret;
ths3b46e622007-09-17 08:09:54 +00001026
bellardfdf9b3e2006-04-27 21:07:38 +00001027 if (cpu_single_env)
1028 env = cpu_single_env; /* XXX: find a correct solution for multithread */
1029#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +00001030 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellardfdf9b3e2006-04-27 21:07:38 +00001031 pc, address, is_write, *(unsigned long *)old_set);
1032#endif
1033 /* XXX: locking issue */
1034 if (is_write && page_unprotect(h2g(address), pc, puc)) {
1035 return 1;
1036 }
1037
1038 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +00001039 ret = cpu_sh4_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellardfdf9b3e2006-04-27 21:07:38 +00001040 if (ret < 0)
1041 return 0; /* not an MMU fault */
1042 if (ret == 0)
1043 return 1; /* the MMU fault was handled without causing real CPU fault */
1044
1045 /* now we have a real cpu fault */
1046 tb = tb_find_pc(pc);
1047 if (tb) {
1048 /* the PC is inside the translated code. It means that we have
1049 a virtual CPU fault */
1050 cpu_restore_state(tb, env, pc, puc);
1051 }
bellardfdf9b3e2006-04-27 21:07:38 +00001052#if 0
ths5fafdf22007-09-16 21:08:06 +00001053 printf("PF exception: NIP=0x%08x error=0x%x %p\n",
bellardfdf9b3e2006-04-27 21:07:38 +00001054 env->nip, env->error_code, tb);
1055#endif
1056 /* we restore the process signal mask as the sigreturn should
1057 do it (XXX: use sigsetjmp) */
pbrook355fb232006-06-17 19:58:25 +00001058 sigprocmask(SIG_SETMASK, old_set, NULL);
1059 cpu_loop_exit();
bellardfdf9b3e2006-04-27 21:07:38 +00001060 /* never comes here */
1061 return 1;
1062}
j_mayereddf68a2007-04-05 07:22:49 +00001063
1064#elif defined (TARGET_ALPHA)
1065static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
1066 int is_write, sigset_t *old_set,
1067 void *puc)
1068{
1069 TranslationBlock *tb;
1070 int ret;
ths3b46e622007-09-17 08:09:54 +00001071
j_mayereddf68a2007-04-05 07:22:49 +00001072 if (cpu_single_env)
1073 env = cpu_single_env; /* XXX: find a correct solution for multithread */
1074#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +00001075 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
j_mayereddf68a2007-04-05 07:22:49 +00001076 pc, address, is_write, *(unsigned long *)old_set);
1077#endif
1078 /* XXX: locking issue */
1079 if (is_write && page_unprotect(h2g(address), pc, puc)) {
1080 return 1;
1081 }
1082
1083 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +00001084 ret = cpu_alpha_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
j_mayereddf68a2007-04-05 07:22:49 +00001085 if (ret < 0)
1086 return 0; /* not an MMU fault */
1087 if (ret == 0)
1088 return 1; /* the MMU fault was handled without causing real CPU fault */
1089
1090 /* now we have a real cpu fault */
1091 tb = tb_find_pc(pc);
1092 if (tb) {
1093 /* the PC is inside the translated code. It means that we have
1094 a virtual CPU fault */
1095 cpu_restore_state(tb, env, pc, puc);
1096 }
1097#if 0
ths5fafdf22007-09-16 21:08:06 +00001098 printf("PF exception: NIP=0x%08x error=0x%x %p\n",
j_mayereddf68a2007-04-05 07:22:49 +00001099 env->nip, env->error_code, tb);
1100#endif
1101 /* we restore the process signal mask as the sigreturn should
1102 do it (XXX: use sigsetjmp) */
1103 sigprocmask(SIG_SETMASK, old_set, NULL);
1104 cpu_loop_exit();
1105 /* never comes here */
1106 return 1;
1107}
thsf1ccf902007-10-08 13:16:14 +00001108#elif defined (TARGET_CRIS)
1109static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
1110 int is_write, sigset_t *old_set,
1111 void *puc)
1112{
1113 TranslationBlock *tb;
1114 int ret;
1115
1116 if (cpu_single_env)
1117 env = cpu_single_env; /* XXX: find a correct solution for multithread */
1118#if defined(DEBUG_SIGNAL)
1119 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
1120 pc, address, is_write, *(unsigned long *)old_set);
1121#endif
1122 /* XXX: locking issue */
1123 if (is_write && page_unprotect(h2g(address), pc, puc)) {
1124 return 1;
1125 }
1126
1127 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +00001128 ret = cpu_cris_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
thsf1ccf902007-10-08 13:16:14 +00001129 if (ret < 0)
1130 return 0; /* not an MMU fault */
1131 if (ret == 0)
1132 return 1; /* the MMU fault was handled without causing real CPU fault */
1133
1134 /* now we have a real cpu fault */
1135 tb = tb_find_pc(pc);
1136 if (tb) {
1137 /* the PC is inside the translated code. It means that we have
1138 a virtual CPU fault */
1139 cpu_restore_state(tb, env, pc, puc);
1140 }
thsf1ccf902007-10-08 13:16:14 +00001141 /* we restore the process signal mask as the sigreturn should
1142 do it (XXX: use sigsetjmp) */
1143 sigprocmask(SIG_SETMASK, old_set, NULL);
1144 cpu_loop_exit();
1145 /* never comes here */
1146 return 1;
1147}
1148
bellarde4533c72003-06-15 19:51:39 +00001149#else
1150#error unsupported target CPU
1151#endif
bellard9de5e442003-03-23 16:49:39 +00001152
bellard2b413142003-05-14 23:01:10 +00001153#if defined(__i386__)
1154
bellardd8ecc0b2007-02-05 21:41:46 +00001155#if defined(__APPLE__)
1156# include <sys/ucontext.h>
1157
1158# define EIP_sig(context) (*((unsigned long*)&(context)->uc_mcontext->ss.eip))
1159# define TRAP_sig(context) ((context)->uc_mcontext->es.trapno)
1160# define ERROR_sig(context) ((context)->uc_mcontext->es.err)
1161#else
1162# define EIP_sig(context) ((context)->uc_mcontext.gregs[REG_EIP])
1163# define TRAP_sig(context) ((context)->uc_mcontext.gregs[REG_TRAPNO])
1164# define ERROR_sig(context) ((context)->uc_mcontext.gregs[REG_ERR])
1165#endif
1166
ths5fafdf22007-09-16 21:08:06 +00001167int cpu_signal_handler(int host_signum, void *pinfo,
bellarde4533c72003-06-15 19:51:39 +00001168 void *puc)
bellard9de5e442003-03-23 16:49:39 +00001169{
ths5a7b5422007-01-31 12:16:51 +00001170 siginfo_t *info = pinfo;
bellard9de5e442003-03-23 16:49:39 +00001171 struct ucontext *uc = puc;
1172 unsigned long pc;
bellardbf3e8bf2004-02-16 21:58:54 +00001173 int trapno;
bellard97eb5b12004-02-25 23:19:55 +00001174
bellardd691f662003-03-24 21:58:34 +00001175#ifndef REG_EIP
1176/* for glibc 2.1 */
bellardfd6ce8f2003-05-14 19:00:11 +00001177#define REG_EIP EIP
1178#define REG_ERR ERR
1179#define REG_TRAPNO TRAPNO
bellardd691f662003-03-24 21:58:34 +00001180#endif
bellardd8ecc0b2007-02-05 21:41:46 +00001181 pc = EIP_sig(uc);
1182 trapno = TRAP_sig(uc);
bellardec6338b2007-11-08 14:25:03 +00001183 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1184 trapno == 0xe ?
1185 (ERROR_sig(uc) >> 1) & 1 : 0,
1186 &uc->uc_sigmask, puc);
bellard2b413142003-05-14 23:01:10 +00001187}
1188
bellardbc51c5c2004-03-17 23:46:04 +00001189#elif defined(__x86_64__)
1190
ths5a7b5422007-01-31 12:16:51 +00001191int cpu_signal_handler(int host_signum, void *pinfo,
bellardbc51c5c2004-03-17 23:46:04 +00001192 void *puc)
1193{
ths5a7b5422007-01-31 12:16:51 +00001194 siginfo_t *info = pinfo;
bellardbc51c5c2004-03-17 23:46:04 +00001195 struct ucontext *uc = puc;
1196 unsigned long pc;
1197
1198 pc = uc->uc_mcontext.gregs[REG_RIP];
ths5fafdf22007-09-16 21:08:06 +00001199 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1200 uc->uc_mcontext.gregs[REG_TRAPNO] == 0xe ?
bellardbc51c5c2004-03-17 23:46:04 +00001201 (uc->uc_mcontext.gregs[REG_ERR] >> 1) & 1 : 0,
1202 &uc->uc_sigmask, puc);
1203}
1204
bellard83fb7ad2004-07-05 21:25:26 +00001205#elif defined(__powerpc__)
bellard2b413142003-05-14 23:01:10 +00001206
bellard83fb7ad2004-07-05 21:25:26 +00001207/***********************************************************************
1208 * signal context platform-specific definitions
1209 * From Wine
1210 */
1211#ifdef linux
1212/* All Registers access - only for local access */
1213# define REG_sig(reg_name, context) ((context)->uc_mcontext.regs->reg_name)
1214/* Gpr Registers access */
1215# define GPR_sig(reg_num, context) REG_sig(gpr[reg_num], context)
1216# define IAR_sig(context) REG_sig(nip, context) /* Program counter */
1217# define MSR_sig(context) REG_sig(msr, context) /* Machine State Register (Supervisor) */
1218# define CTR_sig(context) REG_sig(ctr, context) /* Count register */
1219# define XER_sig(context) REG_sig(xer, context) /* User's integer exception register */
1220# define LR_sig(context) REG_sig(link, context) /* Link register */
1221# define CR_sig(context) REG_sig(ccr, context) /* Condition register */
1222/* Float Registers access */
1223# define FLOAT_sig(reg_num, context) (((double*)((char*)((context)->uc_mcontext.regs+48*4)))[reg_num])
1224# define FPSCR_sig(context) (*(int*)((char*)((context)->uc_mcontext.regs+(48+32*2)*4)))
1225/* Exception Registers access */
1226# define DAR_sig(context) REG_sig(dar, context)
1227# define DSISR_sig(context) REG_sig(dsisr, context)
1228# define TRAP_sig(context) REG_sig(trap, context)
1229#endif /* linux */
1230
1231#ifdef __APPLE__
1232# include <sys/ucontext.h>
1233typedef struct ucontext SIGCONTEXT;
1234/* All Registers access - only for local access */
1235# define REG_sig(reg_name, context) ((context)->uc_mcontext->ss.reg_name)
1236# define FLOATREG_sig(reg_name, context) ((context)->uc_mcontext->fs.reg_name)
1237# define EXCEPREG_sig(reg_name, context) ((context)->uc_mcontext->es.reg_name)
1238# define VECREG_sig(reg_name, context) ((context)->uc_mcontext->vs.reg_name)
1239/* Gpr Registers access */
1240# define GPR_sig(reg_num, context) REG_sig(r##reg_num, context)
1241# define IAR_sig(context) REG_sig(srr0, context) /* Program counter */
1242# define MSR_sig(context) REG_sig(srr1, context) /* Machine State Register (Supervisor) */
1243# define CTR_sig(context) REG_sig(ctr, context)
1244# define XER_sig(context) REG_sig(xer, context) /* Link register */
1245# define LR_sig(context) REG_sig(lr, context) /* User's integer exception register */
1246# define CR_sig(context) REG_sig(cr, context) /* Condition register */
1247/* Float Registers access */
1248# define FLOAT_sig(reg_num, context) FLOATREG_sig(fpregs[reg_num], context)
1249# define FPSCR_sig(context) ((double)FLOATREG_sig(fpscr, context))
1250/* Exception Registers access */
1251# define DAR_sig(context) EXCEPREG_sig(dar, context) /* Fault registers for coredump */
1252# define DSISR_sig(context) EXCEPREG_sig(dsisr, context)
1253# define TRAP_sig(context) EXCEPREG_sig(exception, context) /* number of powerpc exception taken */
1254#endif /* __APPLE__ */
1255
ths5fafdf22007-09-16 21:08:06 +00001256int cpu_signal_handler(int host_signum, void *pinfo,
bellarde4533c72003-06-15 19:51:39 +00001257 void *puc)
bellard2b413142003-05-14 23:01:10 +00001258{
ths5a7b5422007-01-31 12:16:51 +00001259 siginfo_t *info = pinfo;
bellard25eb4482003-05-14 21:50:54 +00001260 struct ucontext *uc = puc;
bellard25eb4482003-05-14 21:50:54 +00001261 unsigned long pc;
bellard25eb4482003-05-14 21:50:54 +00001262 int is_write;
1263
bellard83fb7ad2004-07-05 21:25:26 +00001264 pc = IAR_sig(uc);
bellard25eb4482003-05-14 21:50:54 +00001265 is_write = 0;
1266#if 0
1267 /* ppc 4xx case */
bellard83fb7ad2004-07-05 21:25:26 +00001268 if (DSISR_sig(uc) & 0x00800000)
bellard25eb4482003-05-14 21:50:54 +00001269 is_write = 1;
bellard9de5e442003-03-23 16:49:39 +00001270#else
bellard83fb7ad2004-07-05 21:25:26 +00001271 if (TRAP_sig(uc) != 0x400 && (DSISR_sig(uc) & 0x02000000))
bellard25eb4482003-05-14 21:50:54 +00001272 is_write = 1;
1273#endif
ths5fafdf22007-09-16 21:08:06 +00001274 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellardbf3e8bf2004-02-16 21:58:54 +00001275 is_write, &uc->uc_sigmask, puc);
bellard9de5e442003-03-23 16:49:39 +00001276}
bellard2b413142003-05-14 23:01:10 +00001277
bellard2f87c602003-06-02 20:38:09 +00001278#elif defined(__alpha__)
1279
ths5fafdf22007-09-16 21:08:06 +00001280int cpu_signal_handler(int host_signum, void *pinfo,
bellard2f87c602003-06-02 20:38:09 +00001281 void *puc)
1282{
ths5a7b5422007-01-31 12:16:51 +00001283 siginfo_t *info = pinfo;
bellard2f87c602003-06-02 20:38:09 +00001284 struct ucontext *uc = puc;
1285 uint32_t *pc = uc->uc_mcontext.sc_pc;
1286 uint32_t insn = *pc;
1287 int is_write = 0;
1288
bellard8c6939c2003-06-09 15:28:00 +00001289 /* XXX: need kernel patch to get write flag faster */
bellard2f87c602003-06-02 20:38:09 +00001290 switch (insn >> 26) {
1291 case 0x0d: // stw
1292 case 0x0e: // stb
1293 case 0x0f: // stq_u
1294 case 0x24: // stf
1295 case 0x25: // stg
1296 case 0x26: // sts
1297 case 0x27: // stt
1298 case 0x2c: // stl
1299 case 0x2d: // stq
1300 case 0x2e: // stl_c
1301 case 0x2f: // stq_c
1302 is_write = 1;
1303 }
1304
ths5fafdf22007-09-16 21:08:06 +00001305 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellardbf3e8bf2004-02-16 21:58:54 +00001306 is_write, &uc->uc_sigmask, puc);
bellard2f87c602003-06-02 20:38:09 +00001307}
bellard8c6939c2003-06-09 15:28:00 +00001308#elif defined(__sparc__)
1309
ths5fafdf22007-09-16 21:08:06 +00001310int cpu_signal_handler(int host_signum, void *pinfo,
bellarde4533c72003-06-15 19:51:39 +00001311 void *puc)
bellard8c6939c2003-06-09 15:28:00 +00001312{
ths5a7b5422007-01-31 12:16:51 +00001313 siginfo_t *info = pinfo;
bellard8c6939c2003-06-09 15:28:00 +00001314 int is_write;
1315 uint32_t insn;
blueswir16b4c11c2008-05-19 17:20:01 +00001316#if !defined(__arch64__) || defined(HOST_SOLARIS)
blueswir1c9e1e2b2008-05-18 06:40:16 +00001317 uint32_t *regs = (uint32_t *)(info + 1);
1318 void *sigmask = (regs + 20);
bellard8c6939c2003-06-09 15:28:00 +00001319 /* XXX: is there a standard glibc define ? */
blueswir1c9e1e2b2008-05-18 06:40:16 +00001320 unsigned long pc = regs[1];
1321#else
blueswir184778502008-10-26 20:33:16 +00001322#ifdef __linux__
blueswir1c9e1e2b2008-05-18 06:40:16 +00001323 struct sigcontext *sc = puc;
1324 unsigned long pc = sc->sigc_regs.tpc;
1325 void *sigmask = (void *)sc->sigc_mask;
blueswir184778502008-10-26 20:33:16 +00001326#elif defined(__OpenBSD__)
1327 struct sigcontext *uc = puc;
1328 unsigned long pc = uc->sc_pc;
1329 void *sigmask = (void *)(long)uc->sc_mask;
1330#endif
blueswir1c9e1e2b2008-05-18 06:40:16 +00001331#endif
1332
bellard8c6939c2003-06-09 15:28:00 +00001333 /* XXX: need kernel patch to get write flag faster */
1334 is_write = 0;
1335 insn = *(uint32_t *)pc;
1336 if ((insn >> 30) == 3) {
1337 switch((insn >> 19) & 0x3f) {
1338 case 0x05: // stb
1339 case 0x06: // sth
1340 case 0x04: // st
1341 case 0x07: // std
1342 case 0x24: // stf
1343 case 0x27: // stdf
1344 case 0x25: // stfsr
1345 is_write = 1;
1346 break;
1347 }
1348 }
ths5fafdf22007-09-16 21:08:06 +00001349 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellardbf3e8bf2004-02-16 21:58:54 +00001350 is_write, sigmask, NULL);
bellard8c6939c2003-06-09 15:28:00 +00001351}
1352
1353#elif defined(__arm__)
1354
ths5fafdf22007-09-16 21:08:06 +00001355int cpu_signal_handler(int host_signum, void *pinfo,
bellarde4533c72003-06-15 19:51:39 +00001356 void *puc)
bellard8c6939c2003-06-09 15:28:00 +00001357{
ths5a7b5422007-01-31 12:16:51 +00001358 siginfo_t *info = pinfo;
bellard8c6939c2003-06-09 15:28:00 +00001359 struct ucontext *uc = puc;
1360 unsigned long pc;
1361 int is_write;
ths3b46e622007-09-17 08:09:54 +00001362
blueswir148bbf112008-07-08 18:35:02 +00001363#if (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ <= 3))
balrog5c49b362008-06-02 01:01:18 +00001364 pc = uc->uc_mcontext.gregs[R15];
1365#else
balrog4eee57f2008-05-06 14:47:19 +00001366 pc = uc->uc_mcontext.arm_pc;
balrog5c49b362008-06-02 01:01:18 +00001367#endif
bellard8c6939c2003-06-09 15:28:00 +00001368 /* XXX: compute is_write */
1369 is_write = 0;
ths5fafdf22007-09-16 21:08:06 +00001370 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellard8c6939c2003-06-09 15:28:00 +00001371 is_write,
pbrookf3a96762006-07-29 19:09:31 +00001372 &uc->uc_sigmask, puc);
bellard8c6939c2003-06-09 15:28:00 +00001373}
1374
bellard38e584a2003-08-10 22:14:22 +00001375#elif defined(__mc68000)
1376
ths5fafdf22007-09-16 21:08:06 +00001377int cpu_signal_handler(int host_signum, void *pinfo,
bellard38e584a2003-08-10 22:14:22 +00001378 void *puc)
1379{
ths5a7b5422007-01-31 12:16:51 +00001380 siginfo_t *info = pinfo;
bellard38e584a2003-08-10 22:14:22 +00001381 struct ucontext *uc = puc;
1382 unsigned long pc;
1383 int is_write;
ths3b46e622007-09-17 08:09:54 +00001384
bellard38e584a2003-08-10 22:14:22 +00001385 pc = uc->uc_mcontext.gregs[16];
1386 /* XXX: compute is_write */
1387 is_write = 0;
ths5fafdf22007-09-16 21:08:06 +00001388 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellard38e584a2003-08-10 22:14:22 +00001389 is_write,
bellardbf3e8bf2004-02-16 21:58:54 +00001390 &uc->uc_sigmask, puc);
bellard38e584a2003-08-10 22:14:22 +00001391}
1392
bellardb8076a72005-04-07 22:20:31 +00001393#elif defined(__ia64)
1394
1395#ifndef __ISR_VALID
1396 /* This ought to be in <bits/siginfo.h>... */
1397# define __ISR_VALID 1
bellardb8076a72005-04-07 22:20:31 +00001398#endif
1399
ths5a7b5422007-01-31 12:16:51 +00001400int cpu_signal_handler(int host_signum, void *pinfo, void *puc)
bellardb8076a72005-04-07 22:20:31 +00001401{
ths5a7b5422007-01-31 12:16:51 +00001402 siginfo_t *info = pinfo;
bellardb8076a72005-04-07 22:20:31 +00001403 struct ucontext *uc = puc;
1404 unsigned long ip;
1405 int is_write = 0;
1406
1407 ip = uc->uc_mcontext.sc_ip;
1408 switch (host_signum) {
1409 case SIGILL:
1410 case SIGFPE:
1411 case SIGSEGV:
1412 case SIGBUS:
1413 case SIGTRAP:
bellardfd4a43e2006-04-24 20:32:17 +00001414 if (info->si_code && (info->si_segvflags & __ISR_VALID))
bellardb8076a72005-04-07 22:20:31 +00001415 /* ISR.W (write-access) is bit 33: */
1416 is_write = (info->si_isr >> 33) & 1;
1417 break;
1418
1419 default:
1420 break;
1421 }
1422 return handle_cpu_signal(ip, (unsigned long)info->si_addr,
1423 is_write,
1424 &uc->uc_sigmask, puc);
1425}
1426
bellard90cb9492005-07-24 15:11:38 +00001427#elif defined(__s390__)
1428
ths5fafdf22007-09-16 21:08:06 +00001429int cpu_signal_handler(int host_signum, void *pinfo,
bellard90cb9492005-07-24 15:11:38 +00001430 void *puc)
1431{
ths5a7b5422007-01-31 12:16:51 +00001432 siginfo_t *info = pinfo;
bellard90cb9492005-07-24 15:11:38 +00001433 struct ucontext *uc = puc;
1434 unsigned long pc;
1435 int is_write;
ths3b46e622007-09-17 08:09:54 +00001436
bellard90cb9492005-07-24 15:11:38 +00001437 pc = uc->uc_mcontext.psw.addr;
1438 /* XXX: compute is_write */
1439 is_write = 0;
ths5fafdf22007-09-16 21:08:06 +00001440 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
thsc4b89d12007-05-05 19:23:11 +00001441 is_write, &uc->uc_sigmask, puc);
1442}
1443
1444#elif defined(__mips__)
1445
ths5fafdf22007-09-16 21:08:06 +00001446int cpu_signal_handler(int host_signum, void *pinfo,
thsc4b89d12007-05-05 19:23:11 +00001447 void *puc)
1448{
ths9617efe2007-05-08 21:05:55 +00001449 siginfo_t *info = pinfo;
thsc4b89d12007-05-05 19:23:11 +00001450 struct ucontext *uc = puc;
1451 greg_t pc = uc->uc_mcontext.pc;
1452 int is_write;
ths3b46e622007-09-17 08:09:54 +00001453
thsc4b89d12007-05-05 19:23:11 +00001454 /* XXX: compute is_write */
1455 is_write = 0;
ths5fafdf22007-09-16 21:08:06 +00001456 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
thsc4b89d12007-05-05 19:23:11 +00001457 is_write, &uc->uc_sigmask, puc);
bellard90cb9492005-07-24 15:11:38 +00001458}
1459
aurel32f54b3f92008-04-12 20:14:54 +00001460#elif defined(__hppa__)
1461
1462int cpu_signal_handler(int host_signum, void *pinfo,
1463 void *puc)
1464{
1465 struct siginfo *info = pinfo;
1466 struct ucontext *uc = puc;
1467 unsigned long pc;
1468 int is_write;
1469
1470 pc = uc->uc_mcontext.sc_iaoq[0];
1471 /* FIXME: compute is_write */
1472 is_write = 0;
1473 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1474 is_write,
1475 &uc->uc_sigmask, puc);
1476}
1477
bellard2b413142003-05-14 23:01:10 +00001478#else
1479
bellard3fb2ded2003-06-24 13:22:59 +00001480#error host CPU specific signal handler needed
bellard2b413142003-05-14 23:01:10 +00001481
1482#endif
bellard67b915a2004-03-31 23:37:16 +00001483
1484#endif /* !defined(CONFIG_SOFTMMU) */